source: tol/tolbase/lib/byswidget/blistboxplus/blistboxplus.tcl

devel
Last change on this file was f738c05, checked in by Pedro Gea <pgea@…>, 10 years ago

Refs #1933
Se revisa el widget blistboxplus.
Se eliminan las barras propias (ya están las de wtree).
Se elimina código antiguo comentado.

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

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