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