source: tol/tolbase/lib/byswidget/bmultiselect/bmultiselect.tcl @ ffeacdc

1941-docker-image-to-testdevel
Last change on this file since ffeacdc was ffeacdc, checked in by Pedro Gea <pgea@…>, 10 years ago

Refs #1933
Mejora en bmultiselect.
Se quitan algunas trazas

git-svn-id: ​https://www.tol-project.org/svn/tolp/trunk@7351 be4846ae-f051-483a-831f-b64e7d08527f

  • Property mode set to 100644
File size: 20.7 KB
Line 
1#/////////////////////////////////////////////////////////////////////////////
2# FILE    : bmultiselec.tcl
3# PURPOSE : Component for creating a multiple selector of items and
4#           managing its events. A multiple selector consist of two listboxes:
5#           unselected (left) and selected (right) with items which you can
6#           move from one listbox to the other.
7#/////////////////////////////////////////////////////////////////////////////
8
9package require byscommon
10package require blistbox
11package require blistboxplus
12
13
14#/////////////////////////////////////////////////////////////////////////////
15::snit::widget bmultiselect {
16#
17# PURPOSE: Selector de elementos multiple
18#
19# opciones especificas
20#  unsel -> valores no seleccionados
21#  sel -> valores seleccionados
22#  labelsel -> etiqueta para la lista de elementos seleccionados
23#  labelunsel -> etiqueta para la lista de elementos no seleccionados
24#  font -> font for the both listboxes
25#  onchanged -> comando a ejecutar cada vez que cambia algo en las listas
26#  unique -> si esta a true solamente se permite pasar un elemento a la lista
27#            de seleccionados
28#  cols -> lista con las columnas de cada ListBox
29#  hiddencols -> aquellas columnas del ListBox que queremos mantener ocultas
30#  width -> ancho total orientativo del widget
31#  height -> alto total orientativo del widget
32#  initialdir -> directory where to go when opening a save dialog
33#
34# variables
35#  lright -> the right label
36#  lleft -> the left label
37#  right -> the right blistbox or blistcontrol
38#  left -> the left blistbox or blistcontrol
39#  bbox -> the buttonbox
40#  plus -> indicates if the listbox is listbox+ (columns)
41#  created -> indicates if the widget has been fully created
42# 
43#/////////////////////////////////////////////////////////////////////////////
44  widgetclass Bmultiselect
45
46  option -sel {}
47  option -unsel {}
48  option -labelsel   "Selected"
49  option -labelunsel "Not Selected"
50  option -font {arial 10}
51  option -onchanged ""
52  option -unique false
53  option -width {}
54  option -height {}
55  option -cols {}
56  option -hiddencols {}
57  option -initialdir ""
58 
59  variable lright
60  variable lleft
61  variable right
62  variable left
63  variable bbox
64  variable bboxright
65
66  variable created 0
67  variable plus 0
68
69  #///////////////////////////////////////////////////////////////////////////
70  constructor { args } {
71  #
72  # PURPOSE: Constructor de un bmultiselect. Crea una instancia de un selector
73  #          multiple
74  #
75  # PARAMETERS:
76  #   args -> Lista de opciones para el bmultiselect
77  #
78  #///////////////////////////////////////////////////////////////////////////
79    $self configure -cols [from args -cols ""]
80    $self configure -sel [from args -sel ""]
81    $self configure -unsel [from args -unsel ""]
82    $self configure -unique [from args -unique 0]
83   
84    # Create the widget
85    $self createwidget $args
86
87    # Apply all arguments given:
88    $self configurelist $args
89  }
90
91
92  #///////////////////////////////////////////////////////////////////////////
93  #
94  # PURPOSE: Metodos cget y configure
95  #
96  #///////////////////////////////////////////////////////////////////////////
97
98  onconfigure -sel { lst } {
99    set options(-sel) $lst
100    if { $created } {
101      $self _FillLB
102    }
103  }
104 
105  onconfigure -unsel { lst } {
106    set options(-unsel) $lst
107    if { $created } {
108      $self _FillLB
109    }
110  }
111 
112  onconfigure -labelsel { value } {
113    if { $created } {
114      set options(-labelsel) $value
115      $lright configure -text $value
116    }
117  }
118 
119  onconfigure -labelunsel { value } {
120    if { $created } {
121          set options(-labelunsel) $value
122      $lleft configure -text $value
123    }
124  }
125 
126  onconfigure -cols { value } {
127    set options(-cols) $value
128    set plus [llength $options(-cols)]
129    if { $created && $plus } {
130      $right configure -cols $value
131      $left configure -cols $value
132    }
133  }
134
135  onconfigure -hiddencols { value } {
136    set options(-hiddencols) $value
137    set plus [llength $options(-cols)]
138    if { $created && $plus } {
139      $right configure -hiddencols $value
140      $left configure -hiddencols $value
141    }
142  }
143
144  onconfigure -width { value } {
145    set options(-width) $value
146    if { ! $plus } {
147      set value [expr $value / 2]
148    }
149    if { $created } {
150      $left configure -width $value
151      $right configure -width $value
152    }
153  }
154
155  onconfigure -height { value } {
156    set options(-height) $value
157    if { ! $plus } {
158      set value [expr $value / 2]
159    }
160    if { $created } {
161      $left configure -height $value
162      $right configure -height $value
163    }
164  }
165
166   onconfigure -initialdir { value } {
167     set options(-initialdir) $value
168     if { $created && $plus } {
169       $left configure -initialdir $options(-initialdir)
170       $right configure -initialdir $options(-initialdir)
171     }
172   }
173
174   onconfigure -font { f } {
175     set options(-font) $f
176     if { $created } {
177       $left configure -font $f
178       $right configure -font $f
179     }
180   }
181
182 
183  #///////////////////////////////////////////////////////////////////////////
184  method createwidget { args } {
185  #
186  # PURPOSE: Creacion de los objetos que componen el widget
187  #
188  # PARAMETERS:
189  #   args -> Lista de opciones para el bmultiselect
190  #
191  #///////////////////////////////////////////////////////////////////////////
192    set labelunsel [from args -labelunsel [mc "Not Selected"]]
193    set labelsel [from args -labelsel [mc "Selected"]]
194    set cols [from args -cols ""]
195    set initialdir [from args -initialdir ""]
196
197    # listbox 1
198    install lleft using label $self.l1 -text $labelunsel -bd 1 -relief raised
199    if { ! $plus } {
200      ScrolledWindow $self.sw1
201      install left using blistbox $self.sw1.lb -selectmode extended \
202        -breadonly true -bkeypress true -bparent $self
203      $self.sw1 setwidget $self.sw1.lb
204      bind $left <Button-1> +[list focus -force %W]
205      bind $left <Double-Button-1> +[list $self _LBLeftToRight]
206    } else {
207       install left using blistboxplus $self.lbl -cols $options(-cols) \
208         -hiddencols $options(-hiddencols) -initialdir $initialdir -readonly true
209       if { $options(-unique) } {
210         $left configure -selectmode single
211       } else {
212         $left configure -selectmode multiple
213       }
214       $left bind all <Double-Button-1> +[list $self _LBLeftToRight]
215    }
216
217    # buttons
218    install bbox using ButtonBox $self.bb -orient vertical -spacing 0 \
219                                          -padx 4 -pady 1
220    $bbox add -image [Bitmap::get play] -height 16 -width 16 \
221      -command [list $self _LBLeftToRight] -relief link \
222      -helptext [mc "Moves selection from left to right"]
223    $bbox add -image [Bitmap::get reverse] -height 16 -width 16 \
224      -command [list $self _LBRightToLeft] -relief link \
225      -helptext [mc "Moves selection from right to left"]
226        if { ! $options(-unique) } {
227    $bbox add -image [Bitmap::get end] -height 16 -width 16 \
228      -command [list $self _LBAllLeftToRight] -relief link \
229      -helptext [mc "Moves all from left to right"]
230    $bbox add -image [Bitmap::get begin] -height 16 -width 16 \
231      -command [list $self _LBAllRightToLeft] -relief link \
232      -helptext [mc "Moves all from right to left"]
233    }
234
235
236    install bboxright using ButtonBox $self.bbr -orient vertical -spacing 0 \
237                                          -padx 4 -pady 1
238    $bboxright add -image [Bitmap::get upNext] -height 16 -width 16 \
239      -command [list $self _LBDownToUp] -relief link \
240      -helptext [mc "Moves selection up"]
241    $bboxright add -image [Bitmap::get downNext] -height 16 -width 16 \
242      -command [list $self _LBUpToDown] -relief link \
243      -helptext [mc "Moves selection down"]
244 
245 
246    # listbox 2
247    install lright using label $self.l2 -text $labelsel -bd 1 -relief raised
248    if { ! $plus  } {
249      ScrolledWindow $self.sw2
250      install right using blistbox $self.sw2.lb -selectmode extended \
251        -breadonly true -bkeypress true -bparent $self
252      $self.sw2 setwidget $self.sw2.lb
253      bind $right <Button-1> +[list focus -force %W]
254      bind $right <Double-Button-1> +[list $self _LBRightToLeft]
255    } else {
256       install right using blistboxplus $self.lbr -cols $options(-cols) \
257                                   -initialdir $initialdir -readonly true
258       if { $options(-unique) } {
259         $right configure -selectmode single
260       } else {
261         $right configure -selectmode multiple
262       }
263       $right bind all <Double-Button-1> +[list $self _LBRightToLeft]
264    }
265 
266    # fill the listbox
267    $self _FillLB
268
269    grid $self.l1 $bbox $self.l2 $bboxright -sticky news
270    if { ! $plus } {
271      grid $self.sw1  ^      $self.sw2 ^ -sticky news
272    } else {
273          grid $left  ^      $right ^ -sticky news
274    }
275    grid rowconfigure    $self 1 -weight 1
276    grid columnconfigure $self 0 -weight 1
277    grid columnconfigure $self 1 -pad 5
278    grid columnconfigure $self 2 -weight 1
279    grid columnconfigure $self 3 -pad 5
280    update
281    bind <Destroy> $self [list $self KillData]
282   
283    set created 1
284   
285    return $self
286  }
287 
288
289  #///////////////////////////////////////////////////////////////////////////
290    method _EvalOnChanged {} {
291  #
292  # PURPOSE: Evaluates a procedure when any of the listboxes changes any of
293  #          its items and actualizes the -sel and -unsel options.
294  #
295  #///////////////////////////////////////////////////////////////////////////
296   
297    set options(-unsel) [$left get 0 end]
298    set options(-sel) [$right get 0 end]
299       
300    if { [string length $options(-onchanged)] } {
301      eval $options(-onchanged)
302    }
303  }
304
305
306  #///////////////////////////////////////////////////////////////////////////
307    method _FillLB {} {
308  #
309  # PURPOSE: Fill unselected and selected listboxes.
310  #
311  #///////////////////////////////////////////////////////////////////////////
312
313    if { "" eq $options(-cols) } {
314      $left delete 0 end
315      $right delete 0 end
316    } else {
317      $left clear
318      $right clear
319    }
320   
321    foreach it $options(-unsel) {
322      $left insert end $it
323    }
324    foreach it $options(-sel) {
325     
326      $right insert end $it
327      if { $options(-unique) } { break }
328    }
329    $self _EvalOnChanged
330  }
331
332
333  #///////////////////////////////////////////////////////////////////////////
334    method _ListTransferSel { src dst } {
335  #
336  # PURPOSE: Transfer selected items from scr listbox to dst listbox.
337  #
338  # PARAMETERS:
339  #    src -> source listbox path
340  #    dst -> destination listbox path
341  #
342  #///////////////////////////////////////////////////////////////////////////
343
344    if { "$dst" eq "$right" && $options(-unique) } {
345      if { [$right size] eq 0 } {
346        if { "" ne [$src curselection] } {
347          switch [llength $options(-cols)] {
348            1 {
349              eval $dst insert end [$src get [lindex [$src curselection] 0]]
350            }
351            default {
352              $dst insert end [$src get [lindex [$src curselection] 0]]
353            }
354          }
355        }
356      } else {
357        if { $plus } {
358          $src selection clearall
359        } else {
360          $src select clear 0 end
361        }
362      }
363    } else {
364      foreach i [$src curselection] {
365        switch [llength $options(-cols)] {
366          1       { eval $dst insert end [$src get $i] }
367          default { $dst insert end [$src get $i]      }
368        }
369      }
370    }
371  }
372
373
374  #///////////////////////////////////////////////////////////////////////////
375    method _ListDeleteSel { w } {
376  #
377  # PURPOSE: Deletes selected items of a listbox
378  #
379  # PARAMETERS:
380  #    w -> listbox's path
381  #
382  #///////////////////////////////////////////////////////////////////////////
383 
384    if { "$w" eq "$left" && $options(-unique) } {
385          set index [lindex [$w curselection] 0]
386          if { $index >= 0 } { $w delete $index }
387    } else {
388      foreach i [lsort -integer -decreasing [$w curselection]] {
389        $w delete $i
390      }
391    }
392  }
393
394
395  #///////////////////////////////////////////////////////////////////////////
396    method _LBLeftToRight {} {
397  #
398  # PURPOSE: Moves selected items from unselected listbox to selected listbox
399  #
400  #///////////////////////////////////////////////////////////////////////////
401    $self _ListTransferSel $left $right
402    $self _ListDeleteSel   $left
403    $self _EvalOnChanged
404  }
405
406
407  #///////////////////////////////////////////////////////////////////////////
408    method _LBRightToLeft {} {
409  #
410  # PURPOSE: Moves selected items from selectedu listbox to unselected listbox
411  #
412  #///////////////////////////////////////////////////////////////////////////
413    $self _ListTransferSel $right $left
414    $self _ListDeleteSel   $right
415    $self _EvalOnChanged
416  }
417
418
419  #///////////////////////////////////////////////////////////////////////////
420    method _LBAllLeftToRight {} {
421  #
422  # PURPOSE: Moves all items from unselected listbox to selected listbox
423  #
424  #///////////////////////////////////////////////////////////////////////////
425    if { $plus } {
426      foreach i [$left get] {
427        switch [llength $options(-cols)] {
428          1       { eval $right add [$left get $i] }
429          default {      $right add [$left get $i] }
430        }
431        $left delete $i
432      }
433    } else {
434      eval $right insert end [$left get 0 end]
435      $left delete 0 end
436    }
437    $self _EvalOnChanged
438  }
439
440
441  #///////////////////////////////////////////////////////////////////////////
442    method _LBAllRightToLeft {} {
443  #
444  # PURPOSE: Moves all items from selected listbox to unselected listbox
445  #
446  #///////////////////////////////////////////////////////////////////////////
447    if { $plus } {
448      foreach i [$right get] {
449        switch [llength $options(-cols)] {
450          1       { eval $left add [$right get $i] }
451          default {      $left add [$right get $i] }
452        }
453        $right delete $i
454      }
455    } else {
456      eval $left insert end [$right get 0 end]
457      $right delete 0 end
458    }
459    $self _EvalOnChanged
460  }
461
462
463  #///////////////////////////////////////////////////////////////////////////
464    method _LBDownToUp {} {
465  #
466  # PURPOSE: Moves selected items in listbox on the right side up
467  #
468  #///////////////////////////////////////////////////////////////////////////
469    set indexes [$right curselection]
470    if {$indexes != ""} {
471      set first [lindex $indexes 0]
472      set last [lindex $indexes end]     
473      if { $plus } {
474        # hacia arriba
475        if {$first eq [$right item firstchild root]} return
476        foreach index $indexes {
477          $right move $index before {}
478        }
479        #@+ set start [$right first]
480        #@+ if { $first != $start } {
481        #@+   $right move [lindex [$right range [$right first] $first] end-1] after $last
482        #@+   $right selection clearall
483        #@+   $right selection set $first $last
484        #@+ }       
485      } else {
486        if { $first != 0 } {
487          set previous [$right get [expr {$first-1}]]
488          $right delete [expr {$first-1}]
489          $right insert $last $previous
490        }
491      }
492    }
493  }
494
495
496  #///////////////////////////////////////////////////////////////////////////
497    method _LBUpToDown {} {
498  #
499  # PURPOSE: Moves selected items in listbox on the right side down
500  #
501  #///////////////////////////////////////////////////////////////////////////
502    set indexes [$right curselection]
503    if {$indexes != ""} {
504      set first [lindex $indexes 0]
505      set last [lindex $indexes end]
506      if { $plus } {
507        # hacia abajo
508        if {$last eq [$right item lastchild root]} return
509        foreach index [lreverse $indexes] {
510          $right move $index after {}
511        }
512        #@+ set end [$right last]
513        #@+ if { $last != $end } {
514        #@+   $right move [lindex [$right find $last] 1] before $first
515        #@+   $right selection clearall
516        #@+   $right selection set $first $last
517        #@+ }
518      } else {
519        set end [$right index end]
520        if { $last != [expr {$end-1}] } {
521          set next [$right get [expr {$last+1}]]
522          $right delete [expr {$last+1}]
523          $right insert $first $next
524        }
525      }
526    }
527  }
528
529 
530  #///////////////////////////////////////////////////////////////////////////
531    method get { {sel "selected"} } {
532  #
533  # PURPOSE: gets items selected or unselected
534  #
535  # PARAMETERS:
536  #  sel: selected or unselected, indicates which ones to return
537  #
538  #///////////////////////////////////////////////////////////////////////////
539    if { $sel eq "selected" } {
540      if { $plus } {
541        set result {}
542        foreach i [$right get] {
543          switch [llength $options(-cols)] {
544            1       { lappend result [lindex [$right get $i] 0] }
545            default { lappend result [$right get $i] }
546          }
547        }
548        return $result
549      } else {
550        return [$right get 0 end]
551      }
552    }
553   
554    if { $sel eq "unselected" } {
555      if { $plus } {
556        set result {}
557        foreach i [$left get] {
558          switch [llength $options(-cols)] {         
559            1       { lappend result [lindex [$left get $i] 0] }
560            default { lappend result [$left get $i] }
561          }
562        }
563        return $result
564      } else {
565        return [$left get 0 end]
566      }
567    }
568  }
569
570  #///////////////////////////////////////////////////////////////////////////
571    method GetSelected {} {
572  #
573  # PURPOSE: Gets item from selected listbox (rigth)
574  #
575  #///////////////////////////////////////////////////////////////////////////
576    puts "This function is deprecated use get selected instead"
577    $self get selected
578  }
579
580
581  #///////////////////////////////////////////////////////////////////////////
582    method GetUnselected {} {
583  #
584  # PURPOSE: Gets item from unselected listbox (left)
585  #
586  #///////////////////////////////////////////////////////////////////////////
587    puts "This function is deprecated use get unselected instead"
588    $self get unselected
589  }
590}
591
592
593# TEST CODE
594
595
596#/////////////////////////////////////////////////////////////////////////////
597proc closeBmultiselectDialog { w } {
598#
599# PURPOSE: closes the dialog and returns the result
600#
601# PARAMETERS:
602#  w -> The dialog's window pathname
603#
604#/////////////////////////////////////////////////////////////////////////////
605  set f [$w getframe]
606  set result [$f.bms get selected]
607  $w enddialog $result
608}
609
610
611#/////////////////////////////////////////////////////////////////////////////
612proc launchDialog { unique multicolumn le } {
613#
614# PURPOSE: Launches a Dialog with a bmultiselect widget
615#
616# PARAMETERS:
617#  w -> The dialog's window pathname
618#  unique -> This option tells the bmultiselect widget if it will admit only
619#            one selected item
620#
621#/////////////////////////////////////////////////////////////////////////////
622
623  # example of how to use in a dialog
624  destroy .top.d
625  set dialog [Dialog .top.d -title "Prueba de BMultiSelect" \
626    -modal local -parent .top]
627  set dialogframe [$dialog getframe]
628
629  if { $multicolumn } {
630    bmultiselect $dialogframe.bms -cols {una dos tres} -unique $unique \
631          -unsel { {un dos tres} {i ii iii} {x y z} {@ # &} } \
632          -sel   { {one two three} {a b c} {k kk kkk} } \
633          -labelunsel "no seleccionados" -labelsel "seleccionados" \
634          -height 200
635  } else {
636    bmultiselect $dialogframe.bms -unsel {uno 2 tres 4} -sel {cinco 5 siete} \
637      -labelunsel "no seleccionados" -labelsel "seleccionados" -unique $unique
638  }
639 
640  set dialogframe_bbox \
641          [ButtonBox $dialogframe.bb -orient horizontal -spacing 10 -padx 0 -pady 0 \
642          -homogeneous false]
643  $dialogframe_bbox add -text [mc "Accept"] -relief link \
644          -helptext [mc "Accept selection"] \
645          -image [::Bitmap::get accept] -compound left -padx 5 -pady 1 \
646          -command [list closeBmultiselectDialog $dialog]
647  $dialogframe_bbox add -text [mc "Cancel"] -relief link \
648          -helptext [mc "Cancel selection"]\
649          -image [::Bitmap::get cancelx] -compound left -padx 5 -pady 1 \
650          -command [list $dialog enddialog ""]   
651 
652  pack $dialogframe_bbox -fill x -expand false -side bottom
653  pack $dialogframe.bms -fill both -expand true
654 
655  set result [$dialog draw]
656  $le configure -text $result
657}
658
659
660#/////////////////////////////////////////////////////////////////////////////
661proc test_bmultiselect {} {
662#
663# PURPOSE: Test function of a bmultiselect
664#
665#/////////////////////////////////////////////////////////////////////////////
666  destroy .top
667  toplevel .top
668  variable multcols 0
669  variable uniq 0
670
671  radiobutton .top.rb1 -text "Multiple columns" -value 1 -variable multcols
672  radiobutton .top.rb2 -text "Only one column"  -value 0 -variable multcols
673  checkbutton .top.cb -text "Only one selected" -command toggleuniq
674  .top.cb deselect
675  button .top.b -text "Launch a MultiSelect Dialog" -command "preLaunchDialog"
676  LabelEntry .top.le -label Result
677
678
679  grid .top.rb1 -row 0 -column 0
680  grid .top.rb2 -row 1 -column 0
681  grid .top.cb -row 0 -column 1
682  grid .top.b -row 1 -column 1
683  grid .top.le -row 2 -column 0 -columnspan 2 -sticky "ew"
684
685  proc toggleunique {} {
686    variable uniq
687    set uniq [expr ! $uniq]
688  }
689 
690  proc preLaunchDialog {} {
691    variable uniq
692        variable multcols
693    launchDialog $uniq $multcols .top.le
694  }
695
696}
697
698package provide bmultiselect 1.0
Note: See TracBrowser for help on using the repository browser.