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

Last change on this file since 1799 was 1729, checked in by gah, 14 years ago
File size: 12.9 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        set files [glob -nocomplain $glob]
305        set allfiles [concat $allfiles $files]
306    }
307    set first ""
308    eval $_tree tag add unused [$_tree children root]
309    foreach file $allfiles {
310        set tail [file tail $file]
311        if { $first == "" } {
312            set first $tail
313        }
314        set tail [file root $tail]
315        set id [$_tree index root->"$tail"]
316        if { $id < 0 } {
317            set data [list path $file show 0]
318            set id [$_tree insert root -label $tail -data $data -tag ""]
319        } else {
320            $_tree tag delete unused $id
321        }
322        set len [string length $tail]
323        if {$len > $max} { set max $len }
324    }
325    $itk_component(tree) configure -icons ""
326    $itk_component(tree) entry configure all -icons ""
327    eval $_tree delete [$_tree tag nodes unused]
328    $itk_component(tree) configure -width $max
329    catch {
330        if { ![$itk_component(tree) selection present] } {
331            $itk_component(tree) selection set [$_tree firstchild root]
332        }
333    }
334}
335
336# ----------------------------------------------------------------------
337# USAGE: _newValue
338#
339# Invoked automatically whenever the value in the choice changes.
340# Sends a <<Value>> event to notify clients of the change.
341# ----------------------------------------------------------------------
342itcl::body Rappture::FileListEntry::_newValue { args } {
343    event generate $itk_component(hull) <<Value>>
344}
345
346# ----------------------------------------------------------------------
347# USAGE: _tooltip
348#
349# Returns the tooltip for this widget, given the current choice in
350# the selector.  This is normally called by the Rappture::Tooltip
351# facility whenever it is about to pop up a tooltip for this widget.
352# ----------------------------------------------------------------------
353itcl::body Rappture::FileListEntry::_tooltip {} {
354    set tip [string trim [$_owner xml get $_path.about.description]]
355    # get the description for the current choice, if there is one
356    set path ""
357    set desc ""
358    if {$path == ""} {
359        set desc [$_owner xml get $_path.about.description]
360    }
361    set str ""
362    if {[string length $str] > 0 && [string length $desc] > 0} {
363        append tip "\n\n$str:\n$desc"
364    }
365    return $tip
366}
367
368# ----------------------------------------------------------------------
369# CONFIGURATION OPTION: -state
370# ----------------------------------------------------------------------
371itcl::configbody Rappture::FileListEntry::state {
372    set valid {normal disabled}
373    if {[lsearch -exact $valid $itk_option(-state)] < 0} {
374        error "bad value \"$itk_option(-state)\": should be [join $valid {, }]"
375    }
376    #$itk_component(tree) configure -state $itk_option(-state)
377}
378
379itcl::body Rappture::FileListEntry::_whenidle {} {
380    if { !$_rebuildPending } {
381        after 10 [itcl::code $this _rebuild]
382        set _rebuildPending 1
383    }
384}
385
386proc Rappture::FileListEntry::SetSelectionAnchor { w tagOrId clear how } {
387    set index [$w index $tagOrId]
388    if { $clear } {
389        $w selection clearall
390    }
391    $w see $index
392    $w focus $index
393    $w selection $how $index
394    $w selection anchor $index
395}
396
397
Note: See TracBrowser for help on using the repository browser.