home *** CD-ROM | disk | FTP | other *** search
- #
- # ::iwidgets::Disjointlistbox
- # ----------------------------------------------------------------------
- # Implements a widget which maintains a disjoint relationship between
- # the items displayed by two listboxes. The disjointlistbox is composed
- # of 2 Scrolledlistboxes, 2 Pushbuttons, and 2 labels.
- #
- # The disjoint behavior of this widget exists between the two Listboxes,
- # That is, a given instance of a ::iwidgets::Disjointlistbox will never
- # exist which has Listbox widgets with items in common.
- #
- # Users may transfer items between the two Listbox widgets using the
- # the two Pushbuttons.
- #
- # The options include the ability to configure the "items" displayed by
- # either of the two Listboxes and to control the placement of the insertion
- # and removal buttons.
- #
- # The following depicts the allowable "-buttonplacement" option values
- # and their associated layout:
- #
- # "-buttonplacement" => center
- #
- # --------------------------
- # |listbox| |listbox|
- # | |________| |
- # | (LHS) | button | (RHS) |
- # | |========| |
- # | | button | |
- # |_______|--------|_______|
- # | count | | count |
- # --------------------------
- #
- # "-buttonplacement" => bottom
- #
- # ---------------------
- # | listbox | listbox |
- # | (LHS) | (RHS) |
- # |_________|_________|
- # | button | button |
- # |---------|---------|
- # | count | count |
- # ---------------------
- #
- # ----------------------------------------------------------------------
- # AUTHOR: John A. Tucker EMAIL: jatucker@spd.dsccc.com
- #
- # ======================================================================
-
- #
- # Default resources.
- #
- option add *Disjointlistbox.lhsLabelText Available widgetDefault
- option add *Disjointlistbox.rhsLabelText Current widgetDefault
- option add *Disjointlistbox.lhsButtonLabel {Insert >>} widgetDefault
- option add *Disjointlistbox.rhsButtonLabel {<< Remove} widgetDefault
- option add *Disjointlistbox.vscrollMode static widgetDefault
- option add *Disjointlistbox.hscrollMode static widgetDefault
- option add *Disjointlistbox.selectMode multiple widgetDefault
- option add *Disjointlistbox.labelPos nw widgetDefault
- option add *Disjointlistbox.buttonPlacement bottom widgetDefault
- option add *Disjointlistbox.lhsSortOption increasing widgetDefault
- option add *Disjointlistbox.rhsSortOption increasing widgetDefault
-
-
- #
- # Usual options.
- #
- itk::usual Disjointlistbox {
- keep -background -textbackground -cursor \
- -foreground -textfont -labelfont
- }
-
-
- # ----------------------------------------------------------------------
- # ::iwidgets::Disjointlistbox
- # ----------------------------------------------------------------------
- itcl::class ::iwidgets::Disjointlistbox {
-
- inherit itk::Widget
-
- #
- # options
- #
- itk_option define -buttonplacement buttonPlacement ButtonPlacement bottom
- itk_option define -lhsbuttonlabel lhsButtonLabel LabelText {Insert >>}
- itk_option define -rhsbuttonlabel rhsButtonLabel LabelText {<< Remove}
- itk_option define -lhssortoption lhsSortOption LhsSortOption increasing
- itk_option define -rhssortoption rhsSortOption RhsSortOption increasing
-
- constructor {args} {}
-
- #
- # PUBLIC
- #
- public {
- method clear {}
- method getlhs {{first 0} {last end}}
- method getrhs {{first 0} {last end}}
- method lhs {args}
- method insertlhs {items}
- method insertrhs {items}
- method setlhs {items}
- method setrhs {items}
- method rhs {args}
- }
-
- #
- # PROTECTED
- #
- protected {
- method insert {theListbox items}
- method listboxClick {clickSide otherSide}
- method listboxDblClick {clickSide otherSide}
- method remove {theListbox items}
- method showCount {}
- method transfer {}
-
- variable sourceListbox {}
- variable destinationListbox {}
- }
- }
-
- #
- # Provide a lowercased access method for the ::iwidgets::Disjointlistbox class.
- #
- proc ::iwidgets::disjointlistbox {pathName args} {
- uplevel ::iwidgets::Disjointlistbox $pathName $args
- }
-
- # ------------------------------------------------------------------
- #
- # Method: Constructor
- #
- # Purpose:
- #
- itcl::body ::iwidgets::Disjointlistbox::constructor {args} {
- #
- # Create the left-most Listbox
- #
- itk_component add lhs {
- iwidgets::Scrolledlistbox $itk_interior.lhs \
- -selectioncommand [itcl::code $this listboxClick lhs rhs] \
- -dblclickcommand [itcl::code $this listboxDblClick lhs rhs]
- } {
- usual
- keep -selectmode -vscrollmode -hscrollmode
- rename -labeltext -lhslabeltext lhsLabelText LabelText
- }
-
- #
- # Create the right-most Listbox
- #
- itk_component add rhs {
- iwidgets::Scrolledlistbox $itk_interior.rhs \
- -selectioncommand [itcl::code $this listboxClick rhs lhs] \
- -dblclickcommand [itcl::code $this listboxDblClick rhs lhs]
- } {
- usual
- keep -selectmode -vscrollmode -hscrollmode
- rename -labeltext -rhslabeltext rhsLabelText LabelText
- }
-
- #
- # Create the left-most item count Label
- #
- itk_component add lhsCount {
- label $itk_interior.lhscount
- } {
- usual
- rename -font -labelfont labelFont Font
- }
-
- #
- # Create the right-most item count Label
- #
- itk_component add rhsCount {
- label $itk_interior.rhscount
- } {
- usual
- rename -font -labelfont labelFont Font
- }
-
- set sourceListbox $itk_component(lhs)
- set destinationListbox $itk_component(rhs)
-
- #
- # Bind the "showCount" method to the Map event of one of the labels
- # to keep the diplayed item count current.
- #
- bind $itk_component(lhsCount) <Map> [itcl::code $this showCount]
-
- grid $itk_component(lhs) -row 0 -column 0 -sticky nsew
- grid $itk_component(rhs) -row 0 -column 2 -sticky nsew
-
- grid rowconfigure $itk_interior 0 -weight 1
- grid columnconfigure $itk_interior 0 -weight 1
- grid columnconfigure $itk_interior 2 -weight 1
-
- eval itk_initialize $args
- }
-
- # ------------------------------------------------------------------
- # Method: listboxClick
- #
- # Purpose: Evaluate a single click make in the specified Listbox.
- #
- itcl::body ::iwidgets::Disjointlistbox::listboxClick {clickSide otherSide} {
- set button "button"
- $itk_component($clickSide$button) configure -state active
- $itk_component($otherSide$button) configure -state disabled
- set sourceListbox $clickSide
- set destinationListbox $otherSide
- }
-
- # ------------------------------------------------------------------
- # Method: listboxDblClick
- #
- # Purpose: Evaluate a double click in the specified Listbox.
- #
- itcl::body ::iwidgets::Disjointlistbox::listboxDblClick {clickSide otherSide} {
- listboxClick $clickSide $otherSide
- transfer
- }
-
- # ------------------------------------------------------------------
- # Method: transfer
- #
- # Purpose: Transfer source Listbox items to destination Listbox
- #
- itcl::body ::iwidgets::Disjointlistbox::transfer {} {
-
- if {[$sourceListbox selecteditemcount] == 0} {
- return
- }
- set selectedindices [lsort -integer -decreasing [$sourceListbox curselection]]
- set selecteditems [$sourceListbox getcurselection]
-
- foreach index $selectedindices {
- $sourceListbox delete $index
- }
-
- foreach item $selecteditems {
- $destinationListbox insert end $item
- }
-
- if {![string equal $itk_option(-${destinationListbox}sortoption) "none"]} {
- $destinationListbox sort $itk_option(-${destinationListbox}sortoption)
- }
-
- showCount
- }
-
- # ------------------------------------------------------------------
- # Method: getlhs
- #
- # Purpose: Retrieve the items of the left Listbox widget
- #
- itcl::body ::iwidgets::Disjointlistbox::getlhs {{first 0} {last end}} {
- return [lhs get $first $last]
- }
-
- # ------------------------------------------------------------------
- # Method: getrhs
- #
- # Purpose: Retrieve the items of the right Listbox widget
- #
- itcl::body ::iwidgets::Disjointlistbox::getrhs {{first 0} {last end}} {
- return [rhs get $first $last]
- }
-
- # ------------------------------------------------------------------
- # Method: insertrhs
- #
- # Purpose: Insert items into the right Listbox widget
- #
- itcl::body ::iwidgets::Disjointlistbox::insertrhs {items} {
- remove $itk_component(lhs) $items
- insert rhs $items
- }
-
- # ------------------------------------------------------------------
- # Method: insertlhs
- #
- # Purpose: Insert items into the left Listbox widget
- #
- itcl::body ::iwidgets::Disjointlistbox::insertlhs {items} {
- remove $itk_component(rhs) $items
- insert lhs $items
- }
-
- # ------------------------------------------------------------------
- # Method: clear
- #
- # Purpose: Remove the items from the Listbox widgets and set the item count
- # Labels text to 0
- #
- itcl::body ::iwidgets::Disjointlistbox::clear {} {
- lhs clear
- rhs clear
- showCount
- }
-
- # ------------------------------------------------------------------
- # Method: insert
- #
- # Purpose: Insert the input items into the input Listbox widget while
- # maintaining the disjoint property between them.
- #
- itcl::body ::iwidgets::Disjointlistbox::insert {theListbox items} {
-
- set curritems [$theListbox get 0 end]
-
- foreach item $items {
- #
- # if the item is not already present in the Listbox then insert it
- #
- if {[lsearch -exact $curritems $item] == -1} {
- $theListbox insert end $item
- }
- }
-
- if {![string equal $itk_option(-${theListbox}sortoption) "none"]} {
- $theListbox sort $itk_option(-${theListbox}sortoption)
- }
-
- showCount
- }
-
- # ------------------------------------------------------------------
- # Method: remove
- #
- # Purpose: Remove the input items from the input Listbox widget while
- # maintaining the disjoint property between them.
- #
- itcl::body ::iwidgets::Disjointlistbox::remove {theListbox items} {
-
- set indexes {}
- set curritems [$theListbox get 0 end]
-
- foreach item $items {
- #
- # if the item is in the listbox then add its index to the index list
- #
- if {[set index [lsearch -exact $curritems $item]] != -1} {
- lappend indexes $index
- }
- }
-
- foreach index [lsort -integer -decreasing $indexes] {
- $theListbox delete $index
- }
- showCount
- }
-
- # ------------------------------------------------------------------
- # Method: showCount
- #
- # Purpose: Set the text of the item count Labels.
- #
- itcl::body ::iwidgets::Disjointlistbox::showCount {} {
- $itk_component(lhsCount) config -text "item count: [lhs size]"
- $itk_component(rhsCount) config -text "item count: [rhs size]"
- }
-
- # ------------------------------------------------------------------
- # METHOD: setlhs
- #
- # Set the items of the left-most Listbox with the input list
- # option. Remove all (if any) items from the right-most Listbox
- # which exist in the input list option to maintain the disjoint
- # property between the two
- #
- itcl::body ::iwidgets::Disjointlistbox::setlhs {items} {
- lhs clear
- insertlhs $items
- }
-
- # ------------------------------------------------------------------
- # METHOD: setrhs
- #
- # Set the items of the right-most Listbox with the input list
- # option. Remove all (if any) items from the left-most Listbox
- # which exist in the input list option to maintain the disjoint
- # property between the two
- #
- itcl::body ::iwidgets::Disjointlistbox::setrhs {items} {
- rhs clear
- insertrhs $items
- }
-
- # ------------------------------------------------------------------
- # Method: lhs
- #
- # Purpose: Evaluates the specified arguments against the lhs Listbox
- #
- itcl::body ::iwidgets::Disjointlistbox::lhs {args} {
- return [eval $itk_component(lhs) $args]
- }
-
- # ------------------------------------------------------------------
- # Method: rhs
- #
- # Purpose: Evaluates the specified arguments against the rhs Listbox
- #
- itcl::body ::iwidgets::Disjointlistbox::rhs {args} {
- return [eval $itk_component(rhs) $args]
- }
-
- # ------------------------------------------------------------------
- # OPTION: buttonplacement
- #
- # Configure the placement of the buttons to be either between or below
- # the two list boxes.
- #
- itcl::configbody ::iwidgets::Disjointlistbox::buttonplacement {
- if {$itk_option(-buttonplacement) != ""} {
-
- if { [lsearch [component] lhsbutton] != -1 } {
- eval destroy $itk_component(rhsbutton) $itk_component(lhsbutton)
- }
-
- if { [lsearch [component] bbox] != -1 } {
- destroy $itk_component(bbox)
- }
-
- set where $itk_option(-buttonplacement)
-
- switch $where {
-
- center {
- #
- # Create the button box frame
- #
- itk_component add bbox {
- frame $itk_interior.bbox
- }
-
- itk_component add lhsbutton {
- button $itk_component(bbox).lhsbutton -command [itcl::code \
- $this transfer]
- } {
- usual
- rename -text -lhsbuttonlabel lhsButtonLabel LabelText
- rename -font -labelfont labelFont Font
- }
-
- itk_component add rhsbutton {
- button $itk_component(bbox).rhsbutton -command [itcl::code \
- $this transfer]
- } {
- usual
- rename -text -rhsbuttonlabel rhsButtonLabel LabelText
- rename -font -labelfont labelFont Font
- }
-
- grid configure $itk_component(lhsCount) -row 1 -column 0 \
- -sticky ew
- grid configure $itk_component(rhsCount) -row 1 -column 2 \
- -sticky ew
-
- grid configure $itk_component(bbox) \
- -in $itk_interior -row 0 -column 1 -columnspan 1 \
- -sticky nsew
-
- grid configure $itk_component(rhsbutton) \
- -in $itk_component(bbox) -row 0 -column 0 -sticky ew
- grid configure $itk_component(lhsbutton) \
- -in $itk_component(bbox) -row 1 -column 0 -sticky ew
- }
-
- bottom {
-
- itk_component add lhsbutton {
- button $itk_interior.lhsbutton -command [itcl::code $this \
- transfer]
- } {
- usual
- rename -text -lhsbuttonlabel lhsButtonLabel LabelText
- rename -font -labelfont labelFont Font
- }
-
- itk_component add rhsbutton {
- button $itk_interior.rhsbutton -command [itcl::code $this \
- transfer]
- } {
- usual
- rename -text -rhsbuttonlabel rhsButtonLabel LabelText
- rename -font -labelfont labelFont Font
- }
-
- grid $itk_component(lhsCount) -row 2 -column 0 -sticky ew
- grid $itk_component(rhsCount) -row 2 -column 2 -sticky ew
- grid $itk_component(lhsbutton) -row 1 -column 0 -sticky ew
- grid $itk_component(rhsbutton) -row 1 -column 2 -sticky ew
- }
-
- default {
- error "bad buttonplacement option\"$where\": should be center\
- or bottom"
- }
- }
- }
- }
-
- # ------------------------------------------------------------------
- # OPTION: lhssortoption
- #
- # Configure the sort option to use for the left side
- #
- itcl::configbody ::iwidgets::Disjointlistbox::lhssortoption {
-
- if {![string equal $itk_option(-lhssortoption) "none"]} {
- $itk_component(lhs) sort $itk_option(-lhssortoption)
- }
- }
-
-
- # ------------------------------------------------------------------
- # OPTION: rhssortoption
- #
- # Configure the sort option to use for the right side
- #
- itcl::configbody ::iwidgets::Disjointlistbox::rhssortoption {
-
- if {![string equal $itk_option(-rhssortoption) "none"]} {
- $itk_component(rhs) sort $itk_option(-rhssortoption)
- }
- }
-