source: branches/blt4/gui/scripts/filechoiceentry.tcl @ 1675

Last change on this file since 1675 was 1675, checked in by gah, 14 years ago
File size: 9.5 KB
Line 
1
2# ----------------------------------------------------------------------
3#  COMPONENT: FileChoiceEntry - 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
16itcl::class Rappture::FileChoiceEntry {
17    inherit itk::Widget
18
19    itk_option define -state state State "normal"
20   
21    private variable _rebuildPending 0
22
23    constructor {owner path args} {
24        # defined below
25    }
26    destructor {
27        # defined below
28    }
29    public method value {args}
30
31    public method label {}
32    public method tooltip {}
33
34    protected method _rebuild {}
35    protected method _newValue {}
36    protected method _tooltip {}
37    protected method _whenidle {}
38
39    private variable _owner ""    ;# thing managing this control
40    private variable _path ""     ;# path in XML to this number
41    private variable _str2val     ;# maps option label => option value
42}
43
44
45itk::usual FileChoiceEntry {
46    keep -cursor -font
47    keep -foreground -background
48    keep -textforeground -textbackground
49    keep -selectbackground -selectforeground -selectborderwidth
50}
51
52# ----------------------------------------------------------------------
53# CONSTRUCTOR
54# ----------------------------------------------------------------------
55itcl::body Rappture::FileChoiceEntry::constructor {owner path args} {
56    if {[catch {$owner isa Rappture::ControlOwner} valid] != 0 || !$valid} {
57        error "bad object \"$owner\": should be Rappture::ControlOwner"
58    }
59    set _owner $owner
60    set _path $path
61
62    #
63    # Create the widget and configure it properly based on other
64    # hints in the XML.
65    #
66    itk_component add choice {
67        Rappture::Combobox $itk_interior.choice -editable no
68    }
69    pack $itk_component(choice) -expand yes -fill both
70    bind $itk_component(choice) <<Value>> [itcl::code $this _newValue]
71
72    # First time, parse the <pattern> elements to generate notify callbacks
73    # for each template found.
74    foreach cname [$_owner xml children -type pattern $_path] {
75        set glob [string trim [$_owner xml get $_path.$cname]]
76        # Successively replace each template with its value.
77        while { [regexp -indices {@@[^@]*@@} $glob range] } {
78            foreach {first last} $range break
79            set i1 [expr $first + 2]
80            set i2 [expr $last  - 2]
81            set path [string range $glob $i1 $i2]
82            set value [$_owner xml get $_path.$cname]
83            set value [$_owner xml get $path]
84            set glob [string replace $glob $first $last $value]
85            $_owner notify add $this $path [itcl::code $this _whenidle]
86        }
87    }
88    $_owner notify sync
89    eval itk_initialize $args
90    _rebuild
91}
92
93# ----------------------------------------------------------------------
94# DESTRUCTOR
95# ----------------------------------------------------------------------
96itcl::body Rappture::FileChoiceEntry::destructor {} {
97    $_owner notify remove $this
98}
99
100# ----------------------------------------------------------------------
101# USAGE: value ?-check? ?<newval>?
102#
103# Clients use this to query/set the value for this widget.  With
104# no args, it returns the current value for the widget.  If the
105# <newval> is specified, it sets the value of the widget and
106# sends a <<Value>> event.  If the -check flag is included, the
107# new value is not actually applied, but just checked for correctness.
108# ----------------------------------------------------------------------
109itcl::body Rappture::FileChoiceEntry::value {args} {
110    set onlycheck 0
111    set i [lsearch -exact $args -check]
112    if {$i >= 0} {
113        set onlycheck 1
114        set args [lreplace $args $i $i]
115    }
116
117    if {[llength $args] == 1} {
118        if {$onlycheck} {
119            # someday we may add validation...
120            return
121        }
122        set newval [lindex $args 0]
123        if {[info exists _str2val($newval)]} {
124            # this is a label -- use it directly
125            $itk_component(choice) value $newval
126            set newval $_str2val($newval)  ;# report the actual value
127        } else {
128            # this is a value -- search for corresponding label
129            foreach str [array names _str2val] {
130                if {$_str2val($str) == $newval} {
131                    $itk_component(choice) value $str
132                    break
133                }
134            }
135        }
136        return $newval
137
138    } elseif {[llength $args] != 0} {
139        error "wrong # args: should be \"value ?-check? ?newval?\""
140    }
141
142    #
143    # Query the value and return.
144    #
145    set str [$itk_component(choice) value]
146    if {[info exists _str2val($str)]} {
147        return $_str2val($str)
148    }
149    return $str
150}
151
152# ----------------------------------------------------------------------
153# USAGE: label
154#
155# Clients use this to query the label associated with this widget.
156# Reaches into the XML and pulls out the appropriate label string.
157# ----------------------------------------------------------------------
158itcl::body Rappture::FileChoiceEntry::label {} {
159    set label [$_owner xml get $_path.about.label]
160    if {"" == $label} {
161        set label "Choice"
162    }
163    return $label
164}
165
166# ----------------------------------------------------------------------
167# USAGE: tooltip
168#
169# Clients use this to query the tooltip associated with this widget.
170# Reaches into the XML and pulls out the appropriate description
171# string.  Returns the string that should be used with the
172# Rappture::Tooltip facility.
173# ----------------------------------------------------------------------
174itcl::body Rappture::FileChoiceEntry::tooltip {} {
175    # query tooltip on-demand based on current choice
176    return "@[itcl::code $this _tooltip]"
177}
178
179# ----------------------------------------------------------------------
180# USAGE: _rebuild
181#
182# Used internally to rebuild the contents of this choice widget
183# whenever something that it depends on changes.  Scans through the
184# information in the XML spec and builds a list of choices for the
185# widget.
186# ----------------------------------------------------------------------
187itcl::body Rappture::FileChoiceEntry::_rebuild {} {
188    puts stderr "filechoiceentry rebuild"
189    set _rebuildPending 0
190    # get rid of any existing choices
191    $itk_component(choice) choices delete 0 end
192    array unset _str2val
193    #
194    # Plug in the various options for the choice.
195    #
196    set max 10
197    $_owner notify sync
198    set allfiles {}
199    foreach cname [$_owner xml children -type pattern $_path] {
200        set glob [string trim [$_owner xml get $_path.$cname]]
201        # Successively replace each template with its value.
202        puts stderr "before glob=$glob"
203        while { [regexp -indices {@@[^@]*@@} $glob range] } {
204            foreach {first last} $range break
205            set i1 [expr $first + 2]
206            set i2 [expr $last  - 2]
207            set path [string range $glob $i1 $i2]
208            set value [$_owner xml get $path.current]
209            puts stderr "$path.current: value=$value"
210            if { $value == "" } {
211                set value [$_owner xml get $path.default]
212                puts stderr "$path.default: value=$value"
213            }
214            set glob [string replace $glob $first $last $value]
215        }
216        puts stderr "after glob=$glob"
217        # Replace the template with the substituted value.
218        set files [glob -nocomplain $glob]
219        puts stderr "files=$files"
220        set allfiles [concat $allfiles $files]
221    }
222    set first ""
223    foreach file $allfiles {
224        set tail [file tail $file]
225        if { $first == "" } {
226            set first $tail
227        }
228        $itk_component(choice) choices insert end $file $tail
229        set _str2val($file) $tail
230        set len [string length $tail]
231        if {$len > $max} { set max $len }
232    }
233    $itk_component(choice) configure -width $max
234    $itk_component(choice) value $tail
235}
236
237# ----------------------------------------------------------------------
238# USAGE: _newValue
239#
240# Invoked automatically whenever the value in the choice changes.
241# Sends a <<Value>> event to notify clients of the change.
242# ----------------------------------------------------------------------
243itcl::body Rappture::FileChoiceEntry::_newValue {} {
244    event generate $itk_component(hull) <<Value>>
245}
246
247# ----------------------------------------------------------------------
248# USAGE: _tooltip
249#
250# Returns the tooltip for this widget, given the current choice in
251# the selector.  This is normally called by the Rappture::Tooltip
252# facility whenever it is about to pop up a tooltip for this widget.
253# ----------------------------------------------------------------------
254itcl::body Rappture::FileChoiceEntry::_tooltip {} {
255    set tip [string trim [$_owner xml get $_path.about.description]]
256
257    # get the description for the current choice, if there is one
258    set str [$itk_component(choice) value]
259    set path [$itk_component(choice) translate $str]
260    set desc ""
261    if {$path != ""} {
262        set desc [$_owner xml get $path.about.description]
263    }
264
265    if {[string length $str] > 0 && [string length $desc] > 0} {
266        append tip "\n\n$str:\n$desc"
267    }
268    return $tip
269}
270
271# ----------------------------------------------------------------------
272# CONFIGURATION OPTION: -state
273# ----------------------------------------------------------------------
274itcl::configbody Rappture::FileChoiceEntry::state {
275    set valid {normal disabled}
276    if {[lsearch -exact $valid $itk_option(-state)] < 0} {
277        error "bad value \"$itk_option(-state)\": should be [join $valid {, }]"
278    }
279    $itk_component(choice) configure -state $itk_option(-state)
280}
281
282itcl::body Rappture::FileChoiceEntry::_whenidle {} {
283    if { !$_rebuildPending } {
284        after 10 [itcl::code $this _rebuild]
285        set _rebuildPending 1
286    }
287}
Note: See TracBrowser for help on using the repository browser.