home *** CD-ROM | disk | FTP | other *** search
/ PC Welt 2005 March / PCWELT_3_2005.ISO / pcwsoft / framework-2.2.exe / disjointlistbox.itk < prev    next >
Encoding:
Text File  |  2003-09-01  |  15.9 KB  |  530 lines

  1. #
  2. # ::iwidgets::Disjointlistbox
  3. # ----------------------------------------------------------------------
  4. # Implements a widget which maintains a disjoint relationship between
  5. # the items displayed by two listboxes.  The disjointlistbox is composed
  6. # of 2 Scrolledlistboxes,  2 Pushbuttons, and 2 labels.
  7. #
  8. # The disjoint behavior of this widget exists between the two Listboxes,
  9. # That is, a given instance of a ::iwidgets::Disjointlistbox will never
  10. # exist which has Listbox widgets with items in common.
  11. #
  12. # Users may transfer items between the two Listbox widgets using the
  13. # the two Pushbuttons.
  14. #
  15. # The options include the ability to configure the "items" displayed by
  16. # either of the two Listboxes and to control the placement of the insertion
  17. # and removal buttons.
  18. #
  19. # The following depicts the allowable "-buttonplacement" option values
  20. # and their associated layout:
  21. #
  22. #   "-buttonplacement" => center
  23. #
  24. #   --------------------------
  25. #   |listbox|        |listbox|
  26. #   |       |________|       |
  27. #   | (LHS) | button | (RHS) |
  28. #   |       |========|       |
  29. #   |       | button |       |
  30. #   |_______|--------|_______|
  31. #   | count |        | count |
  32. #   --------------------------
  33. #
  34. #   "-buttonplacement" => bottom
  35. #
  36. #   ---------------------
  37. #   | listbox | listbox |
  38. #   |  (LHS)  |  (RHS)  |
  39. #   |_________|_________|
  40. #   | button  | button  |
  41. #   |---------|---------|
  42. #   | count   | count   |
  43. #   ---------------------
  44. #
  45. # ----------------------------------------------------------------------
  46. #  AUTHOR: John A. Tucker               EMAIL: jatucker@spd.dsccc.com
  47. #
  48. # ======================================================================
  49.  
  50. #
  51. # Default resources.
  52. #
  53. option add *Disjointlistbox.lhsLabelText    Available   widgetDefault
  54. option add *Disjointlistbox.rhsLabelText    Current     widgetDefault
  55. option add *Disjointlistbox.lhsButtonLabel  {Insert >>} widgetDefault
  56. option add *Disjointlistbox.rhsButtonLabel  {<< Remove} widgetDefault
  57. option add *Disjointlistbox.vscrollMode     static      widgetDefault
  58. option add *Disjointlistbox.hscrollMode     static      widgetDefault
  59. option add *Disjointlistbox.selectMode      multiple    widgetDefault
  60. option add *Disjointlistbox.labelPos        nw          widgetDefault
  61. option add *Disjointlistbox.buttonPlacement bottom      widgetDefault
  62. option add *Disjointlistbox.lhsSortOption   increasing  widgetDefault
  63. option add *Disjointlistbox.rhsSortOption   increasing  widgetDefault
  64.  
  65.  
  66. #
  67. # Usual options.
  68. #
  69. itk::usual Disjointlistbox {
  70.   keep -background -textbackground -cursor \
  71.        -foreground -textfont -labelfont
  72. }
  73.  
  74.  
  75. # ----------------------------------------------------------------------
  76. # ::iwidgets::Disjointlistbox 
  77. # ----------------------------------------------------------------------
  78. itcl::class ::iwidgets::Disjointlistbox {
  79.  
  80.   inherit itk::Widget
  81.  
  82.   #
  83.   # options
  84.   #
  85.   itk_option define -buttonplacement buttonPlacement ButtonPlacement bottom
  86.   itk_option define -lhsbuttonlabel  lhsButtonLabel  LabelText       {Insert >>}
  87.   itk_option define -rhsbuttonlabel  rhsButtonLabel  LabelText       {<< Remove}
  88.   itk_option define -lhssortoption   lhsSortOption   LhsSortOption   increasing
  89.   itk_option define -rhssortoption   rhsSortOption   RhsSortOption   increasing
  90.  
  91.   constructor {args} {}
  92.  
  93.   #
  94.   # PUBLIC
  95.   #
  96.   public {
  97.     method clear {}
  98.     method getlhs {{first 0} {last end}}
  99.     method getrhs {{first 0} {last end}}
  100.     method lhs {args}
  101.     method insertlhs {items}
  102.     method insertrhs {items}
  103.     method setlhs {items}
  104.     method setrhs {items}
  105.     method rhs {args}
  106.   }
  107.  
  108.   #
  109.   # PROTECTED
  110.   #
  111.   protected {
  112.     method insert {theListbox items}
  113.     method listboxClick {clickSide otherSide}
  114.     method listboxDblClick {clickSide otherSide}
  115.     method remove {theListbox items}
  116.     method showCount {}
  117.     method transfer {}
  118.  
  119.     variable sourceListbox {}
  120.     variable destinationListbox {}
  121.   }
  122. }
  123.  
  124. #
  125. # Provide a lowercased access method for the ::iwidgets::Disjointlistbox class.
  126. proc ::iwidgets::disjointlistbox {pathName args} {
  127.     uplevel ::iwidgets::Disjointlistbox $pathName $args
  128. }
  129.  
  130. # ------------------------------------------------------------------
  131. #
  132. # Method: Constructor
  133. #
  134. # Purpose:   
  135. #
  136. itcl::body ::iwidgets::Disjointlistbox::constructor {args} {
  137.     #
  138.     # Create the left-most Listbox
  139.     #
  140.     itk_component add lhs {
  141.         iwidgets::Scrolledlistbox $itk_interior.lhs \
  142.                 -selectioncommand [itcl::code $this listboxClick lhs rhs] \
  143.                 -dblclickcommand [itcl::code $this listboxDblClick lhs rhs]
  144.     } {
  145.         usual
  146.         keep -selectmode -vscrollmode -hscrollmode
  147.         rename -labeltext -lhslabeltext lhsLabelText LabelText
  148.     }
  149.  
  150.     #
  151.     # Create the right-most Listbox
  152.     #
  153.     itk_component add rhs {
  154.         iwidgets::Scrolledlistbox $itk_interior.rhs \
  155.                 -selectioncommand [itcl::code $this listboxClick rhs lhs] \
  156.                 -dblclickcommand [itcl::code $this listboxDblClick rhs lhs]
  157.     } {
  158.         usual
  159.         keep -selectmode -vscrollmode -hscrollmode
  160.         rename -labeltext -rhslabeltext rhsLabelText LabelText
  161.     }
  162.  
  163.     #
  164.     # Create the left-most item count Label
  165.     #
  166.     itk_component add lhsCount {
  167.         label $itk_interior.lhscount
  168.     } {
  169.         usual
  170.         rename -font -labelfont labelFont Font
  171.     }
  172.  
  173.     #
  174.     # Create the right-most item count Label
  175.     #
  176.     itk_component add rhsCount {
  177.         label $itk_interior.rhscount
  178.     } {
  179.         usual
  180.         rename -font -labelfont labelFont Font
  181.     }
  182.  
  183.     set sourceListbox $itk_component(lhs)
  184.     set destinationListbox $itk_component(rhs)
  185.  
  186.     #
  187.     # Bind the "showCount" method to the Map event of one of the labels
  188.     # to keep the diplayed item count current.
  189.     #
  190.     bind $itk_component(lhsCount) <Map> [itcl::code $this showCount]
  191.  
  192.     grid $itk_component(lhs) -row 0 -column 0 -sticky nsew
  193.     grid $itk_component(rhs) -row 0 -column 2 -sticky nsew
  194.  
  195.     grid rowconfigure    $itk_interior 0 -weight 1
  196.     grid columnconfigure $itk_interior 0 -weight 1
  197.     grid columnconfigure $itk_interior 2 -weight 1
  198.  
  199.     eval itk_initialize $args
  200. }
  201.  
  202. # ------------------------------------------------------------------
  203. # Method:  listboxClick
  204. #
  205. # Purpose: Evaluate a single click make in the specified Listbox.
  206. #
  207. itcl::body ::iwidgets::Disjointlistbox::listboxClick {clickSide otherSide} {
  208.     set button "button"
  209.     $itk_component($clickSide$button) configure -state active
  210.     $itk_component($otherSide$button) configure -state disabled
  211.     set sourceListbox      $clickSide
  212.     set destinationListbox $otherSide
  213. }
  214.  
  215. # ------------------------------------------------------------------
  216. # Method:  listboxDblClick
  217. #
  218. # Purpose: Evaluate a double click in the specified Listbox.
  219. #
  220. itcl::body ::iwidgets::Disjointlistbox::listboxDblClick {clickSide otherSide} {
  221.     listboxClick $clickSide $otherSide
  222.     transfer
  223. }
  224.  
  225. # ------------------------------------------------------------------
  226. # Method:  transfer
  227. #
  228. # Purpose: Transfer source Listbox items to destination Listbox
  229. #
  230. itcl::body ::iwidgets::Disjointlistbox::transfer {} {
  231.  
  232.     if {[$sourceListbox selecteditemcount] == 0} {
  233.         return
  234.     }
  235.     set selectedindices [lsort -integer -decreasing [$sourceListbox curselection]]
  236.     set selecteditems [$sourceListbox getcurselection]
  237.  
  238.     foreach index $selectedindices {
  239.         $sourceListbox delete $index
  240.     }
  241.  
  242.     foreach item $selecteditems {
  243.         $destinationListbox insert end $item
  244.     }
  245.  
  246.     if {![string equal $itk_option(-${destinationListbox}sortoption) "none"]} {
  247.         $destinationListbox sort $itk_option(-${destinationListbox}sortoption)
  248.     }
  249.  
  250.     showCount
  251. }
  252.  
  253. # ------------------------------------------------------------------
  254. # Method: getlhs
  255. #
  256. # Purpose: Retrieve the items of the left Listbox widget
  257. #
  258. itcl::body ::iwidgets::Disjointlistbox::getlhs {{first 0} {last end}} {
  259.     return [lhs get $first $last]
  260. }
  261.  
  262. # ------------------------------------------------------------------
  263. # Method: getrhs
  264. #
  265. # Purpose: Retrieve the items of the right Listbox widget
  266. #
  267. itcl::body ::iwidgets::Disjointlistbox::getrhs {{first 0} {last end}} {
  268.     return [rhs get $first $last]
  269. }
  270.  
  271. # ------------------------------------------------------------------
  272. # Method: insertrhs
  273. #
  274. # Purpose: Insert items into the right Listbox widget
  275. #
  276. itcl::body ::iwidgets::Disjointlistbox::insertrhs {items} {
  277.     remove $itk_component(lhs) $items
  278.     insert rhs $items
  279. }
  280.  
  281. # ------------------------------------------------------------------
  282. # Method: insertlhs
  283. #
  284. # Purpose: Insert items into the left Listbox widget
  285. #
  286. itcl::body ::iwidgets::Disjointlistbox::insertlhs {items} {
  287.     remove $itk_component(rhs) $items
  288.     insert lhs $items
  289. }
  290.  
  291. # ------------------------------------------------------------------
  292. # Method:  clear
  293. #
  294. # Purpose: Remove the items from the Listbox widgets and set the item count
  295. #          Labels text to 0
  296. #
  297. itcl::body ::iwidgets::Disjointlistbox::clear {} {
  298.     lhs clear
  299.     rhs clear
  300.     showCount
  301. }
  302.  
  303. # ------------------------------------------------------------------
  304. # Method: insert
  305. #
  306. # Purpose: Insert the input items into the input Listbox widget while
  307. #          maintaining the disjoint property between them.
  308. #
  309. itcl::body ::iwidgets::Disjointlistbox::insert {theListbox items} {
  310.  
  311.     set curritems [$theListbox get 0 end]
  312.  
  313.     foreach item $items {
  314.         #
  315.         # if the item is not already present in the Listbox then insert it
  316.         #
  317.         if {[lsearch -exact $curritems $item] == -1} {
  318.             $theListbox insert end $item
  319.         }
  320.     }
  321.  
  322.     if {![string equal $itk_option(-${theListbox}sortoption) "none"]} {
  323.         $theListbox sort $itk_option(-${theListbox}sortoption)
  324.     }
  325.  
  326.     showCount
  327. }
  328.  
  329. # ------------------------------------------------------------------
  330. # Method: remove
  331. #
  332. # Purpose: Remove the input items from the input Listbox widget while
  333. #          maintaining the disjoint property between them.
  334. #
  335. itcl::body ::iwidgets::Disjointlistbox::remove {theListbox items} {
  336.  
  337.     set indexes {}
  338.     set curritems [$theListbox get 0 end]
  339.  
  340.     foreach item $items {
  341.         #
  342.         # if the item is in the listbox then add its index to the index list
  343.         # 
  344.         if {[set index [lsearch -exact $curritems $item]] != -1} {
  345.             lappend indexes $index
  346.         }
  347.     }
  348.  
  349.     foreach index [lsort -integer -decreasing $indexes] {
  350.         $theListbox delete $index
  351.     }
  352.     showCount
  353. }
  354.  
  355. # ------------------------------------------------------------------
  356. # Method: showCount
  357. #
  358. # Purpose: Set the text of the item count Labels.
  359. #
  360. itcl::body ::iwidgets::Disjointlistbox::showCount {} {
  361.     $itk_component(lhsCount) config -text "item count: [lhs size]"
  362.     $itk_component(rhsCount) config -text "item count: [rhs size]"
  363. }
  364.  
  365. # ------------------------------------------------------------------
  366. # METHOD: setlhs
  367. #
  368. # Set the items of the left-most Listbox with the input list
  369. # option.  Remove all (if any) items from the right-most Listbox
  370. # which exist in the input list option to maintain the disjoint
  371. # property between the two
  372. #
  373. itcl::body ::iwidgets::Disjointlistbox::setlhs {items} {
  374.     lhs clear
  375.     insertlhs $items
  376. }
  377.  
  378. # ------------------------------------------------------------------
  379. # METHOD: setrhs
  380. #
  381. # Set the items of the right-most Listbox with the input list
  382. # option.  Remove all (if any) items from the left-most Listbox
  383. # which exist in the input list option to maintain the disjoint
  384. # property between the two
  385. #
  386. itcl::body ::iwidgets::Disjointlistbox::setrhs {items} {
  387.     rhs clear
  388.     insertrhs $items
  389. }
  390.  
  391. # ------------------------------------------------------------------
  392. # Method:  lhs
  393. #
  394. # Purpose: Evaluates the specified arguments against the lhs Listbox
  395. #
  396. itcl::body ::iwidgets::Disjointlistbox::lhs {args} {
  397.     return [eval $itk_component(lhs) $args]
  398. }
  399.  
  400. # ------------------------------------------------------------------
  401. # Method:  rhs
  402. #
  403. # Purpose: Evaluates the specified arguments against the rhs Listbox
  404. #
  405. itcl::body ::iwidgets::Disjointlistbox::rhs {args} {
  406.     return [eval $itk_component(rhs) $args]
  407. }
  408.  
  409. # ------------------------------------------------------------------
  410. # OPTION: buttonplacement
  411. #
  412. # Configure the placement of the buttons to be either between or below
  413. # the two list boxes.
  414. #
  415. itcl::configbody ::iwidgets::Disjointlistbox::buttonplacement {
  416.     if {$itk_option(-buttonplacement) != ""} {
  417.  
  418.         if { [lsearch [component] lhsbutton] != -1 } {
  419.             eval destroy $itk_component(rhsbutton) $itk_component(lhsbutton)
  420.         }
  421.  
  422.         if { [lsearch [component] bbox] != -1 } {
  423.             destroy $itk_component(bbox)
  424.         }
  425.  
  426.         set where $itk_option(-buttonplacement)
  427.  
  428.         switch $where {
  429.  
  430.             center {
  431.                 #
  432.                 # Create the button box frame
  433.                 #
  434.                 itk_component add bbox {
  435.                     frame $itk_interior.bbox
  436.                 }
  437.     
  438.                 itk_component add lhsbutton {
  439.                     button $itk_component(bbox).lhsbutton -command [itcl::code \
  440.                             $this transfer]
  441.                 } {
  442.                     usual
  443.                     rename -text -lhsbuttonlabel lhsButtonLabel LabelText
  444.                     rename -font -labelfont labelFont Font
  445.                 }
  446.     
  447.                 itk_component add rhsbutton {
  448.                     button $itk_component(bbox).rhsbutton -command [itcl::code \
  449.                             $this transfer]
  450.                 } {
  451.                     usual
  452.                     rename -text -rhsbuttonlabel rhsButtonLabel LabelText
  453.                     rename -font -labelfont labelFont Font
  454.                 }
  455.     
  456.                 grid configure $itk_component(lhsCount) -row 1 -column 0 \
  457.                         -sticky ew
  458.                 grid configure $itk_component(rhsCount) -row 1 -column 2 \
  459.                         -sticky ew
  460.      
  461.                 grid configure $itk_component(bbox) \
  462.                         -in $itk_interior -row 0 -column 1 -columnspan 1 \
  463.                                 -sticky nsew
  464.     
  465.                 grid configure $itk_component(rhsbutton) \
  466.                         -in $itk_component(bbox) -row 0 -column 0 -sticky ew
  467.                 grid configure $itk_component(lhsbutton) \
  468.                         -in $itk_component(bbox) -row 1 -column 0 -sticky ew
  469.                 }
  470.  
  471.             bottom {
  472.     
  473.                 itk_component add lhsbutton {
  474.                     button $itk_interior.lhsbutton -command [itcl::code $this \
  475.                             transfer]
  476.                 } {
  477.                     usual
  478.                     rename -text -lhsbuttonlabel lhsButtonLabel LabelText
  479.                     rename -font -labelfont labelFont Font
  480.                 }
  481.  
  482.                 itk_component add rhsbutton {
  483.                     button $itk_interior.rhsbutton -command [itcl::code $this \
  484.                             transfer]
  485.                 } {
  486.                     usual
  487.                     rename -text -rhsbuttonlabel rhsButtonLabel LabelText
  488.                     rename -font -labelfont labelFont Font
  489.                 }
  490.  
  491.                 grid $itk_component(lhsCount)  -row 2 -column 0 -sticky ew
  492.                 grid $itk_component(rhsCount)  -row 2 -column 2 -sticky ew
  493.                 grid $itk_component(lhsbutton) -row 1 -column 0 -sticky ew
  494.                 grid $itk_component(rhsbutton) -row 1 -column 2 -sticky ew
  495.             }
  496.  
  497.             default {
  498.                 error "bad buttonplacement option\"$where\": should be center\
  499.                         or bottom"
  500.             }
  501.         }
  502.     }
  503. }
  504.  
  505. # ------------------------------------------------------------------
  506. # OPTION: lhssortoption
  507. #
  508. # Configure the sort option to use for the left side
  509. #
  510. itcl::configbody ::iwidgets::Disjointlistbox::lhssortoption {
  511.  
  512.     if {![string equal $itk_option(-lhssortoption) "none"]} {
  513.         $itk_component(lhs) sort $itk_option(-lhssortoption)
  514.     }
  515. }
  516.  
  517.  
  518. # ------------------------------------------------------------------
  519. # OPTION: rhssortoption
  520. #
  521. # Configure the sort option to use for the right side
  522. #
  523. itcl::configbody ::iwidgets::Disjointlistbox::rhssortoption {
  524.  
  525.     if {![string equal $itk_option(-rhssortoption) "none"]} {
  526.         $itk_component(rhs) sort $itk_option(-rhssortoption)
  527.     }
  528. }
  529.