Version 0 of ClipboardMonitor

Updated 2009-10-17 12:41:22 by HZe

If you use the clipboard to transfer some of information, sometimes it happens that you copy something and then in the process of coming to the program you want to paste it in, you copy something else and bumm, your first copy is lost.

This tool tries to prevent this by keeping a history of the clipboard selections.

Additionally, it allows to execute a diff; this make sense if the last to entries of the history are file names.

    ######################################################
    # ClipboardMonitor
    #   by Holger Zeinert
    #
    # This small tool monitors the clipboard and adds every
    # new content to a list. From this list, automatically
    # the last two entries are selected.
    #
    # LIMITATION:
    #   Currently, on UNIX the clipboard CLIPBOARD is
    #   used, not PRIMARY.
    #   Also, it's not tested very much on UNIX. I use it
    #   mainly on Windows.
    #
    set usage {
        ClipboardMonitor
            by Holger Zeinert

        This tool monitors the clipboard and keeps a list
        of snapshots from the content. This keeps track
        of things that were in the clipboard and items
        can be reused later.

        If you select one entry in the list, this entry can be
        exported to the clipboard by pressing the button "export"

        "Clear" resets the list. Please note that this will
        at least enter the current content of the clipboard
        again in the list.

        The content of the list is also stored in a private
        configuration file, so that the current content is
        preserved even if the tool is closed and opened
        again.
        Also be careful when copying passwords over the
        clipboard when this tool is running. Those will
        be visible in plain text! And they are saved
        uncrypted in the history file of the tool.

        If you want to do a diff, use the text editor of your
        choice and go to the first file, copy the file name
        to the clipboard, go to the second file, copy the
        file name to the clipboard. Then, in this tool the
        last two (selected) entries show the two filenames
        Press "diff" to invoke tkdiff.
        You also may select two files from the list to do
        the diff on.
    }

    ######################################################
    # Utility procedures
    #
    proc scan_clp {{update_list 0}} {
        global CONFIG
        if {![catch {set content [clipboard get]}]} {
            if {$content != [lindex $CONFIG(clpList) end]} {
                lappend CONFIG(clpList) $content
                set update_list 1
            }
        }
        if {$update_list} {
            update_listbox
        }
        after 500 scan_clp
    }

    proc exit_handler {} {
        # save current content to private configuration
        write_rc
    }

    proc getrcname {} {
        global env argv0 tcl_platform
        if {[string match "win*" $tcl_platform(platform)]} {
            set filename [file join $env(USERPROFILE) "[file rootname [file tail $argv0]].rc"]
        } else {
            set filename [file join ~ "[file rootname ".[file tail $argv0]"].rc"]
        }
        return $filename
    }

    proc read_rc {} {
        global CONFIG

        catch {
            set fp [open [getrcname] r]
            array set CONFIG [read $fp]
            close $fp
        }
        # set defaults
        if {![info exists CONFIG(diff)]} {
            if {[file exists c:/zeinert/tools/tkdiff.bat]} {
                set CONFIG(diff) c:/zeinert/tools/tkdiff.bat
            } else {
                set CONFIG(diff) tkdiff
            }
        }
    }

    proc write_rc {} {
        global CONFIG

        set fp [open [getrcname] w]
        # try to write arrag get a little nicer, so that a human could edit it
        foreach {var value} [array get CONFIG] {
            puts $fp "[list $var]\n[list $value]\n"
        }
        close $fp
    }

    #####################################################
    # GUI handlers
    #
    proc update_listbox {} {
        global lb
        global CONFIG

        set l [llength $CONFIG(clpList)]
        $lb selection clear 0 $l
        $lb selection set [expr $l-2] end
        $lb yview end
        return
    }

    proc export_clp {} {
        global lb
        global CONFIG
        set s [$lb curselection]
        if {[llength $s] != 1} {
            tk_messageBox -message "Please select exactly one entry"
        } else {
            clipboard clear
            clipboard append [lindex $CONFIG(clpList) [lindex $s 0]]
        }
        return
    }

    proc diff {} {
        global lb
        global CONFIG

        set s [$lb curselection]
        if {[llength $s] < 2} {
            tk_messageBox -message "please select two files"
        } else {
            set s1 [lindex $s end]
            set s2 [lindex $s end-1]
            set f1 [lindex $CONFIG(clpList) $s1]
            set f2 [lindex $CONFIG(clpList) $s2]
            if {[catch {
                exec $CONFIG(diff) $f1 $f2
            } msg]} {
                tk_messageBox -message "could not execute diff tool\n    \
                    $msg\n\
                    Please check installation or change [getrcname] to specify the diff tool of your choice."
            }
        }
        return
    }

    proc finish {} {
        exit_handler
        exit
    }

    proc build_gui {} {
        global lb

        frame .l
        set lb .l.lb
        listbox $lb -listvar CONFIG(clpList) -selectmode extended -height 7 -width 50 -yscrollcommand ".l.sb set"
        scrollbar .l.sb  -command "$lb yview"
        pack $lb -expand 1 -fill both -side left
        pack .l.sb -fill y -side left
        pack .l -expand 1 -fill both -padx 5 -pady 5

        frame .b
        button .b.diff -text Diff -command diff
        button .b.clear -text Clear -command {set CONFIG(clpList) {}}
        button .b.exit -text Exit -command finish
        button .b.help -text Help -command {
            toplevel .help
            label .help.l -text $usage -justify left -width 60
            pack .help.l -expand 1
            button .help.b -command {destroy .help} -text "    OK    "
            pack .help.b -expand 1 -padx 3 -pady 3
        }
        button .b.export -text Export -command {export_clp}

        pack .b.exit .b.help .b.diff .b.export .b.clear -side right -padx 5 -pady 5 -ipadx 15
        pack .b -fill x

        wm protocol . WM_DELETE_WINDOW finish
        wm title . "Clipboard Monitor"

        # set minsize to the size of the window after 1sec.
        # this freezes the automatically set windows size as minimum.
        after 1000 {catch {wm minsize . [lindex [split [wm geometry .] x+] 0] [lindex [split [wm geometry .] x+] 1]}}
    }

    #########################################################
    # main
    #
    build_gui
    read_rc
    scan_clp 1