source: branches/blt4/gui/scripts/filelistentry.tcl @ 1970

Last change on this file since 1970 was 1969, checked in by gah, 14 years ago
File size: 13.8 KB
Line 
1
2# ----------------------------------------------------------------------
3#  COMPONENT: FileListEntry - widget for entering a choice of strings
4#
5#  This widget represents a <choice> entry on a control panel.
6#  It is used to choose one of several mutually-exclusive strings.
7# ======================================================================
8#  AUTHOR:  Michael McLennan, Purdue University
9#  Copyright (c) 2004-2005  Purdue Research Foundation
10#
11#  See the file "license.terms" for information on usage and
12#  redistribution of this file, and for a DISCLAIMER OF ALL WARRANTIES.
13# ======================================================================
14package require Itk
15
16itk::usual TreeView {
17    keep -foreground -cursor
18}
19itk::usual Scrollset {
20}
21
22itcl::class Rappture::FileListEntry {
23    inherit itk::Widget
24
25    itk_option define -state state State "normal"
26   
27    private variable _rebuildPending 0
28    private variable _tree ""
29    private variable _owner ""    ;# thing managing this control
30    private variable _path ""     ;# path in XML to this number
31    private variable _icon ""
32
33    constructor {owner path args} {
34        # defined below
35    }
36    destructor {
37        # defined below
38    }
39    public method value {args}
40
41    public method label {}
42    public method tooltip {}
43
44    protected method _rebuild {}
45    protected method _newValue { args }
46    protected method _tooltip {}
47    protected method _whenidle {}
48}
49
50itk::usual FileListEntry {
51    keep -cursor -font
52    keep -foreground -background
53    keep -textforeground -textbackground
54    keep -selectbackground -selectforeground -selectborderwidth
55}
56
57# ----------------------------------------------------------------------
58# CONSTRUCTOR
59# ----------------------------------------------------------------------
60itcl::body Rappture::FileListEntry::constructor {owner path args} {
61    if {[catch {$owner isa Rappture::ControlOwner} valid] != 0 || !$valid} {
62        error "bad object \"$owner\": should be Rappture::ControlOwner"
63    }
64    set _owner $owner
65    set _path $path
66    set _tree [blt::tree create]
67
68    #
69    # Create the widget and configure it properly based on other
70    # hints in the XML.
71    #
72    set label [$_owner xml get $_path.about.label]
73    set desc [$_owner xml get $_path.about.description]
74    itk_component add scrollset {
75        blt::scrollset $itk_interior.ss \
76            -xscrollbar $itk_interior.ss.xs \
77            -yscrollbar $itk_interior.ss.ys \
78            -window $itk_interior.ss.tree \
79            -height 100
80    }
81    blt::tk::scrollbar $itk_interior.ss.xs
82    blt::tk::scrollbar $itk_interior.ss.ys
83    itk_component add tree {
84        blt::treeview $itk_component(scrollset).tree -linewidth 0 \
85            -alternatebackground "" \
86            -bg white -selectmode multiple \
87            -highlightthickness 0 \
88            -tree $_tree \
89            -flat yes -separator /  \
90            -selectcommand [itcl::code $this _newValue]
91    }
92    $itk_component(tree) column configure "treeView" -justify left \
93        -weight 1.0 -text "" -pad 0 -borderwidth 0 -edit no
94    pack $itk_component(scrollset) -fill both -expand yes
95
96    blt::table $itk_interior \
97        0,0 $itk_component(scrollset) -fill both 
98    bind $itk_component(tree) <<Value>> [itcl::code $this _newValue]
99
100    # Standard ButtonPress-1
101    $itk_component(tree) bind Entry <ButtonPress-1> {   
102        Rappture::FileListEntry::SetSelectionAnchor %W current yes set
103        set blt::TreeView::_private(scroll) 1
104    }
105    # Standard B1-Motion
106    $itk_component(tree) bind Entry <B1-Motion> {
107        set blt::TreeView::_private(x) %x
108        set blt::TreeView::_private(y) %y
109        set index [%W nearest %x %y]
110        Rappture::FileListEntry::SetSelectionAnchor %W $index yes set
111    }
112    # Standard ButtonRelease-1
113    $itk_component(tree) button bind all <ButtonRelease-1> {
114        set index [%W nearest %x %y blt::TreeView::_private(who)]
115        if { [%W index current] == $index &&
116             $blt::TreeView::_private(who) == "button" } {
117            %W see -anchor nw current
118            %W toggle current
119        }
120    }
121    # Shift-ButtonPress-1
122    $itk_component(tree) bind Entry <Shift-ButtonPress-1> {     
123        Rappture::FileListEntry::SetSelectionAnchor %W current yes set
124        set blt::TreeView::_private(scroll) 1
125    }
126    # Shift-B1-Motion
127    $itk_component(tree) bind Entry <Shift-B1-Motion> {
128        set blt::TreeView::_private(x) %x
129        set blt::TreeView::_private(y) %y
130        set index [%W nearest %x %y]
131        if { [%W cget -selectmode] == "multiple" } {
132            %W selection mark $index
133        } else {
134            Rappture::FileListEntry::SetSelectionAnchor %W $index yes set
135        }
136    }
137    # Shift-ButtonRelease-1
138    $itk_component(tree) bind Entry <Shift-ButtonRelease-1> {
139        if { [%W cget -selectmode] == "multiple" } {
140            %W selection anchor current
141        }
142        after cancel $blt::TreeView::_private(afterId)
143        set blt::TreeView::_private(afterId) -1
144        set blt::TreeView::_private(scroll) 0
145    }
146    $itk_component(tree) bind Entry <Control-ButtonPress-1> {   
147        Rappture::FileListEntry::SetSelectionAnchor %W current no toggle
148        set blt::TreeView::_private(scroll) 1
149    }
150    $itk_component(tree) bind Entry <Control-B1-Motion> {
151        set blt::TreeView::_private(x) %x
152        set blt::TreeView::_private(y) %y
153        set index [%W nearest %x %y]
154        if { [%W cget -selectmode] == "multiple" } {
155            %W selection mark $index
156        } else {
157            Rappture::FileListEntry::SetSelectionAnchor %W $index no toggle
158        }
159    }
160    $itk_component(tree) bind Entry <Control-ButtonRelease-1> {
161        if { [%W cget -selectmode] == "multiple" } {
162            %W selection anchor current
163        }
164        after cancel $blt::TreeView::_private(afterId)
165        set blt::TreeView::_private(afterId) -1
166        set blt::TreeView::_private(scroll) 0
167    }
168    # First time, parse the <pattern> elements to generate notify callbacks
169    # for each template found.
170    foreach cname [$_owner xml children -type pattern $_path] {
171        set glob [string trim [$_owner xml get $_path.$cname]]
172        # Successively replace each template with its value.
173        while { [regexp -indices {@@[^@]*@@} $glob range] } {
174            foreach {first last} $range break
175            set i1 [expr $first + 2]
176            set i2 [expr $last  - 2]
177            set cpath [string range $glob $i1 $i2]
178            set value [$_owner xml get $cpath.$cname]
179            set glob [string replace $glob $first $last $value]
180            $_owner notify add $this $cpath [itcl::code $this _whenidle]
181        }
182    }
183    $_owner notify sync
184    eval itk_initialize $args
185
186    # if the control has an icon, plug it in
187    set str [$_owner xml get $path.about.icon]
188    if {$str != ""} {
189        set _icon [image create picture -data $str]
190    }
191    _rebuild
192}
193
194# ----------------------------------------------------------------------
195# DESTRUCTOR
196# ----------------------------------------------------------------------
197itcl::body Rappture::FileListEntry::destructor {} {
198    blt::tree destroy $_tree
199    $_owner notify remove $this
200}
201
202# ----------------------------------------------------------------------
203# USAGE: value ?-check? ?<newval>?
204#
205# Clients use this to query/set the value for this widget.  With
206# no args, it returns the current value for the widget.  If the
207# <newval> is specified, it sets the value of the widget and
208# sends a <<Value>> event.  If the -check flag is included, the
209# new value is not actually applied, but just checked for correctness.
210# ----------------------------------------------------------------------
211itcl::body Rappture::FileListEntry::value {args} {
212    set onlycheck 0
213    set i [lsearch -exact $args -check]
214    if {$i >= 0} {
215        set onlycheck 1
216        set args [lreplace $args $i $i]
217    }
218    if {[llength $args] == 1} {
219        if {$onlycheck} {
220            # someday we may add validation...
221            return
222        }
223        foreach id [$itk_component(tree) curselection] {
224            set path [$_tree get $id "path" ""]
225            set path2id($path) $id
226        }
227        set paths [split $newval ,]
228    } elseif {[llength $args] != 0} {
229        error "wrong # args: should be \"value ?-check? ?newval?\""
230    }
231
232    #
233    # Query the value and return.
234    #
235    set list {}
236    foreach id [$itk_component(tree) curselection] {
237        set path [$_tree get $id "path" ""]
238        if { $path != "" } {
239            lappend list $path
240        }
241    }
242    return [join $list ,]
243}
244
245# ----------------------------------------------------------------------
246# USAGE: label
247#
248# Clients use this to query the label associated with this widget.
249# Reaches into the XML and pulls out the appropriate label string.
250# ----------------------------------------------------------------------
251itcl::body Rappture::FileListEntry::label {} {
252    set label [$_owner xml get $_path.about.label]
253    if {"" == $label} {
254        set label "Choice"
255    }
256    return $label
257}
258
259# ----------------------------------------------------------------------
260# USAGE: tooltip
261#
262# Clients use this to query the tooltip associated with this widget.
263# Reaches into the XML and pulls out the appropriate description
264# string.  Returns the string that should be used with the
265# Rappture::Tooltip facility.
266# ----------------------------------------------------------------------
267itcl::body Rappture::FileListEntry::tooltip {} {
268    # query tooltip on-demand based on current choice
269    return "@[itcl::code $this _tooltip]"
270}
271
272# ----------------------------------------------------------------------
273# USAGE: _rebuild
274#
275# Used internally to rebuild the contents of this choice widget
276# whenever something that it depends on changes.  Scans through the
277# information in the XML spec and builds a list of choices for the
278# widget.
279# ----------------------------------------------------------------------
280itcl::body Rappture::FileListEntry::_rebuild {} {
281    set _rebuildPending 0
282
283    #
284    # Plug in the various options for the choice.
285    #
286    set max 10
287    $_owner notify sync
288    set allfiles {}
289    foreach cname [$_owner xml children -type pattern $_path] {
290        set glob [string trim [$_owner xml get $_path.$cname]]
291        # Successively replace each template with its value.
292        while { [regexp -indices {@@[^@]*@@} $glob range] } {
293            foreach {first last} $range break
294            set i1 [expr $first + 2]
295            set i2 [expr $last  - 2]
296            set cpath [string range $glob $i1 $i2]
297            set value [$_owner xml get $cpath.current]
298            if { $value == "" } {
299                set value [$_owner xml get $cpath.default]
300            }
301            set glob [string replace $glob $first $last $value]
302        }
303        # Replace the template with the substituted value.
304        if { [catch {
305            glob -nocomplain -type { r f } $glob
306        } files] == 0 } {
307            set allfiles [concat $allfiles $files]
308        }
309    }
310    set first ""
311    eval $_tree tag add unused [$_tree children root]
312    foreach file $allfiles {
313        set tail [file tail $file]
314        if { $first == "" } {
315            set first $tail
316        }
317        set tail [file root $tail]
318        set id [$_tree index root->"$tail"]
319        if { $id < 0 } {
320            set data [list path $file show 0]
321            set id [$_tree insert root -label $tail -data $data -tag ""]
322        } else {
323            $_tree tag delete unused $id
324        }
325        set len [string length $tail]
326        if {$len > $max} { set max $len }
327    }
328    $itk_component(tree) configure -icons ""
329    $itk_component(tree) entry configure all -icons ""
330    eval $_tree delete [$_tree tag nodes unused]
331    $itk_component(tree) configure -width $max
332    catch {
333        if { ![$itk_component(tree) selection present] } {
334            $itk_component(tree) selection set [$_tree firstchild root]
335        }
336    }
337}
338
339# ----------------------------------------------------------------------
340# USAGE: _newValue
341#
342# Invoked automatically whenever the value in the choice changes.
343# Sends a <<Value>> event to notify clients of the change.
344# ----------------------------------------------------------------------
345itcl::body Rappture::FileListEntry::_newValue { args } {
346    event generate $itk_component(hull) <<Value>>
347}
348
349# ----------------------------------------------------------------------
350# USAGE: _tooltip
351#
352# Returns the tooltip for this widget, given the current choice in
353# the selector.  This is normally called by the Rappture::Tooltip
354# facility whenever it is about to pop up a tooltip for this widget.
355# ----------------------------------------------------------------------
356itcl::body Rappture::FileListEntry::_tooltip {} {
357    set tip [string trim [$_owner xml get $_path.about.description]]
358    # get the description for the current choice, if there is one
359    set path ""
360    set desc ""
361    if {$path == ""} {
362        set desc [$_owner xml get $_path.about.description]
363    }
364    set str ""
365    if {[string length $str] > 0 && [string length $desc] > 0} {
366        append tip "\n\n$str:\n$desc"
367    }
368    return $tip
369}
370
371# ----------------------------------------------------------------------
372# CONFIGURATION OPTION: -state
373# ----------------------------------------------------------------------
374itcl::configbody Rappture::FileListEntry::state {
375    set valid {normal disabled}
376    if {[lsearch -exact $valid $itk_option(-state)] < 0} {
377        error "bad value \"$itk_option(-state)\": should be [join $valid {, }]"
378    }
379    #$itk_component(tree) configure -state $itk_option(-state)
380}
381
382itcl::body Rappture::FileListEntry::_whenidle {} {
383    if { !$_rebuildPending } {
384        after 10 [itcl::code $this _rebuild]
385        set _rebuildPending 1
386    }
387}
388
389proc Rappture::FileListEntry::SetSelectionAnchor { w tagOrId clear how } {
390    set index [$w index $tagOrId]
391    if { $clear } {
392        $w selection clearall
393    }
394    $w see $index
395    $w focus $index
396    $w selection $how $index
397    $w selection anchor $index
398}
Note: See TracBrowser for help on using the repository browser.