source: tol/tolbase/lib/wtree/wtree.tcl @ 72b4d96

1941-docker-image-to-testdevel
Last change on this file since 72b4d96 was 2c0158d, checked in by Jorge Pérez <josp.jorge@…>, 15 years ago

refs #1417, implementamos un metodo de wtree para facilitar la modificación/consulat de las columnas en items creados, el ícono del nodo de un paquete refleja el estado de sus hijos (paquetes con versión específica), se corrige un error cuando la ruta de instalación de los paquetes tiene espacio en el nombre

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

  • Property mode set to 100644
File size: 32.3 KB
Line 
1if { [ string compare $::tcl_version "8.5" ] >= 0 } {
2  package require tile
3}
4package require -exact treectrl 2.2.9
5package require autoscroll
6package require snit
7
8#
9# TODO:
10#
11#  - filtrado: una entry y filtrar tipo google
12#
13#     buscar mientras se escribe puede ser lento, podemos encolar la
14#     busqueda para que sea atendida en un after idle. Para eso el
15#     loop de busqueda debe entrar en el loop de eventos de tcl
16#
17#  - especificar columnas de filtrado
18#
19#  - parametrizar el contenido de las columnas: usar -tags, sino se da
20#    tag se asume el tag column${i}
21#
22#  - propiedad "-globalcheck" para indicar si el campo check debe
23#    sincronizar entre todos los items. Esto implica que sea de tipo
24#    "tristate" para poder reflejar un nodo con hijos parcialmente
25#    seleccionados. Si un campo check no esta marcado como
26#    "globalcheck" entonces es de tipo "on/off".
27#
28#  - la columna 1 puede llevar dos imagenes para open y close que
29#    pueden estar dadas por imision.
30#
31#  - open_image, close_image: dar unas por omision. No tener en cuenta
32#    si es formato tabla.
33#
34#  - en una columna puedo tener "image", "text" o check
35#
36
37#
38# Ejemplo de especificacion:
39if { 0 } {
40  wtree .t01.t \
41      -columns [ list \
42                     { -tags ID -label "Identifier" \
43                           {-type image} {-type text } } \
44                     { -tags DESC -label "Description" {-type text} } ]
45
46 # en la definicion de las elementos de columnas se puede dar un unico
47 # elemento en cuyo caso se dice el tipo o se puede dar una lista de
48 # pares uno de los cuales espcifica el tipo del elemento y el resto
49 # define propiedades del elemento.
50
51  .t01.t insert { {"" "node1"} {"Desc. node1"} }
52  .t01.t insert [ list { -image "" -text "node 1" } { -text "Desc. node 1" } ]
53
54 # en la insercion de un item las columnas se pueden dar con un solo
55 # elemento si la columna contiene solo un elemento o una lista de
56 # pares indicando para cada tipo el valor de la propiedad
57}
58 
59snit::widget wtree {
60  typevariable SystemButtonFace
61  typevariable SystemHighlight
62  typevariable SystemHighlightText
63  typevariable ButtonImageConf
64
65  option -columns \
66      -default "" -configuremethod "_conf-columns"
67  option -buttonstyle \
68      -default "" -configuremethod "_conf-buttonstyle"
69  option -table \
70      -default no -configuremethod "_conf-table"
71  option -contextmenu  \
72      -default "" -configuremethod "_conf-contextmenu"
73
74  option -filter \
75      -default 0 -configuremethod "_conf-filter"
76
77  option -columnfilter \
78      -default "" -configuremethod "_conf-columnfilter"
79 
80  variable tree
81  variable vscrollbar
82  variable hscrollbar
83
84  variable elements
85  variable styles
86  variable column_info
87
88  variable textFilter
89  variable columnsToFilter -array {-1 0}
90  variable idIdleFilter ""
91  variable idWaitFilter ""
92  variable breakFilter 0
93  variable numItemsFiltered 0
94  variable listFilterOn  ""
95  variable listFilterOff ""
96  variable widgets
97
98  variable sortedColumn 0
99
100  method _getTrace_ { } {
101    trace info variable [ myvar textFilter ]
102  }
103
104  delegate method * to tree
105  delegate option * to tree
106  delegate option -borderwidth to hull
107  delegate option -bd to hull
108  delegate option -relief to hull
109 
110  typeconstructor {
111   
112    set thisPlatform $::tcl_platform(platform)
113    set w [ listbox .___lb___ ]
114    set SystemButtonFace [$w cget -highlightbackground]
115    set SystemHighlight [$w cget -selectbackground]
116    set SystemHighlightText [$w cget -selectforeground]
117    destroy $w
118
119    if {$thisPlatform == "unix"} {
120      # I hate that gray selection color
121      set SystemHighlight #316ac5
122      set SystemHighlightText White
123    }
124
125    if { [ lsearch -exact [ image names ] mac-collapse ] == -1 } {
126      image create photo mac-collapse  -data {
127        R0lGODlhEAAQALIAAAAAAAAAMwAAZgAAmQAAzAAA/wAzAAAzMyH5BAUAAAYA
128        LAAAAAAQABAAggAAAGZmzIiIiLu7u5mZ/8zM/////wAAAAMlaLrc/jDKSRm4
129        OAMHiv8EIAwcYRKBSD6AmY4S8K4xXNFVru9SAgAh/oBUaGlzIGFuaW1hdGVk
130        IEdJRiBmaWxlIHdhcyBjb25zdHJ1Y3RlZCB1c2luZyBVbGVhZCBHSUYgQW5p
131        bWF0b3IgTGl0ZSwgdmlzaXQgdXMgYXQgaHR0cDovL3d3dy51bGVhZC5jb20g
132        dG8gZmluZCBvdXQgbW9yZS4BVVNTUENNVAAh/wtQSUFOWUdJRjIuMAdJbWFn
133        ZQEBADs=
134      }
135    }
136
137    if { [ lsearch -exact [ image names ] mac-expand ] == -1 } {
138      image create photo mac-expand -data {
139        R0lGODlhEAAQALIAAAAAAAAAMwAAZgAAmQAAzAAA/wAzAAAzMyH5BAUAAAYA
140        LAAAAAAQABAAggAAAGZmzIiIiLu7u5mZ/8zM/////wAAAAMnaLrc/lCB6MCk
141        C5SLNeGR93UFQQRgVaLCEBasG35tB9Qdjhny7vsJACH+gFRoaXMgYW5pbWF0
142        ZWQgR0lGIGZpbGUgd2FzIGNvbnN0cnVjdGVkIHVzaW5nIFVsZWFkIEdJRiBB
143        bmltYXRvciBMaXRlLCB2aXNpdCB1cyBhdCBodHRwOi8vd3d3LnVsZWFkLmNv
144        bSB0byBmaW5kIG91dCBtb3JlLgFVU1NQQ01UACH/C1BJQU5ZR0lGMi4wB0lt
145        YWdlAQEAOw==
146      }
147    }
148
149    if { [ lsearch -exact [ image names ] folder-open ] == -1 } {
150      image create photo folder-open -data {
151        R0lGODlhEAANANIAAAAAAISEhMbGxv//AP////8AAAAAAAAAACH5BAkZAAUA
152        LAAAAAAQAA0AAAM8WBrM+rAEQmmIb4qxBWnNQnCkV32ARHRlGQBgDA7vdN6v
153        UK8tC78qlrCWmvRKsJTquHkpZTKAsiCtWq0JAAA7
154      }
155    }
156   
157    if { [ lsearch -exact [ image names ] folder-closed ] == -1 } {
158      image create photo folder-closed -data {
159        R0lGODlhDwANANIAAAAAAISEhMbGxv//AP////8AAAAAAAAAACH5BAkZAAUA
160        LAAAAAAPAA0AAAMzWBXM+jCIMUWAT9JtmwtEKI5hAIBcOplgpVIs8bqxa8On
161        fNP5zsWzDctD9AAKgKRyuUwAAAA7
162      }
163    }
164
165    if { [ lsearch -exact [ image names ] actcross16 ] == -1 } {
166      image create photo actcross16 -data {
167        R0lGODlhEAAQAIIAAASC/PwCBMQCBEQCBIQCBAAAAAAAAAAAACH5BAEAAAAA
168        LAAAAAAQABAAAAMuCLrc/hCGFyYLQjQsquLDQ2ScEEJjZkYfyQKlJa2j7AQn
169        MM7NfucLze1FLD78CQAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJz
170        aW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVz
171        ZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7
172      }
173    }
174
175    array set ButtonImageConf {
176      ""       ""
177      "mac"    { mac-collapse open mac-expand    !open }
178      "folder" { folder-open  open folder-closed !open }
179    }
180  }
181
182  method DoubleButton1 {w x y} {
183
184    set id [$w identify $x $y]
185    if {$id eq ""} {
186      return
187    }
188    if {[lindex $id 0] eq "item"} {
189      #lassign $id where item arg1 arg2
190      foreach  {where item arg1 arg2} $id break
191     
192      if {[llength [$w item descendants $item]] == 0} {
193        $self notify generate <<ItemSelected>> [list T $w c $item]
194      } else {
195        $w item toggle $item
196      }
197     
198    } else {
199      TreeCtrl::DoubleButton1 $w $x $y
200    }
201  }
202
203  method KeyPressReturn {w} {
204
205    if {[llength [$w item descendants active]] == 0} {
206      $self notify generate <<ItemSelected>> [list T $w c active]
207    } else {
208      $w item toggle active
209    }
210  }
211 
212  method Button3 {w x y rootX rootY} {
213
214    set cmenu [$self cget -contextmenu]
215    if {$cmenu eq ""} {
216      return
217    }
218    set id [$w identify $x $y]
219
220    #if {$id eq ""} {
221    #  return
222    #}
223    if {[lindex $id 0] == "item"} {
224      foreach {where item arg1 arg2} $id break
225     
226      if {[$w selection includes $item]==0} {
227        $w selection clear
228        $w selection add $item
229      }
230      $w activate $item
231    }
232    tk_popup $cmenu $rootX $rootY
233  }
234 
235  method KeyPressEscape {} {
236
237    $self notify generate <<Escape>>
238  }
239 
240  method SortbyColumn {t column} {
241
242        #puts "SortbyColumn: column=$column, tree=$t"
243        if {[$t column compare $column == $sortedColumn]} {
244          if {[$t column cget $sortedColumn -arrow] eq "up"} {
245                set order -decreasing
246                set arrow "down"
247          } else {
248                set order -increasing
249                set arrow "up"
250          }
251        } else {
252          if {[$t column cget $sortedColumn -arrow] eq "down"} {
253                set order -decreasing
254                set arrow "down"
255          } else {
256                set order -increasing
257                set arrow "up"
258          }
259          $t column configure $sortedColumn -arrow none
260          set sortedColumn $column
261        }
262        $t column configure $column -arrow $arrow
263       
264        $t item sort root $order -column $column -dictionary
265  }
266
267  constructor { args } {
268    # frame para el filtro de nodos
269    frame $win.frameFilter
270    label $win.frameFilter.l -text "[ msgcat::mc Search ]:"
271    menubutton $win.frameFilter.b -image mac-collapse \
272        -menu $win.frameFilter.b.m
273    menu $win.frameFilter.b.m \
274        -postcommand [ mymethod _postFilterMenu $win.frameFilter.b.m ] \
275        -tearoff no
276    frame $win.frameFilter.fentry -relief sunken -bd 1 -highlightthickness 1
277    set widgets(filter,entry) \
278        [ entry $win.frameFilter.fentry.e \
279              -bd 0 -highlightthickness 0 \
280              -textvar [ myvar textFilter ] ]
281    set widgets(filter,bcancel) \
282        [ button $win.frameFilter.fentry.b \
283              -bd 0 -highlightthickness 0 \
284              -image actcross16 \
285              -command [ mymethod _cancelFilter ] ]
286    grid $widgets(filter,entry) -row 0 -column 0 -sticky snew
287    grid $widgets(filter,bcancel) -row 0 -column 1 -sticky ew
288    grid rowconfigure $win.frameFilter.fentry 0 -weight 1
289    grid columnconfigure $win.frameFilter.fentry 0 -weight 1
290    grid remove $widgets(filter,bcancel)
291   
292    bind $widgets(filter,entry) <Key-Return> [ mymethod _applyFilter ]
293    grid $win.frameFilter.l -row 0 -column 1 -sticky "e"
294    grid $win.frameFilter.b -row 0 -column 2 -sticky "e"
295    grid $win.frameFilter.fentry -row 0 -column 3 -sticky "ew"
296    grid columnconfigure $win.frameFilter 0 -weight 1
297    grid columnconfigure $win.frameFilter 3 -weight 1
298    grid $win.frameFilter -row 0 -column 0 -sticky "snew"
299
300    trace add variable [ myvar textFilter ] write [ mymethod _onChangeFilter ]
301
302    # frame para tree widget
303    frame $win.frameTree
304    grid $win.frameTree -row 1 -column 0 -sticky "snew"
305    grid rowconfigure $win.frameTree 0 -weight 1
306    grid columnconfigure $win.frameTree 0 -weight 1
307   
308    install tree as treectrl $win.frameTree.t \
309        -highlightthickness 0 -borderwidth 0 \
310        -xscrollincrement 20 -showheader 1 -indent 19 \
311        -selectmode extended -showroot no \
312        -showrootbutton no -showbuttons yes -showlines yes \
313        -scrollmargin 16 -xscrolldelay "500 50" -yscrolldelay "500 50"
314
315
316    $tree notify install <<ItemSelected>>
317    $tree notify install <<Escape>>
318
319    $tree notify install <Header-invoke>
320
321    $tree notify install <Edit-begin>
322    $tree notify install <Edit-end>
323    $tree notify install <Edit-accept>
324   
325    $tree notify bind $tree <Edit-begin> \
326        [ mymethod EditCallback begin %I %C %E %t ]
327    $tree notify bind $tree <Edit-end> \
328        [ mymethod EditCallback end %I %C %E %t ]
329    $tree notify bind $tree <Edit-accept>  \
330        [ mymethod EditCallback accept %I %C %E %t ]
331   
332    bind $tree <ButtonPress-1> [ mymethod OnButtonPress1 %x %y ]
333    bind $tree <Control-ButtonPress-1> { }
334    bind $tree <Shift-ButtonPress-1> { }
335
336    set height [font metrics [$tree cget -font] -linespace]
337    if {$height < 18} {
338      set height 18
339    }
340    $tree configure -itemheight $height
341
342    # create the elements & styles
343
344    set elements(image) [ $tree element create eIMG image ]
345    set elements(text) [ $tree element create eTXT text \
346                           -fill [list $wtree::SystemHighlightText \
347                                      {selected focus}] ]
348    set elements(check) [ $tree element create eCHK window ]
349   
350    set elements(rect) [ $tree element create eRECT rect \
351                             -showfocus yes -open ew \
352                             -fill [ list \
353                                         $wtree::SystemHighlight \
354                                         {selected focus} \
355                                         gray {selected !focus} ] ]
356
357
358    # vertical scrollbar
359    if { [ string compare $::tcl_version "8.5" ] >= 0 } {
360      set wscroll ttk::scrollbar
361    } else {
362      set wscroll scrollbar
363    }
364    install vscrollbar as $wscroll $win.frameTree.sv \
365        -orient vertical -command [list $win.frameTree.t yview]
366
367    # horizontal scrollbar
368    install hscrollbar as $wscroll $win.frameTree.sh \
369        -orient horizontal -command [list $win.frameTree.t xview]
370
371    grid $tree       -row 0 -column 0 -sticky nsew
372    grid $vscrollbar -row 0 -column 1 -sticky ns
373    grid $hscrollbar -row 1 -column 0 -sticky ew
374    grid columnconfigure $win 0 -weight 1
375    grid rowconfigure    $win 1 -weight 1
376
377    focus $tree
378   
379    $self _configure_bindings
380    $self _conf-columns -columns $options(-columns)
381    $self _conf-contextmenu -contextmenu $options(-contextmenu)
382    $self configurelist $args
383    if { !$options(-filter) } {
384      grid remove $win.frameFilter
385    }
386    #return $win
387  }
388 
389  method getItemText { item } {
390    set itemText ""
391    # buscar las columnas que tiene elemento eTXT
392    foreach c [ $tree column list ] {
393      if { !$columnsToFilter($c) } {
394        continue
395      }
396      # extraigo el style asociado a la columna
397      set columnStyle [ $tree column cget $c -itemstyle ]
398      # extraigo los elementos del style
399      set styleElements [ $tree style elements $columnStyle ]
400      # busco si eTXT es uno de esos elementos
401      if { [ lsearch $styleElements "eTXT" ] != -1 } {
402        # el root no tiene styles
403        catch {
404          append itemText [ $tree item element cget $item $c eTXT -text ] " "
405        }
406      }
407    }
408    return $itemText
409  }
410
411  method getColumnLabels { args } {
412    array set opts {
413      -onlyvisible yes
414      -hastext no
415    }
416    array set opts $args
417    set labels [ list ]
418    foreach c [ $tree column list ] {
419      if { $opts(-hastext) } {
420        # extraigo el style asociado a la columna
421        set columnStyle [ $tree column cget $c -itemstyle ]
422        # extraigo los elementos del style
423        set styleElements [ $tree style elements $columnStyle ]
424        # busco si eTXT es uno de esos elementos
425        if { [ lsearch $styleElements "eTXT" ] == -1 } {
426          # no tiene elemento Text
427          continue
428        }
429      }
430      if { $opts(-onlyvisible) && ![ $tree column cget $c -visible ] } {
431        # no es visible
432        continue
433      }
434      lappend labels [ list -idx $c -text [ $tree column cget $c -text ] ]
435    }
436    return $labels
437  }
438
439  method _postFilterMenu { m } {
440    $m delete 0 end
441    foreach c [ $self getColumnLabels ] {
442      array set cinfo $c
443      $m add checkbutton -label $cinfo(-text) -onvalue 1 -offvalue 0 \
444          -variable [ myvar columnsToFilter($cinfo(-idx)) ]
445    }
446  }
447
448  method _setWaitCursor { } {
449    $win configure -cursor watch
450    $widgets(filter,entry) configure -cursor watch
451    update
452  }
453
454  method _setNormalCursor { } {
455    $win configure -cursor {}
456    $widgets(filter,entry) configure -cursor {}
457    update
458  }
459
460  method _cancelFilter { } {
461    set textFilter ""
462    grid remove $widgets(filter,bcancel)
463  }
464
465  method filterItems { text } {
466    #puts "filterItems $text"
467    $self _setWaitCursor
468    set negativeWords [ list ]
469    set positiveWords [ list ]
470    set negating 0
471    set wordList [regexp -inline -all -- {\S+} $text]
472    foreach word $wordList {
473      if { $negating } {
474        lappend negative $word
475        set negating 0
476      } elseif { [ string index $word 0 ] eq "-" } {
477        # se pide negar la palabra
478        set _word [ string range $word 1 end ]
479        if { $_word eq "" } {
480          set negating 1
481        } else {
482          lappend negativeWords $_word
483        }
484      } else {
485        lappend positiveWords $word
486      }
487    }
488    # regexp {^(?!(.*(foo|bar).*))} atttcokebar
489    if { [ llength $negativeWords ] } {
490      set negativeRegExp "^(?!(.*([ join $negativeWords | ]).*))"
491    } else {
492      set negativeRegExp ""
493    }
494    set breakFilter 0
495    set numItemsFiltered 0
496    set listFilterOn [ list ]
497    set listFilterOff [ list ]
498    $self _filterNodeSet [ $tree item children root ] \
499        $positiveWords $negativeRegExp
500    $self _setNormalCursor
501  }
502 
503  method _filterNodesMatching { } {
504    if { [ llength $listFilterOff ] } {
505      $tree item configure [ list list $listFilterOff ] -visible 0
506      set listFilterOff [ list ]
507    }
508    if { [ llength $listFilterOn ] } {
509      $tree item configure [ list list $listFilterOn ] -visible 1
510      if { !$options(-table) } {
511        foreach nid $listFilterOn {
512          $tree item configure \
513              [ list list [ $tree item ancestors $nid ] ] -visible 1
514        }
515      }
516      set listFilterOn [ list ]
517    }
518  }
519
520  method _filterNodeSet { nodes positiveWords negativeRegExp } {
521    #puts "filterNodeSet '$nodes' '$positiveWords'"
522    # recorro cada uno de los nodos
523    foreach n $nodes {
524      # filtro el nodo
525     
526      #esto es para el filtrado automatico incremental
527      if { $breakFilter } {
528        return 0
529      }
530
531      $self _filterNode $n $positiveWords $negativeRegExp
532      # desciendo a los hijos
533      $self _filterNodeSet [ $tree item children $n ] \
534          $positiveWords $negativeRegExp
535     
536      if { 0 } {
537      if { [ $self _filterNode $n $positiveWords $negativeRegExp ] } {
538        # si el resultado es visible desciendo y filtro a los hijos
539        $self _filterNodeSet [ $tree item children $n ] \
540            $positiveWords $negativeRegExp
541      }
542      }
543
544      # esto es para el filtrado automatico incremental
545      incr numItemsFiltered
546      if { !$breakFilter && !( $numItemsFiltered % 1000 ) } {
547        # refresco la cola de eventos
548        $self _filterNodesMatching
549        update
550      }
551    }
552    $self _filterNodesMatching
553    return 1
554  }
555
556  method _filterNode { node positiveWords negativeRegExp } {
557    #puts "filterNode '$node' '$positiveWords' '$negativeRegExp'"
558    set itemText [ $self getItemText $node ]
559    #puts "itemText $itemText"
560    # hago match, luego hago algo mas sofisticado con regexp
561    # set visible [ string match "*${text}*" $itemText ]
562    if { [ string length $negativeRegExp ] &&
563         ![ regexp -nocase $negativeRegExp $itemText ] } {
564      # itemText contiene alguna de las palabra prohibidas
565      #puts "itemText contiene alguna de las palabra prohibidas"
566      #$tree item configure $node -visible 0
567      lappend listFilterOff $node
568      return 0
569    }
570    foreach word $positiveWords {
571      if { ![ string match -nocase "*${word}*" $itemText ] } {
572        # itemText no contiene una de las palabras deseadas
573        #puts "itemText no contiene una de las palabras deseadas: $word"
574        #puts "string match \"*${word}*\" $itemText"
575        #$tree item configure $node -visible 0
576        lappend listFilterOff $node
577        return 0
578      }
579    }
580    # finalmente todas las palabras deseadas y niguna de las
581    # prohibidas estan.
582    #$tree item configure $node -visible 1
583    lappend listFilterOn $node
584    return 1
585  }
586
587  method _applyFilter { } {
588    set columnFound -1
589    foreach c [ array name columnsToFilter ] {
590      if { $columnsToFilter($c) } {
591        set columnFound $c
592        break
593      }
594    }
595    if { $columnFound == -1 } {
596      return
597    }
598    if { $textFilter eq "" } {
599      $tree item configure all -visible 1
600    } else {
601      $self filterItems $textFilter
602    }
603  }
604
605  method _onChangeFilter { args } {
606    if { $textFilter eq "" } {
607      grid remove $widgets(filter,bcancel)
608      $tree item configure all -visible 1
609    } else {
610      #puts "filtering on $textFilter"
611      grid $widgets(filter,bcancel)
612      update
613      after cancel $idWaitFilter
614      set breakFilter 1
615      set idWaitFilter [ after 500 $self _scheduleFilter ]
616    }
617  }
618 
619  method _scheduleFilter { } {
620    after cancel $idIdleFilter
621    set idIdleFilter [ after idle $self _applyFilter ]
622  }
623
624  method _configure_bindings { } {
625   
626    bind $tree <Double-ButtonPress-1> "[mymethod DoubleButton1 %W %x %y] ; break"
627    bind $tree <Return> "[mymethod KeyPressReturn %W] ; break"
628
629    bind $tree <ButtonPress-3> [ mymethod Button3 %W %x %y %X %Y]
630
631    bind $tree <Escape> "[mymethod KeyPressEscape] ; break"
632   
633    $tree notify bind $tree <Header-invoke> [mymethod SortbyColumn %W %C]
634
635    $tree notify bind $vscrollbar <Scroll-y> { %W set %l %u }
636    bind $vscrollbar <ButtonPress-1> [list focus $tree]
637   
638    $tree notify bind $hscrollbar <Scroll-x> { %W set %l %u }
639    bind $hscrollbar <ButtonPress-1> [list focus $tree]
640   
641    ::autoscroll::autoscroll $vscrollbar
642    ::autoscroll::autoscroll $hscrollbar
643  }
644
645  method _conf-table { _ yesno } {
646    if { $yesno } {
647      set options(-table) 1
648      $tree configure -showbuttons 0 -showlines 0
649    } else {
650      set options(-table) 0
651      $tree configure -showbuttons 1 -showlines 1
652    }
653  }
654
655  method _conf-buttonstyle { _ bs } {
656    set valid_bstyles [ array names wtree::ButtonImageConf ]
657    if { [ lsearch $valid_bstyles $bs ] == -1 } {
658      error "invalid button style $bs should be one of $valid_bstyles"
659    } else {
660      set options(-buttonstyle) $bs
661      $tree configure -buttonimage $wtree::ButtonImageConf($bs)
662    }
663  }
664
665  method _conf-contextmenu { _ cmenu } {
666    set options(-contextmenu) $cmenu
667  }
668
669  method _conf-filter { _ value } {
670    if { [ string is boolean $value ] } {
671      if { ( $options(-filter)  && $value ) ||
672           ( !$options(-filter) && !$value ) } {
673        return
674      }
675      set options(-filter) $value
676      if { $value } {
677        grid $win.frameFilter
678      } else {
679        grid remove $win.frameFilter
680      }
681      set textFilter ""
682    } else {
683      error "invalid boolean value $value"
684    }
685  }
686
687  method _conf-columnfilter { _ value } {
688    # hago el chequeo en el postcommand del menu que despliegua las
689    # opciones y tambien a la hora de filtrar
690    set options(-columnfilter) $value
691        foreach {idx v} $value {
692          set columnsToFilter($idx) $v
693    }
694  }
695
696  #
697  # columnsSpec es una lista de "columnas" y una columna puede ser
698  #
699  #  - un unico elemento con valor: image, text o check
700  #
701  #  - una lista de elementos, donde cada elemento puede estar dado
702  #    por su tipo.
703  #
704  #    { image text }
705  #
706  #    en un futuro se le puede adjuntar propiedades de layout.
707  #
708  #    cada columna crea un stilo y el layout esa definido por el
709  #    orden en que se describen los elementos de la columna.
710  #
711  method _conf-columns { _ columnsSpec } {
712    if { $columnsSpec eq "" } {
713      set columnsSpec [ list { text -tags C0 -label "Column 0" -editable 0 } ]
714    }
715    set options(-columns) $columnsSpec
716    # elimino columnas
717    $tree column delete all
718    # elimino estilos
719    eval $tree style delete [ $tree style names ]
720
721    # limpio la informacion interna de las columnas
722    array unset column_info
723    array unset style_info
724    # crear las columnas y estilos
725    set idx 0
726    foreach col_spec $columnsSpec {
727      set col_elements [ lindex $col_spec 0 ]
728      # opciones por omision.
729      array set opts [ list -tags C${idx} -label "Column $idx" -image "" \
730                           -editable 0 ]
731      # opciones dadas en la llamada.
732      array set opts [ lrange $col_spec 1 end ]
733      set colID [ $tree column create \
734                      -text [ msgcat::mc $opts(-label) ] \
735                      -image $opts(-image) \
736                      -itembackground "\#e0e8f0 {}" \
737                      -tags $opts(-tags) ]
738      set column_info($idx,ID) $colID
739      set column_info(MAPIDX,$colID) $idx
740      set column_info($idx,elements) $col_elements
741      set column_info($idx,-editable) $opts(-editable)
742      # creamos el estilo para esta columna
743      set s [ $tree style create style$colID ]
744      set column_info($idx,style) $s
745      set eList [ list ]
746      # selecciono los id's de los elementos de esta columna
747      set eIMG ""
748      foreach e $col_elements {
749        lappend eList $elements($e)
750        if { $e eq "image" } {
751          set eIMG $elements($e)
752        }
753      }
754      # asocio los elementos al style
755      $tree style elements $s [ eval list eRECT $eList ]
756
757      # defino el layout de los elementos
758      $tree style layout   $s eRECT -union $eList -iexpand nswe -ipadx 2
759      if { $eIMG ne "" } {
760        $tree style layout   $s $eIMG -iexpand ns -padx 2
761      }
762      # asocio el style a la columna
763      $tree column configure $colID -itemstyle $s
764      incr idx
765    }
766    # Specifies a column description that determines which column
767    # displays the expand/collapse buttons and connecting lines between
768    # items. The default is unspecified.
769    $tree configure -treecolumn $column_info(0,ID)
770    # extraigo las columnas filtrables
771    set first ""
772    set hasCheck 0
773    foreach c [ $self getColumnLabels -onlyvisible yes -hastext yes ] {
774      array set cinfo $c
775      if { $first eq "" } {
776        set first $cinfo(-idx)
777      }
778      if { [ info exists columnsToFilter($cinfo(-idx)) ] } {
779        set _columnsToFilter($cinfo(-idx)) $columnsToFilter($cinfo(-idx))
780      } else {
781        set _columnsToFilter($cinfo(-idx)) 0
782      }
783      if { $_columnsToFilter($cinfo(-idx)) } {
784        set hasCheck 1
785      }
786    }
787    if { !$hasCheck } {
788      set _columnsToFilter($first) 1
789    }
790    array unset columnsToFilter
791    array set columnsToFilter [ array get _columnsToFilter ]
792  }
793
794  method itemcolumn { item col args } {
795    set colid [ $tree column id $col ]
796    if { $colid eq "" } {
797      puts "$col does not reference a valid column"
798      return
799    }
800    set ret {}
801    foreach elemdata $args {
802      set v ""
803      foreach { e v } $elemdata break
804      if { $v eq "" } {
805        array set def_prop {
806          text -text
807          image -image
808        }
809        lappend ret [ list $e [ $tree item element cget $item $colid $elements($e) $def_prop($e) ] ]
810      } else {
811        set e_conf [ $self _build_element_config $e $v ]
812        eval $tree item element configure $item $colid $e_conf
813      }
814    }
815    return $ret
816  }
817
818  method insert { data args } {
819    array set insopt {
820      -at end
821      -relative root
822      -open 0
823      -button 1
824      -tags ""
825    }
826    array set insopt $args
827    # creamos el item, -button yes debe depender si el widget no es
828    # tipo tabla
829    set item [ $tree item create \
830                   -button $insopt(-button) \
831                   -tags insopt(-tags) ]
832    set idx 0
833    set idx_last  [ expr [ llength $options(-columns) ] - 1 ]
834    # 'data' es una lista con informacion para cada columna. Lo que
835    # venga de mas en data no lo considero.
836    foreach col_data [ lrange $data 0 $idx_last ] {
837      # los elementos de esta columna
838      set col_elements $column_info($idx,elements)
839      # col_data debe ser una lista de la misma cantidad de elementos
840      set e_count [ llength $col_elements ]
841      # esta lista es para usar la sintaxis de configurar + de un
842      # elemento al estilo
843      #
844      # $tree item element configure $item $columnID($idx) \
845      #      $elements(IMG) -image $opts(-image) + \
846      #      $elements(TXT) -text  $opts(-text)
847      #
848      set elements_config [ list ]
849      for { set i 0 } { $i < $e_count } { incr i } {
850        set e_data [ lindex $col_data $i ]
851        set e_conf [ $self _build_element_config \
852                         [ lindex $col_elements $i ] $e_data ]
853        eval $tree item element configure $item $column_info($idx,ID) $e_conf
854      }
855      incr idx
856    }
857    # insertamos el item en el arbol
858    $tree item collapse $item
859    switch $insopt(-at) {
860      end - child {
861        $tree item lastchild $insopt(-relative) $item
862      }
863      next {
864        $tree item nextsibling $insopt(-relative) $item
865      }
866      prev {
867        $tree item prevsibling $insopt(-relative) $item
868      }
869      default {
870        error "invalid index, should be: end (child), prev or next"
871      }
872    }
873    return $item
874  }
875
876  method _build_element_config { etype data } {
877    array set def_prop {
878      text -text
879      image -image
880    }
881    if { [ catch { llength $data } ] } {
882      set data [ list $data ]
883    }
884    if { [ llength $data ] } {
885      if { [ llength $data ] == 1 } {
886        return [ list $elements($etype) $def_prop($etype) [ string trim [ lindex $data 0 ] ] ]
887      } elseif { [ string index [ lindex $data 0 ] 0 ] ne "-" } {
888        return [ list $elements($etype) $def_prop($etype) [ string trim $data ] ]
889      } else {
890        return [ linsert $data 0 $elements($etype) ]
891      }
892    } else {
893      return [ list $elements($etype) $def_prop($etype) "" ]
894    }
895  }
896
897  method EditCallback { callback item column elem t } {
898    if { $callback eq "accept" } {
899      $tree item element configure $item $column $elem -text $t
900    }
901  }
902
903  method OnButtonPress1 { x y } {
904   
905    set treeInfo [ $tree identify $x $y ]
906    if { $treeInfo eq "" } {
907      $tree selection clear
908      return
909    }
910   
911    if { [ llength $treeInfo ] != 6 } {
912      return
913    }
914   
915    foreach { item I column C elem E } $treeInfo { }
916   
917    #puts "OnButtonPress1: $treeInfo"
918    if { $item == "item" && \
919             $column == "column" && \
920             $elem == "elem" && \
921             [ $tree selection includes $I ] } {
922
923      #puts "$itemNum = [$tree selection includes $itemNum ]"
924
925      set idx_info $column_info(MAPIDX,$C)
926
927      if { $column_info($idx_info,-editable) && $E eq "eTXT"} {
928        set exists [winfo exists $tree.entry]
929        ::TreeCtrl::EntryOpen $tree $I $C $E
930        if {!$exists} {
931          $tree.entry configure -borderwidth 1 -justify center  \
932              -background white -relief sunken
933          update idletask
934        }
935        $tree.entry selection clear
936        scan [$tree item bbox $I $C $E] "%d %d %d %d" x1 y1 x2 y2
937        set left $x1
938        set right $x2
939        place $tree.entry -y $y1 -x $left -width [expr {$right - $left + 4}]
940        $tree.entry icursor [$tree.entry index @[expr {$x - ($x1 + 1)}]]
941        return -code break
942
943        ::TreeCtrl::ButtonPress1 $tree $x $y
944        update
945        ::TreeCtrl::EntryOpen $tree $itemNum $columnNum $elemName
946        return -code break
947      }
948    }
949  }
950 
951  proc test_GetTextContents { T item } {
952    set textDump ""
953    # buscar las columnas que tiene elemento eTXT
954    foreach c [ $T column list ] {
955      # extraigo el style asociado al item
956      set style [ $T column cget $c -itemstyle ]
957      # extraigo los elementos del style
958      set elements [ $T style elements $style ]
959      # busco si eTXT es uno de esos elementos
960      if { [ lsearch $elements "eTXT" ] != -1 } {
961        append textDump [ $T item element cget $item $c eTXT -text ] " "
962      }
963    }
964    return $textDump
965  }
966
967  proc test_ListenSearch { t args } {
968    if { $::wtreeSearch eq "" } {
969      $t item configure all -visible 1
970    } else {
971      #puts "filtering on $::wtreeSearch"
972      #$t filterNodeSet [ $t item children root ] $::wtreeSearch
973      catch {
974        $t filterItems $::wtreeSearch
975      } msg
976      #puts "msg = $msg"
977    }
978  }
979
980  proc test_01 { w { istable 0 } } {
981    destroy $w
982    toplevel $w
983    if { 0 } {
984      frame $w.fsearch
985      label $w.fsearch.l -text "Search:"
986      entry $w.fsearch.e -textvar ::wtreeSearch
987      grid $w.fsearch.l -row 0 -column 1 -sticky "e"
988      grid $w.fsearch.e -row 0 -column 2 -sticky "ew"
989      grid columnconfigure $w.fsearch 0 -weight 1
990      grid $w.fsearch -row 0 -column 0 -sticky "snew"
991    }
992   
993    set T [ wtree $w.t -table $istable -filter yes -buttonstyle mac \
994                -columns [ list \
995                               { {image text} -tags ID   -label Identifier } \
996                               { text -tags DESC -label Description } ] ]
997   
998    $T notify bind $T <Expand-before> {
999      #puts "before openning %I"
1000    }
1001    $T notify bind $T <Collapse-after> {
1002      #puts "after closing %I"
1003    }
1004    $T notify bind $T <ActiveItem> {
1005      #puts "now active item is %c the previous was %p"
1006    }
1007    grid $T -row 1 -column 0 -sticky "snew"
1008    grid rowconfigure $w 1 -weight 1
1009    grid columnconfigure $w 0 -weight 1
1010
1011    if { 0 } {
1012      trace remove variable ::wtreeSearch write "::wtree::test_ListenSearch $T"
1013      trace add    variable ::wtreeSearch write "::wtree::test_ListenSearch $T"
1014    }
1015   
1016    set bugValue {
1017Serie AlgGetData(
1018 "Lla_MetCon.Atendi.Ser_TNuXXX_GHLAll.Ind.ALL_TLlTLl.XXX_RotXXX.XXX.XXX.XXX_EspEsp.XXX_SegSeg.XXX_PerMHo.XXX_FecDia",
1019 AlgProj1004)
1020}
1021    set id [ $T insert [list  [list folder-open "node bug"] [ list $bugValue ] ] ]
1022    set id [ $T insert [list [list folder-open "node 1"] [list "Desc node\n 1"]] ]
1023    set id [ $T insert { { folder-closed "node 2" } { "Desc node 2" } } \
1024                 -at end -relative [ expr { $istable ? "root" : $id } ] ]
1025    return .t01.t
1026  }
1027
1028  proc TestSearch { w } {
1029    destroy $w
1030    toplevel $w
1031
1032    set T [ wtree $w.t -table 1 -filter yes -buttonstyle mac \
1033                -columns [ list \
1034                               { {image text} -tags ID   -label Identifier } \
1035                               { text -tags DESC -label Description -editable yes} ] ]
1036    grid $T -row 1 -column 0 -sticky "snew"
1037    grid rowconfigure $w 1 -weight 1
1038    grid columnconfigure $w 0 -weight 1
1039   
1040    for { set r 0 } { $r < 100 } { incr r } {
1041      $T insert [list  [list folder-open "node $r"] [ list "Description for node $r" ] ]
1042    }
1043    return $T
1044  }
1045}
1046
1047msgcat::mcload [ file join [ file dir [ info script ] ] msgs ]
1048
1049package provide wtree 1.0
Note: See TracBrowser for help on using the repository browser.