source: tol/tolbase/lib/byswidget/blistboxplus/blistboxplus.tcl @ 6d7779d

1941-docker-image-to-testdevel
Last change on this file since 6d7779d was 6d7779d, checked in by Jorge Pérez <josp.jorge@…>, 18 years ago

initial import

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

  • Property mode set to 100644
File size: 42.7 KB
Line 
1#/////////////////////////////////////////////////////////////////////////////
2# FILE    : blistboxplus.tcl
3# PURPOSE : Bayes List Box. ListBox con opciones sobre su elementos y varias
4#           columnas
5#/////////////////////////////////////////////////////////////////////////////
6
7package require byscommon
8package require BLT
9package require bfunctions
10package require bfieldsdialog
11
12proc debug_init { } {
13  catch {
14    file delete "/tmp/debug_tcl.out"
15  }
16}
17
18proc debug_msg { msg } {
19  catch {
20    set fd [open "/tmp/debug_tcl.out" "a"]
21    puts $fd $msg
22    close $fd
23  }
24}
25
26#/////////////////////////////////////////////////////////////////////////////
27::snit::widget blistboxplus {
28#
29# PURPOSE: ListBox con columnas, menu contextual y caracteristicas adicionales
30#
31#/////////////////////////////////////////////////////////////////////////////
32# opciones especificas
33# readonly -> componente en modo de lectura o lectura/escritura
34# keypress -> Activa la busqueda de filas mediante la pulsacion de teclas
35# colkeypress -> Indica por que columna se busca al pulsar una tecla
36# parent -> indica el padre donde se ubica el blistbox
37# cols -> columnas del listbox
38# hiddencols -> columnas del listbox que no se mostraran
39# filtercols -> columnas del listbox que por las que puede realizarse filtrado
40# initialdir -> directorio inicial para los dialogos de lec/esc de archivos,...
41# orientation -> orientation for de add dialog
42# icon -> icono que se mostrará como primera columna, si no hay icono la
43#  columna no se mostrará
44# nomenu -> Si es 1, no se mostrará el menu contextual
45# titles -> Lista con los titulos a mostrar en cada una de las columnas.
46# values -> List of initial values to load in widget
47# valuesinsert -> List of values to selection element
48# iniconfig -> Nombre que se asigna al listboxplus para identificar sus
49#           opciones en el archivo de configuración .ini por defecto "" en
50#           ese caso no se guardaran las opciones
51#
52# variables
53# listbox -> el treeview que hace de listbox propiamente
54# menu -> el menu contextual del listbox
55# xbar -> horizontal scrollbar
56# ybar -> vertical scrollbar
57# afterTime -> tiempo desde que se pulso la ultima tecla
58# listKey -> lista de teclas pulsadas
59#/////////////////////////////////////////////////////////////////////////////
60  widgetclass Blistboxplus
61
62  option -readonly  0
63  option -keypress    true
64  option -colkeypress ""   
65  option -parent    {}
66  option -cols {}
67  option -hiddencols {}
68  option -filtercols {}
69  option -initialdir {}
70  option -orientation vertical
71  option -showtitles true
72  option -icon ""
73  option -nomenu 0
74  option -titles {}
75  option -values {}
76  option -valuesinsert {}
77  option -iniconfig ""
78 
79  variable _listbox
80  variable menu
81  variable xbar
82  variable ybar
83 
84  variable afterTime 0
85  variable listKey   ""
86  variable currentId 0
87  variable created   0
88
89  #///////////////////////////////////////////////////////////////////////////
90  constructor {args} {
91  #
92  # PURPOSE: Constructor de un blistboxplus. Crea una instancia de un Listbox
93  #
94  # PARAMETERS:
95  #   args -> opciones
96  #
97  #///////////////////////////////////////////////////////////////////////////
98
99    debug_init
100
101    debug_msg "install listbox ..."
102
103    if {0} {
104      install _listbox using ::blt::treeview $win.lb -hideroot yes \
105          -activeicons "" -icons {} -selectmode multiple \
106          -selectbackground grey -selectforeground white \
107          -highlightthickness 0 -borderwidth 1 -selectborderwidth 1 \
108          -nofocusselectbackground grey -font {Arial 9} -flat yes
109    } else {
110      set _listbox [::blt::treeview $win.lb -hideroot yes \
111                        -activeicons "" -icons {} -selectmode multiple \
112                        -selectbackground grey -selectforeground white \
113                        -highlightthickness 0 -borderwidth 1 \
114                        -selectborderwidth 1 \
115                        -nofocusselectbackground grey -font {Arial 9} -flat yes]
116    }
117
118    debug_msg "despues de install listbox"
119
120    install menu using menu $win.m -tearoff 0
121    install xbar using scrollbar $win.sbh -orient horizontal \
122                                           -command "$win xview"
123    install ybar using scrollbar $win.sbv -orient vertical \
124                                           -command "$win yview"
125
126    #bindtags is modified to make possible to associate binds to self
127    bindtags $_listbox [linsert [bindtags $_listbox] 2 $win]
128
129    $_listbox style  configure text     -bg white
130
131    $_listbox column configure treeView -bg white
132
133    $self configure -readonly [from args -readonly]
134    $self _CreateMenu 
135   
136    # Apply all arguments given:
137    $self configurelist $args
138
139    $_listbox configure -xscrollcommand "$xbar set"
140    $_listbox configure -yscrollcommand "$ybar set"
141    if { $options(-parent) eq "" } {
142      $self configure -parent [winfo parent $win]
143    }
144   
145    # bind
146    $_listbox bind all <KeyPress> +[list $self _OnKeyPress %A]
147   
148    $self configure -nomenu [from args -nomenu]
149    $self configure -filtercols [from args -filtercols]
150
151    #pack
152    grid $_listbox -row 0 -column 0 -sticky news
153    grid $ybar -row 0 -column 1 -sticky ns
154    grid $xbar -row 1 -column 0 -sticky ew
155    grid columnconfigure $self 0 -weight 1
156    grid rowconfigure    $self 0 -weight 1
157
158    ::autoscroll::autoscroll $ybar
159    ::autoscroll::autoscroll $xbar
160    debug_msg "voy a pillarte: antes de _ReadIni"
161    $self _ReadIni
162    debug_msg "pase?"
163    set created 1
164  }
165
166  #///////////////////////////////////////////////////////////////////////////
167  destructor {
168  #
169  # PURPOSE: Funciones a evaluar al eliminar la instancia de blistboxplus.
170  #
171  # PARAMETERS:
172  #   self: toplevel
173  #
174  #///////////////////////////////////////////////////////////////////////////
175    # Save .ini
176    catch [list $self _WriteIni ]
177  }
178   
179  #///////////////////////////////////////////////////////////////////////////
180  #
181  # PURPOSE: Metodos cget y configure
182  #
183  #///////////////////////////////////////////////////////////////////////////
184
185    onconfigure -cols { lst } {
186     set options(-cols) $lst
187       foreach col [$self column names] {
188         $_listbox column delete $col
189       }
190       foreach col $options(-cols) {
191         $_listbox column insert end $col -justify left
192         $_listbox column configure $col -command "$self _SortByColumn [list $col]" \
193            -titleborderwidth 1
194       }
195       if { $options(-icon) == "" } {
196         $_listbox column configure "BLT TreeView $_listbox" -hide 1
197       } else {
198         $_lisbox column configure "BLT TreeView $_listbox" -hide 0
199       }
200  }
201
202  onconfigure -hiddencols { lst } {
203    set options(-hiddencols) $lst
204    foreach col [$self column names] {
205      if { "-1" eq [lsearch $options(-hiddencols) $col] } {
206        $_listbox column configure $col -hide 0
207      } else {
208        $_listbox column configure $col -hide 1
209      }
210    }
211  }
212
213  onconfigure -showtitles { bool } {
214    set options(-showtitles) $bool
215    $_listbox configure -showtitles $bool
216    $_listbox show
217  }
218
219  onconfigure -icon { icon } {
220    set options(-icon) $icon
221    if { $icon != "" } {
222      $_listbox column configure "BLT TreeView $_listbox" -min 16 -max 16 \
223        -hide 0 -titleborderwidth 1
224      $_listbox configure -icons [list [Bitmap::get $icon] [Bitmap::get $icon]]
225    } else {
226      $_listbox column configure "BLT TreeView $_listbox" -hide 1
227    }
228  }
229
230  onconfigure -titles { titles } {
231    set options(-titles) $titles
232    set c 0
233    set cols [$self column names]
234    foreach col $cols {
235     $self column configure $col -title [mc [lindex $titles $c] ]
236     incr c 1     
237    }
238  }
239 
240  onconfigure -values { lst } {
241    $self clear
242    eval $self insert end $lst
243  }
244
245  onconfigure -nomenu { bool } {
246    set options(-nomenu) $bool
247    if {$bool} {
248      # no mostrar menu
249      bind $self  <Button-3>   ""
250    } else {
251      # mostrar menu
252      bind $self  <Button-3>   "tk_popup $menu %X %Y"
253    }
254  }
255 
256  onconfigure -readonly { bool } {
257    if {!($created)} {
258      set options(-readonly) $bool       
259    } else {
260      puts "Blistboxplus widget error: option -readonly only can be set on \
261            creation time"
262    }
263  }
264 
265  onconfigure -filtercols { lst } {
266    set cols [$self cget -cols]   
267    set hiddencols [$self cget -hiddencols]
268    if { [llength cols] && [llength hiddencols]} {
269      set filtercols {}
270      foreach col $cols {
271        if {([lsearch -exact $hiddencols  $col])} {
272          lappend filtercols $col
273        }
274      }
275      set options(-filtercols) $filtercols   
276    } else {
277      if { [llength cols] } {
278        set options(-filtercols) $options(-cols)
279      }
280    }
281  }
282 
283  #///////////////////////////////////////////////////////////////////////////
284  method _CreateMenu {args} {
285  #
286  # PURPOSE: Append menu to listbox.
287  #
288  #///////////////////////////////////////////////////////////////////////////
289    # read option
290    $menu add command -label [mc "Select all"] \
291      -command "$self _SelectAll"  -accelerator CTRL+E
292    $menu add command -label [mc "Unselect all"] \
293      -command "$self selection clearall" -accelerator CTRL+U
294    $menu add command -label [mc "Toggle selection"] \
295      -command "$self _ToggleSelection" -accelerator CTRL+I
296    # read/write option
297    if {!([$self cget -readonly])} {
298      # delete
299      $menu add separator
300      $menu add command -label [mc "Insert"] \
301                -command "$self _OpenWR" -accelerator Ins
302      $menu add command -label [mc "Delete all"]  \
303        -command "$self clear"  -accelerator CTRL+D
304      $menu add command -label [mc "Delete selected"] \
305        -command "lbDeleteSelection $self"
306    }
307    # read option
308    # copy
309    $menu add separator
310    $menu add command -label [mc "Filter"] -command "$self _OpenFD"
311    $menu add command -label [mc "Unfilter"] -command "$self _RemoveFilter"
312    $menu add separator
313    set mc [menu $menu.copy -tearoff 0]
314    $menu add cascade -label [mc "Copy"] -menu $mc
315    $mc add command -label [mc "Copy all"] \
316      -command "$self _CopyToClipBoard 1 1" -accelerator CTRL+A
317    $mc add command -label [mc "Copy selected"] \
318      -command "$self _CopyToClipBoard 1 0" -accelerator CTRL+C
319    $mc add command -label [mc "Copy unselect"] \
320      -command "$self _CopyToClipBoard 0 1"
321    # count
322    $menu add separator
323    $menu add command -label [mc "Count elements"] \
324      -command "$self _ShowCountItems" -accelerator CTRL+N
325    # file
326    $menu add separator
327    set mf [menu $menu.file -tearoff 0]
328    $menu add cascade -label [mc "File_lbp"] -menu $mf
329    $mf add command -label "[mc "Save to file"] ..." \
330      -command "$self _SaveToFile 1 1"
331    if {![$self cget -readonly]} {
332      $mf add command -label "[mc "Load form file"] ..." \
333        -command "$self _LoadFromFile"
334    }
335    # bindings   
336    $self bind all <Control-KeyRelease> +[list $self _OnControlKey $self %K %k]
337    $self bind all <Key-Delete>    "lbDeleteSelection $self"
338    $self bind all <Key-Insert>    "$self _OpenWR"   
339    $self bind all <Shift-Up>      "$self addPrevious"
340    $self bind all <Shift-Down>    "$self addNext"
341    $self bind all <Up>            "$self previous"
342    $self bind all <Down>          "$self next"
343    $self bind all <Home>          "$self first"
344    $self bind all <End>           "$self last"
345    $self bind all <Shift-Home>    "$self addAllPrevious"
346    $self bind all <Shift-End>     "$self addAllNext"
347    $self bind all <Button-1>      +[list focus -force %W]
348  }
349
350
351  #///////////////////////////////////////////////////////////////////////////
352  method getMenu { } {
353  #
354  # PURPOSE: Devuelve el menu del blistboxplus para poder modificarlo y
355  #          ampliarlo
356  #
357  # RETURN: La variable de instancia que apunta al menu
358  #
359  #/////////////////////////////////////////////////////////////////////////// 
360    return $menu
361  }
362
363
364  #///////////////////////////////////////////////////////////////////////////
365  method _OnKeyPress {key} {
366  #
367  # PURPOSE: Activa la fila que coincide con las teclas pulsadas. Distinge
368  #          entre muysuculas y minusculas
369  #
370  # PARAMETERS: key -> tecla pulsada
371  #
372  #///////////////////////////////////////////////////////////////////////////
373    if {[$self cget -keypress]} {
374      set diference 500
375      set result [lbOnKeyPress $self $key $listKey $afterTime $diference \
376        [$self cget -colkeypress]]
377      set listKey   [lindex $result 0]
378      set afterTime [lindex $result 1]
379    }
380  }
381
382
383  #///////////////////////////////////////////////////////////////////////////
384  method _OnControlKey {_lb keysym keycode} {
385  #
386  # PURPOSE: Controla es uso de teclas rápidas para le ejecución de funciones
387  #
388  # PARAMETERS: _lb -> self
389  #             keysym -> The keysym corresponding to the event,
390  #                       substituted as a textual string
391  #             keycode -> The keycode field from the event
392  #
393  #///////////////////////////////////////////////////////////////////////////
394    switch [string toupper $keysym] {
395      E { $_lb _SelectAll }
396      C { lbToClipBoard $_lb 1 0 }
397     
398      A { $self _CopyToClipBoard 1 1 }
399      D { $self clear }
400      I { $self _ToggleSelection }
401      U { $self selection clearall }
402      N { $self _ShowCountItems }
403    }
404  } 
405
406  #///////////////////////////////////////////////////////////////////////////
407  method _ShowCountItems {} {
408  #
409  # PURPOSE: Shows information on the selection of the elements
410  #
411  #///////////////////////////////////////////////////////////////////////////
412    set info [lbCountItems $self]
413    set msg "[mc "Total"]: [lindex $info 0] \n\
414             [mc "Selected"]: [lindex $info 1] \n\
415             [mc "Not Selected"]: [lindex $info 2]"
416    if {[string length [$self cget -parent]]} {
417      set par $self
418    } else {
419      set par [$self cget -parent]
420    }
421    tk_messageBox -default ok \
422                  -icon info  \
423                  -message $msg \
424                  -type ok \
425                  -parent $par \
426                  -title [mc "numero de elementos"]
427  }
428
429
430  #/////////////////////////////////////////////////////////////////////////////
431  method _ToggleSelection {} {
432  #
433  # PURPOSE: Toggle selection elements
434  #
435  #/////////////////////////////////////////////////////////////////////////////
436    foreach i [$self get] {
437      $self selection toggle $i
438    }
439  }
440
441
442  #///////////////////////////////////////////////////////////////////////////
443  method _SelectAll { } {
444  #
445  # PURPOSE: Selection all
446  #
447  #///////////////////////////////////////////////////////////////////////////
448    foreach i [$self get] {
449      $self selection set $i
450    }
451  }
452
453
454  #/////////////////////////////////////////////////////////////////////////////
455  method _CopyToClipBoard { sl unSe {pref ""} {suf ""} {sep "\n"}} {
456  #
457  # PURPOSE: copy the elements indicates in clipboard
458  #
459  # PARAMETERS:
460  #   sl   -> Copy items selections
461  #   unSe -> Copy items not selections
462  #   pref -> Text to concatenate in the beginning. Default ""
463  #   suf  -> Text to concatenate in the end. Default ""
464  #   sep  -> Separating text of elements. Default "\n"
465  #
466  #/////////////////////////////////////////////////////////////////////////////
467    # items to copy
468    set lst {}
469    if { $sl } {
470      foreach i [$self curselection] {
471        lappend lst [$self get $i]
472      }
473    }
474    if { $unSe } {
475      foreach i [$self selection get unselected] {
476        lappend lst [$self get $i]
477      }
478    }
479    # copy
480    set str [ListToStr $lst $sep $pref $suf]
481    clipboard clear
482    clipboard append $str
483  }
484
485
486  #/////////////////////////////////////////////////////////////////////////////
487  method _SaveToFile {se unSe {pref ""} {suf ""} {sep "\n"}} {
488  #
489  # PURPOSE: Save the content from listbox in a file
490  #
491  # PARAMETERS:
492  #    sl   -> Copy items selections
493  #   unSe -> Copy items not selections
494  #   pref -> Text to concatenate in the beginning. Default ""
495  #   suf  -> Text to concatenate in the end. Default ""
496  #   sep  -> Separating text of elements. Default "\n"
497  #
498  #/////////////////////////////////////////////////////////////////////////////
499    # select file
500    set filNam [tk_getSaveFile -parent $self -title [mc "File selector"] \
501                               -initialdir $options(-initialdir)]
502
503    if {$filNam != ""} {
504      set options(-initialdir) [file dirname $filNam]   
505      # open file to write
506      if { ![ catch { set fd [open $filNam w] } msgerr] } {
507        # text to save
508        set lst {}
509        if { $se } {
510          foreach i [$self selection get selected] {
511            lappend lst [$self get $i]
512          }
513        }
514        if { $unSe } {
515          foreach i [$self selection get unselected] {
516            lappend lst [$self get $i]
517          }
518        }
519        set str [ListToStr $lst $sep $pref $suf]
520        # write
521        puts -nonewline $fd $str
522        close $fd
523        return 1
524      }
525      error $msgerr
526    }
527  }
528
529  #/////////////////////////////////////////////////////////////////////////////
530  method  _LoadFromFile { } {
531  #
532  # PURPOSE: Load the content from listbox in a file
533  #
534  #/////////////////////////////////////////////////////////////////////////////
535    # select file   
536    set filNam [tk_getOpenFile -parent $self -title [mc "File selector"] \
537                               -initialdir $options(-initialdir)]   
538
539    if {$filNam != ""} {
540      set options(-initialdir) [file dirname $filNam]
541      # open file to read
542      if { ![ catch { set fd [open $filNam r] } msgerr] } {
543         while { [gets $fd line ] >= 0} {
544           $self add $line
545         }
546         close $fd     
547         return 1
548      }
549      error $msgerr
550    }
551  }
552
553 
554  #///////////////////////////////////////////////////////////////////////////
555  method _SortByColumn { col } {
556  #
557  # PURPOSE: Sorts the ListBox by the values of the given column
558  # PARAMETERS:
559  #  col -> the column which the sort is performed
560  #
561  #///////////////////////////////////////////////////////////////////////////
562    $self _QuickSort $col 0 [expr [$self size]-1]
563  }
564
565
566  #///////////////////////////////////////////////////////////////////////////
567  method _QuickSort { col left right } {
568  #
569  # PURPOSE:
570  #  function quicksort(a, left, right)
571  #      if right > left
572  #          select a pivot value a[pivotIndex]
573  #          pivotNewIndex := partition(a, left, right, pivotIndex)
574  #          quicksort(a, left, pivotNewIndex-1)
575  #          quicksort(a, pivotNewIndex+1, right)
576  #
577  #///////////////////////////////////////////////////////////////////////////
578    if {$right > $left} {
579      set pivotIndex [expr (($left + $right) / 2)]
580      set pivotNewIndex [$self _Partition $col $left $right $pivotIndex]
581      $self _QuickSort $col $left [expr $pivotNewIndex-1]
582      $self _QuickSort $col [expr $pivotNewIndex+1] $right
583    }
584  }
585
586
587  #///////////////////////////////////////////////////////////////////////////
588  method _Partition { col left right pivotIndex } {
589  #
590  # PURPOSE:
591  #  function partition(a, left, right, pivotIndex)
592  #      pivotValue := a[pivotIndex]
593  #      swap(a[pivotIndex], a[right]) // Move pivot to end
594  #      storeIndex := left
595  #      for i from left to right
596  #          if a[i] <= pivotValue
597  #              swap(a[storeIndex], a[i])
598  #              storeIndex := storeIndex + 1
599  #      swap(a[right], a[storeIndex]) // Move pivot to its final place
600  #      return storeIndex
601  #
602  #///////////////////////////////////////////////////////////////////////////
603    set pivotValue [$self get [lindex [$self get] $pivotIndex] $col]
604    $self _Swap $pivotIndex $right
605    set storeIndex $left
606    for { set i $left } { $i < $right } { incr i } {
607      if { [$self get [lindex [$self get] $i] $col] <= $pivotValue } {
608        $self _Swap $storeIndex $i
609        incr storeIndex
610      }
611    }
612    $self _Swap $right $storeIndex
613    return $storeIndex
614  }
615
616
617  #///////////////////////////////////////////////////////////////////////////
618  method _Swap { index1 index2 } {
619  #
620  # PURPOSE:
621  #
622  #///////////////////////////////////////////////////////////////////////////
623    if { $index1 < $index2 } {
624      set lst [$self get]
625      $self move [lindex $lst $index1] after [lindex $lst $index2]
626      set lst [$self get]
627      $self move [lindex $lst [expr $index2-1]] before [lindex $lst $index1]
628    } elseif { $index1 > $index2 } {
629      set lst [$self get]
630      $self move [lindex $lst $index1] before [lindex $lst $index2]
631      set lst [$self get]
632      $self move [lindex $lst [expr $index2+1]] after [lindex $lst $index1]
633    }
634  }
635
636
637  #///////////////////////////////////////////////////////////////////////////
638  proc _AddWR { elem father } {
639  #
640  # PURPOSE: adds the item introduced in the dialog to the selected list
641  #
642  # PARAMETERS:
643  #  elem -> the element to insert from the add dialog
644  #  father -> The dialog's window pathname
645  #
646  #///////////////////////////////////////////////////////////////////////////
647    foreach ele $elem {
648      $father insert 0 $ele
649    }
650  }
651
652
653  #//////////////////////////////////////////////////////////////////////////
654  method _OpenWR {} {
655  #
656  # PURPOSE: Calls (and creates) an add dialog for insert by hand elements
657  #
658  #///////////////////////////////////////////////////////////////////////////
659    destroy $self.dw
660   
661    if {![catch {eval $options(-valuesinsert)} res]} {
662      set valuesinsert $res
663    } else {
664      set valuesinsert $options(-valuesinsert)
665    }
666   
667    if {$valuesinsert == ""} {
668      set dialog  [bfieldsdialog $self.dw -title [mc "Insert element"] \
669                  -parent $self -orientation $options(-orientation) \
670                  -fields $options(-cols) -procedure [codename _AddWR] \
671                  -buttons { add exit } -titles $options(-titles) \
672                  -list $valuesinsert]
673    } else {       
674      set dialog  [bfieldsdialog $self.dw -title [mc "Insert element"] \
675                  -parent $self -orientation $options(-orientation) \
676                  -fields $options(-cols) -procedure [codename _AddWR] \
677                  -buttons { add addall exit } -titles $options(-titles) \
678                  -list $valuesinsert]
679    }
680    $dialog draw
681  }
682 
683 
684  #///////////////////////////////////////////////////////////////////////////
685  proc _Filter { elem father } {
686  #
687  # PURPOSE: Filters the listbox with the filter suministred
688  #
689  # PARAMETERS:
690  #  elem -> the list with the filter fields
691  #  father -> The dialog's window pathname
692  #
693  #///////////////////////////////////////////////////////////////////////////
694    eval $father filter $elem
695  }
696
697
698  #//////////////////////////////////////////////////////////////////////////
699  method _OpenFD {} {
700  #
701  # PURPOSE: Calls (and creates) a add dialog for getting a filter
702  #
703  #///////////////////////////////////////////////////////////////////////////
704
705    destroy $self.fd
706    set dialog  [bfieldsdialog $self.fd -title [mc "Filter elements"] \
707                -parent $self -orientation $options(-orientation) \
708                -fields $options(-filtercols) -procedure [codename _Filter] \
709                -buttons { info apply accept cancel } \
710                -titles $options(-titles)]
711    $dialog configure -info \
712"Los filtros admiten expresiones regulares:
713
714  expresiones regulares básicas:
715    - literales: caracteres simples
716    - brackets:  conincide con cualquier caracter especificado dentro
717       tambien pueden expecificarse rangos pe \[a-d\] equivale a \[abcd\]
718       o indicar la no coincidencia colocando como primer caracter ^
719       rangos predefinidos:
720        \[:alnum:\] equivale a \[0-9a-zA-Z\]
721        \[:alpha:\] equivale a \[a-zA-Z\]
722        \[:digit:\] equivale a \[0-9\]
723        \\w equivale a \[:alnum:\]
724        \\W equivale a \[^:alnum:\]
725        para incluir el literal - ponerlo al final del braquet
726        para incluir el literal ^ ponerlo en cualquier lugar menos el primero
727    - punto . : coincide con cualquier caracter simple
728    - ^ y $ : coinciden respectivamente con el principio o final de linea
729    - caracteres especiales: los caracteres que tienen significado en las
730      expresiones regulares pueden escribirse precediendolos con \\
731   
732  operadores sobre las expresiones:
733    - <e1><e2>: concatenacion, la expresion resultante coincide si coinciden
734         secuencialmente las expresiones
735    - <e1>|<e2> : disyuncion, coincide si coincide alguna de las expresiones
736    - <e>? : opcionalidad, coincide si la expresion anterior coincide 0 o 1 vez
737    - <e>* : repeticion, coincide si la expresion anterior coincide 0 o mas veces
738    - <e>+ : repeticion, coincide si la expresion anterior coincide 1 o mas veces
739    - <e>{n} : repeticion, coincide si la expresion anterior coincide  n veces
740    - <e>{n,} : repeticion, coincide si la exp anterior coincide n o mas veces
741    - <e>{n,m} : repeticion, coincide si la exp anterior coincide por lo menos n
742         y no mas de m veces
743
744  precedencia de los operadores:
745    - los operadores de repeticion tienen preferencia sobre la concatenacion
746    - la concatenacion tiene preferencia sobre la disyuncion
747    - las reglas pueden alterarse con el uso de parentesis
748"
749       
750    $dialog draw
751  }
752 
753  #///////////////////////////////////////////////////////////////////////////
754  method _WriteIni { } {
755  #
756  # PURPOSE: Guarda en el .ini informacion referente al blistboxplus
757  #
758  #
759  #///////////////////////////////////////////////////////////////////////////
760    if { [$self cget -iniconfig] ne "" } {
761      # comprobamos cargado namespace y variable de .ini
762      if {[namespace exists ::iniFile]} {
763        set wini ::iniFile::Write
764        set nm [$self cget -iniconfig]
765        if {![string length $nm]} {
766          set nm $self
767        }
768        $wini $nm initialdir $options(-initialdir)
769      }
770    }
771  }
772
773  #///////////////////////////////////////////////////////////////////////////
774  method _ReadIni { } {
775  #
776  # PURPOSE: Recupera del .ini informacion referente al blistboxplus
777  #
778  #
779  #///////////////////////////////////////////////////////////////////////////
780    if { [$self cget -iniconfig] ne "" } {
781      # comprobamos cargado namespace y variable de .ini
782      if {[namespace exists ::iniFile]} {
783        set rini ::iniFile::Read
784        set nm [$self cget -iniconfig]
785        if {![string length $nm]} {
786          set nm $self
787        }
788        set stt [::iniFile::ReadWMState $rini $nm]
789        set inid [$rini $nm initialdir ""]       
790        if {[string length $inid]} {
791            set options(-initialdir) $inid
792        }
793      }
794    }
795  }
796
797
798  #///////////////////////////////////////////////////////////////////////////
799  method selection { args } {
800  #
801  # PURPOSE: extends the original command to extend capabilities
802  #
803  # PARAMETERS:
804  #   args: arguments
805  #
806  #///////////////////////////////////////////////////////////////////////////
807    if { [lindex $args 0] eq "get" } {
808     if { [lindex $args 1] eq "unselected" } {
809       set result {}
810       set selected [$self curselection]
811       foreach i [$self get] {
812         if { "-1" eq [lsearch $selected $i] } {
813           lappend result $i
814         }
815       }
816       return $result
817     } else {
818      return [eval $_listbox curselection]
819     }
820    }
821
822    eval $_listbox selection $args
823  }
824
825
826  #///////////////////////////////////////////////////////////////////////////
827  method insert { pos args } {
828  #
829  # PURPOSE: inserts an element into de listbox
830  #
831  # PARAMETERS:
832  #   args: a list of elements to insert, each element is a list with column
833  #   data
834  #
835  #///////////////////////////////////////////////////////////////////////////   
836    if { [lindex $args 0] eq "cols" } {
837      set cols [lindex $args 1]
838      set args [lrange $args 2 end]
839    } else {
840      set cols $options(-cols)
841    }
842   
843    switch [llength $cols] {
844      1 {
845        # mas de una columna
846        foreach dats $args {
847          set datos [list [lindex $cols 0] $dats]
848          $_listbox insert $pos $currentId -data $datos
849          incr currentId
850        }       
851      }
852      default {
853        # mas de una columna
854        foreach dats $args {
855          set i 0
856          set datos {}
857          foreach col $cols {
858            lappend datos $col [lindex $dats $i]
859            incr i
860          }
861          $_listbox insert $pos $currentId -data $datos
862          incr currentId
863        }
864      }
865    }
866  }
867
868
869  #///////////////////////////////////////////////////////////////////////////
870  method add { args } {
871  #
872  # PURPOSE: appends elements to dthe listbox
873  #
874  # PARAMETERS:
875  #   args: a list of elements to insert, each element is a list with column
876  #   data
877  #
878  #///////////////////////////////////////////////////////////////////////////
879    eval $self insert end $args
880  }
881 
882
883  #///////////////////////////////////////////////////////////////////////////
884  method delete { args } {
885  #
886  # PURPOSE: deletes elements from the listbox
887  #
888  # PARAMETERS:
889  #   args: the tags or ids of the items to be deleted
890  #   data
891  #
892  #///////////////////////////////////////////////////////////////////////////
893    if { "-1" eq [lsearch $args 0] } {
894      eval $_listbox delete $args
895    } else {
896      puts "Root node can't be deleted"
897    }
898  }
899 
900 
901  #/////////////////////////////////////////////////////////////////////////// 
902  method getlb {} {
903  #
904  # PURPOSE: Get path of blistboxplus
905  #
906  #/////////////////////////////////////////////////////////////////////////// 
907    return $_listbox
908  }
909
910
911  #///////////////////////////////////////////////////////////////////////////
912  method get { {ids ""} {cols ""}} {
913  #
914  # PURPOSE: retrieves data from an entry identified by id
915  #
916  # PARAMETERS:
917  #  id: id list of nodes
918  #  cols: name of the cols from which retrieve data
919  #
920  #///////////////////////////////////////////////////////////////////////////
921    if { $ids eq "" } { return [lrange [$self find] 1 end] }
922 
923    set result {}
924   
925    foreach id $ids {
926   
927      set elem {}
928   
929      set data [$_listbox entry cget $id -data]   
930      if { "$cols" eq "" } {
931        set cols [$self column names]
932      }
933   
934      foreach col $cols {
935        set inx [lsearch $data $col]
936        if { "-1" ne $inx } {
937          incr inx
938          lappend elem [lindex $data $inx]
939        }
940      }
941     
942      lappend result $elem
943    }
944    if { [llength $ids] eq 1 } { return [lindex $result 0] }
945    return $result
946  }
947
948
949  #///////////////////////////////////////////////////////////////////////////
950  method set { id data {cols ""}} {
951  #
952  # PURPOSE: inserts data to an entry identified by id
953  #
954  # PARAMETERS:
955  #  id: id of the node
956  #  data: data to insert
957  #  cols: name of the cols from which retrieve data
958  #
959  #///////////////////////////////////////////////////////////////////////////
960    if { "$cols" eq "" } {
961      set cols [$self column names]
962    }   
963    set datos {}
964    set i 0   
965    foreach col $cols {
966      lappend datos $col
967      lappend datos [lindex $data $i]
968      incr i
969    }
970    return [$_listbox entry configure $id -data $datos]
971  }
972
973
974  #///////////////////////////////////////////////////////////////////////////
975  method first {} {
976  #
977  # PURPOSE: Selects and returns the first row of blistboxplus
978  #
979  # RETURN: The index of first row
980  #
981  #///////////////////////////////////////////////////////////////////////////
982    set all [$self get]
983    set selected [$self selection get]
984    if {$selected != ""} {   
985      foreach item $selected { 
986        $self selection clear $item
987      }
988    }
989    if { !([llength [$self get]] eq 0)} {
990      $self selection set [lindex $all 0]
991    }
992    return [lindex $all 0]
993  }
994   
995   
996  #///////////////////////////////////////////////////////////////////////////
997  method last {} {
998  #
999  # PURPOSE: Selects and returns the last row of blistboxplus
1000  #
1001  # RETURN: The index of last row
1002  #
1003  #///////////////////////////////////////////////////////////////////////////
1004    set all [$self get]
1005    set selected [$self selection get]
1006    if {$selected != ""} {
1007      foreach item $selected {
1008        $self selection clear $item
1009      }             
1010    }
1011    if { !([llength [$self get]] eq 0)} {
1012      $self selection set [lindex $all [expr [llength $all] - 1]]
1013    }
1014    return [lindex $all [expr [llength $all] - 1]]           
1015  }
1016
1017
1018  #///////////////////////////////////////////////////////////////////////////
1019  method addPrevious {} {
1020  #
1021  # PURPOSE: adds the row previous to the present selection
1022  #
1023  # RETURN: The index of the row previous
1024  #
1025  #///////////////////////////////////////////////////////////////////////////
1026    set all [$self get]
1027    set selected [$self selection get]
1028    if {$selected == ""} {
1029      return -1
1030    } else  {
1031      set firstSelected [lindex $selected 0]
1032      set first [lindex $all 0]
1033      if { $first == $firstSelected } {
1034        return [lindex $all 0]
1035      } else  {
1036        set allPosition [lsearch -exact $all $firstSelected]
1037        set firstSelected [lindex $all [expr $allPosition - 1]]
1038        #set firstSelected [expr $firstSelected - 1]
1039        $self selection set $firstSelected
1040        return $firstSelected
1041      }
1042    }
1043  }
1044 
1045
1046  #///////////////////////////////////////////////////////////////////////////
1047  method addNext {} {
1048  #
1049  # PURPOSE: Adds the following row to the present selection
1050  #
1051  # RETURN: The index of the following row
1052  #
1053  #///////////////////////////////////////////////////////////////////////////
1054    set all [$self get]
1055    set selected [$self selection get]
1056    if {$selected == ""} {
1057      return -1     
1058    } else  {
1059      set lastSelected [lindex $selected [expr [llength $selected] - 1] ]
1060      set last [lindex $all [expr [llength $all] - 1]]
1061      if { $last == $lastSelected } {
1062        return [lindex $all [expr [llength $all] - 1]]
1063      } else  {
1064        set allPosition [lsearch -exact $all $lastSelected]
1065        set lastSelected [lindex $all [expr $allPosition + 1]]
1066        $self selection set $lastSelected
1067        return $lastSelected
1068      }
1069    }   
1070  }
1071
1072
1073  #///////////////////////////////////////////////////////////////////////////
1074  method previous {} {
1075  #
1076  # PURPOSE: selects the row previous to the present selection
1077  #
1078  # RETURN: The index of the row previous
1079  #
1080  #///////////////////////////////////////////////////////////////////////////
1081    set all [$self get]
1082    set selected [$self selection get]
1083    if {$selected == ""} {
1084      return -1
1085    } else  {
1086      foreach item $selected {
1087        $self selection clear $item
1088      }
1089      set firstSelected [lindex $selected 0]
1090      set first [lindex $all 0]
1091      if { $first == $firstSelected } {
1092        $self selection set $firstSelected
1093        return [lindex $all 0]
1094      } else  {
1095        set allPosition [lsearch -exact $all $firstSelected]
1096        set firstSelected [lindex $all [expr $allPosition - 1]]
1097        $self selection set $firstSelected
1098        return $firstSelected
1099      }
1100    }
1101  }
1102   
1103
1104  #///////////////////////////////////////////////////////////////////////////
1105  method next {} {
1106  #
1107  # PURPOSE: selects the following row to the present selection
1108  #
1109  # RETURN: The index of the following row
1110  #
1111  #///////////////////////////////////////////////////////////////////////////
1112    set all [$self get]
1113    set selected [$self selection get]
1114    if {$selected == ""} {
1115      return -1
1116    } else  {
1117      foreach item $selected {
1118        $self selection clear $item
1119      }
1120      set lastSelected [lindex $selected [expr [llength $selected] - 1] ]
1121      set last [lindex $all [expr [llength $all] - 1]]
1122      if { $last == $lastSelected } {
1123        $self selection set $lastSelected
1124        return [lindex $all [expr [llength $all] - 1]]
1125      } else  {
1126        set allPosition [lsearch -exact $all $lastSelected]
1127        set lastSelected [lindex $all [expr $allPosition + 1]]
1128        $self selection set $lastSelected
1129        return $lastSelected
1130      }
1131    }
1132  }
1133   
1134
1135  #///////////////////////////////////////////////////////////////////////////
1136  method addAllPrevious {} {
1137  #
1138  # PURPOSE: Selects all the previous rows
1139  #
1140  # RETURN: The index of the first row
1141  #
1142  #///////////////////////////////////////////////////////////////////////////
1143    set all [$self get]
1144    set selected [$self selection get]
1145    if {$selected == ""} {
1146      return -1
1147    } else  {
1148      set firstSelected [lindex $selected 0]
1149      set first [lindex $all 0]
1150      set allPosition [lsearch -exact $all $firstSelected]
1151      while { $allPosition != 0 } {
1152        $self addPrevious
1153        #$self selection set $firstSelected
1154        set selected [$self selection get]
1155        set allPosition [lsearch -exact $all $firstSelected]
1156        if { $allPosition != 0 } {
1157          set firstSelected [lindex $all [expr $allPosition - 1]]
1158        }
1159      } 
1160      return [lindex $firstSelected]
1161    }
1162  }
1163   
1164
1165  #///////////////////////////////////////////////////////////////////////////
1166  method addAllNext {} {
1167  #
1168  # PURPOSE: Selects all the following rows
1169  #
1170  # RETURN: The index of the last row
1171  #
1172  #///////////////////////////////////////////////////////////////////////////
1173    set all [$self get]
1174    set selected [$self selection get]
1175    if {$selected == ""} {
1176      return -1
1177    } else  {
1178      set lastSelected [lindex $selected [expr [llength $selected] - 1] ]
1179      set last [lindex $all [expr [llength $all] - 1]] 
1180      set allPosition [lsearch -exact $all $lastSelected]
1181      while {$allPosition != [expr [llength $all] -1]} {
1182        $self addNext
1183        set selected [$self selection get]
1184        set lastSelected [lindex $selected [expr [llength $selected] - 1] ]
1185        set allPosition [lsearch -exact $all $lastSelected]
1186      }
1187      return $lastSelected
1188    }
1189  }
1190   
1191
1192  #///////////////////////////////////////////////////////////////////////////
1193  method clear {} {
1194  #
1195  # PURPOSE: deletes all nodes
1196  #
1197  #///////////////////////////////////////////////////////////////////////////
1198    foreach i [$self get] {
1199      if { 0 eq $i } { continue }
1200      $self delete $i
1201    }
1202  }
1203
1204
1205  #///////////////////////////////////////////////////////////////////////////
1206  method size {} {
1207  #
1208  # PURPOSE: calculates the listbox size
1209  #
1210  #///////////////////////////////////////////////////////////////////////////
1211    return [$_listbox entry size root]
1212  }
1213
1214
1215  #///////////////////////////////////////////////////////////////////////////
1216  method column { args } {
1217  #
1218  # PURPOSE: modifies a particular case of column -> column names
1219  #
1220  #///////////////////////////////////////////////////////////////////////////
1221    if { [lindex $args 0] eq "names" } {
1222      return [lrange [$_listbox column names] 1 end]
1223    }
1224    return [eval $_listbox column $args]
1225  }
1226 
1227
1228  #///////////////////////////////////////////////////////////////////////////
1229  method filter { filters } {
1230  #
1231  # PURPOSE: filters the listbox elements matching filters for each col in cols
1232  #
1233  # PARAMETERS:
1234  #  filters: list of filters for the columns above
1235  #
1236  #///////////////////////////////////////////////////////////////////////////
1237    $self configure -flat no
1238    foreach inx [$self get] {
1239      set datos [$self get $inx $options(-filtercols)]
1240      set match 1
1241      for { set i 0 } { $i < [llength $filters] } { incr i } {
1242        set match [expr $match & [regexp [lindex $filters $i] [lindex $datos $i]]]
1243      }
1244      if { ! $match } {
1245        $_listbox hide $inx
1246      } else {
1247        $_listbox show $inx
1248      }
1249    }
1250    $self configure -flat yes
1251
1252  }
1253
1254  #///////////////////////////////////////////////////////////////////////////
1255  method _RemoveFilter { } {
1256  #
1257  # PURPOSE: filters the listbox elements matching filters for each col in cols
1258  #
1259  # PARAMETERS:
1260  #  filters: list of filters for the columns above
1261  #
1262  #///////////////////////////////////////////////////////////////////////////
1263    $_listbox configure -flat no
1264    $_listbox show all
1265    $_listbox configure -flat yes
1266  }
1267
1268  #///////////////////////////////////////////////////////////////////////////
1269  method icon { id icon } {
1270  #
1271  # PURPOSE: changes the icon for an entry identified by id
1272  #
1273  # PARAMETERS:
1274  #  id: the identificator of the entry
1275  #  icon: the icon image (must be 16x16
1276  #
1277  #///////////////////////////////////////////////////////////////////////////
1278    $_listbox entry configure $id \
1279      -icons [list [Bitmap::get $icon] [Bitmap::get $icon]]
1280  }
1281
1282  # delegacion de metodos y opciones
1283  delegate method * to _listbox
1284  delegate option * to _listbox
1285}
1286
1287package provide blistboxplus 1.0
1288
1289# ------- TEST CODE ----
1290
1291#/////////////////////////////////////////////////////////////////////////////
1292proc test_blistboxplus {} {
1293#
1294# PURPOSE: Funcion de test de un blistcontrol
1295#
1296#///////////////////////////////////////////////////////////////////////////// 
1297  # defining the widgets
1298  variable data
1299  set data(-selected) 1
1300 
1301  destroy .top
1302  toplevel .top -width 200 -height 100
1303   
1304  TitleFrame .top.f1 -text "BListBoxPlus test"
1305  set f1 [ .top.f1 getframe ]
1306  blistboxplus $f1.blb -cols { col1 col2 col3 col4 } -parent $f1 \
1307                    -height 150 -width 500 -orientation vertical \
1308                    -hiddencols {col4}
1309  $f1.blb insert end {1 2 3 4} {one two three four} {uno dos tres cuatro} \
1310                     {k kk kkk kkkk} {0 0 0 0} {@ # $ %}
1311 
1312  TitleFrame .top.f2 -text "Configure"
1313  set f2 [ .top.f2 getframe ]
1314  LabelEntry $f2.lei -width 5 -label Index -text 1
1315  LabelEntry $f2.lee -width 5 -label End
1316  LabelEntry $f2.lec -width 50 -label Content -text "{hay que introducir cada} \
1317     {fila entre corchetes y} {entre estos los items}"
1318  checkbutton $f2.cb -text "Allow multiple selection" \
1319    -command { toggleSelectModeCmd }
1320  $f2.cb select
1321  button $f2.bi -text "Insert" -command { insertCmd }
1322  button $f2.bd -text "Delete" -command { deleteCmd }
1323  button $f2.br -text "Reset" -command { resetCmd }
1324  $f2.bi configure -width 20
1325  $f2.bd configure -width 20
1326  # packing all
1327 
1328  grid .top.f1 -row 0 -column 0 -sticky "new" -padx 10 -pady 10
1329  grid .top.f2 -row 1 -column 0 -sticky "new" -padx 10 -pady 10
1330  grid columnconfigure .top 0 -weight 1
1331  grid rowconfigure .top 0 -weight 0
1332  grid rowconfigure .top 1 -weight 1
1333 
1334  grid $f1.blb -row 0 -column 0 -sticky "new"
1335  grid columnconfigure $f1 0 -weight 1
1336  grid rowconfigure $f1 0 -weight 1
1337
1338  grid $f2.lec -row 0 -column 0 -sticky "new" -columnspan 3
1339  grid $f2.lei -row 1 -column 0 -sticky "new"
1340  grid $f2.lee -row 1 -column 1 -sticky "new"
1341   
1342  grid $f2.cb  -row 1 -column 2 -sticky "new"
1343  grid $f2.bi  -row 2 -column 0 -sticky "new"
1344  grid $f2.bd  -row 2 -column 1 -sticky "new"
1345  grid $f2.br  -row 2 -column 2 -sticky "new"
1346  grid columnconfigure $f2 0 -weight 0
1347  grid columnconfigure $f2 1 -weight 0
1348  grid columnconfigure $f2 2 -weight 1
1349  grid rowconfigure $f2 0 -weight 0
1350  grid rowconfigure $f2 1 -weight 0
1351  grid rowconfigure $f2 2 -weight 0
1352
1353  puts "WIDGET blistboxplus: $f1.blb"
1354 
1355  # commands attached to the widgets
1356  proc insertCmd {} {
1357    eval .top.f1.f.blb insert [.top.f2.f.lei cget -text] \
1358                              [.top.f2.f.lec cget -text]
1359  }
1360 
1361  proc deleteCmd {} {
1362    .top.f1.f.blb delete [.top.f2.f.lei cget -text] \
1363                         [.top.f2.f.lee cget -text]
1364  }
1365 
1366  proc resetCmd {} {
1367    .top.f1.f.blb clear
1368    .top.f1.f.blb insert end {1 2 3 4} {one two three four} \
1369          {uno dos tres cuatro} {k kk kkk kkkk} {0 0 0 0} {@ # $ %}
1370  }
1371 
1372  proc toggleSelectModeCmd {} {
1373    if { [.top.f1.f.blb cget -selectmode] eq "multiple" } {
1374          .top.f1.f.blb configure -selectmode single
1375    } else {
1376          .top.f1.f.blb configure -selectmode multiple
1377    }
1378  }
1379}
Note: See TracBrowser for help on using the repository browser.