source: trunk/gui/scripts/loader.tcl @ 746

Last change on this file since 746 was 746, checked in by mmc, 17 years ago

Fix for support ticket #1773 "bad window path name ".main.area..."
Added a band-aid into the whole GUI loading process. MOSFET has been
having trouble loading its structure. A fix for that caused this
problem in CNTbands v2.0. This will hold for now.

File size: 16.0 KB
Line 
1# ----------------------------------------------------------------------
2#  COMPONENT: loader - widget for loading examples and old runs
3#
4#  This widget is a glorified combobox that is used to load various
5#  example files into the application.
6# ======================================================================
7#  AUTHOR:  Michael McLennan, Purdue University
8#  Copyright (c) 2004-2005  Purdue Research Foundation
9#
10#  See the file "license.terms" for information on usage and
11#  redistribution of this file, and for a DISCLAIMER OF ALL WARRANTIES.
12# ======================================================================
13package require Itk
14
15option add *Loader.textForeground black widgetDefault
16option add *Loader.textBackground white widgetDefault
17
18itcl::class Rappture::Loader {
19    inherit itk::Widget
20
21    itk_option define -tool tool Tool ""
22    itk_option define -state state State "normal"
23
24    constructor {owner path args} { # defined below }
25    destructor { # defined below }
26
27    public method value {args}
28
29    public method label {}
30    public method tooltip {}
31
32    protected method _newValue {}
33    protected method _uploadValue {path args}
34    protected method _downloadValues {}
35    protected method _tooltip {}
36
37    private variable _owner ""    ;# thing managing this control
38    private variable _path ""     ;# path in XML to this loader
39    private variable _lastlabel "";# label of last example loaded
40
41    private variable _uppath ""   ;# list: path label desc ...
42    private variable _dnpaths ""  ;# list of download element paths
43    private common _dnpath2state  ;# maps download path => yes/no state
44}
45
46itk::usual Loader {
47    keep -cursor -font
48    keep -foreground -background
49    keep -textforeground -textbackground
50    keep -selectbackground -selectforeground -selectborderwidth
51}
52
53# ----------------------------------------------------------------------
54# CONSTRUCTOR
55# ----------------------------------------------------------------------
56itcl::body Rappture::Loader::constructor {owner path args} {
57    if {[catch {$owner isa Rappture::ControlOwner} valid] != 0 || !$valid} {
58        error "bad object \"$owner\": should be Rappture::ControlOwner"
59    }
60    set _owner $owner
61    set _path $path
62
63    itk_component add combo {
64        Rappture::Combobox $itk_interior.combo -editable no
65    } {
66        usual
67        keep -width
68    }
69    pack $itk_component(combo) -expand yes -fill both
70    bind $itk_component(combo) <<Value>> [itcl::code $this _newValue]
71
72    eval itk_initialize $args
73
74    # example files are stored here
75    if {$itk_option(-tool) != ""} {
76        set fdir [$itk_option(-tool) installdir]
77    } else {
78        set fdir "."
79    }
80    set defval [$_owner xml get $path.default]
81
82    #
83    # If this loader has a <new> section, then create that
84    # entry first.
85    #
86    set newfile ""
87    foreach comp [$_owner xml children -type new $path] {
88        set name [$_owner xml get $path.$comp]
89        set fname [file join $fdir examples $name]
90
91        if {[file exists $fname]} {
92            set newfile $fname
93            if {[catch {set obj [Rappture::library $fname]} result]} {
94                puts stderr "WARNING: can't load example file \"$fname\""
95                puts stderr "  $result"
96            } else {
97                $itk_component(combo) choices insert end $obj "New"
98                # translate default file name => default label
99                if {[string equal $defval [file tail $fname]]} {
100                    $_owner xml put $path.default "New"
101                }
102            }
103            break
104        } else {
105            puts stderr "WARNING: missing example file \"$fname\""
106        }
107    }
108
109    #
110    # If this loader has an <upload> section, then create that
111    # entry next.
112    #
113    foreach comp [$_owner xml children -type upload $path] {
114        foreach tcomp [$_owner xml children -type to $path.$comp] {
115            set topath [$_owner xml get $path.$comp.$tcomp]
116            set label [$_owner xml get $topath.about.label]
117            set desc [$_owner xml get $topath.about.description]
118            lappend _uppath $topath $label $desc
119        }
120        break
121    }
122    if {[llength $_uppath] > 0} {
123        $itk_component(combo) choices insert end @upload "Upload..."
124    }
125
126    #
127    # If this loader has a <download> section, then create that
128    # entry next.  Build a popup for choices if there is more than
129    # one download element.
130    #
131    Rappture::Balloon $itk_component(hull).download \
132        -title "Choose what to download:"
133    set inner [$itk_component(hull).download component inner]
134
135    set i 0
136    foreach comp [$_owner xml children -type download $path] {
137        foreach dcomp [$_owner xml children -type from $path.$comp] {
138            set frompath [$_owner xml get $path.$comp.$dcomp]
139            if {"" != $frompath} {
140                lappend _dnpaths $frompath
141                set _dnpath2state($this-$frompath) [expr {$i == 0}]
142
143                set label [$_owner xml get $frompath.about.label]
144                checkbutton $inner.cb$i -text $label \
145                    -variable ::Rappture::Loader::_dnpath2state($this-$frompath)
146                pack $inner.cb$i -anchor w
147                incr i
148            }
149        }
150    }
151    button $inner.go -text "Download" \
152        -command [itcl::code $this _downloadValues]
153    pack $inner.go -side bottom -padx 50 -pady {4 2}
154
155    if {[llength $_dnpaths] > 0} {
156        $itk_component(combo) choices insert end @download "Download..."
157    }
158
159    if {[$itk_component(combo) choices size] > 0} {
160        $itk_component(combo) choices insert end "---" "---"
161    }
162
163    #
164    # Scan through and extract example objects, and load them into
165    # the combobox.
166    #
167    set flist ""
168    foreach comp [$_owner xml children -type example $path] {
169        lappend flist [$_owner xml get $path.$comp]
170    }
171
172    # if there are no examples, then look for *.xml
173    if {[llength $flist] == 0} {
174        set flist *.xml
175    }
176
177    catch {unset entries}
178    set _counter 0
179    foreach ftail $flist {
180        set fpath [file join $fdir examples $ftail]
181
182        foreach fname [glob -nocomplain $fpath] {
183            if {[string equal $fname $newfile]} {
184                continue
185            }
186            if {[file exists $fname]} {
187                if {[catch {set obj [Rappture::library $fname]} result]} {
188                    puts stderr "WARNING: can't load example file \"$fname\""
189                    puts stderr "  $result"
190                } else {
191                    set label [$obj get about.label]
192                    if {$label == ""} {
193                        set label "Example #[incr _counter]"
194                    }
195
196                    # if this is new, add it
197                    if {![info exists entries($label)]} {
198                        set entries($label) $obj
199                    }
200
201                    # translate default file name => default label
202                    if {[string equal $defval [file tail $fname]]} {
203                        $_owner xml put $path.default $label
204                    }
205                }
206            } else {
207                puts stderr "WARNING: missing example file \"$fname\""
208            }
209        }
210    }
211    foreach label [lsort -dictionary [array names entries]] {
212        $itk_component(combo) choices insert end $entries($label) $label
213    }
214
215    #
216    # Assign the default value to this widget, if there is one.
217    #
218    set str [$_owner xml get $path.default]
219    if {$str != ""} { after 1500 [itcl::code $this value $str] }
220}
221
222# ----------------------------------------------------------------------
223# DESTRUCTOR
224# ----------------------------------------------------------------------
225itcl::body Rappture::Loader::destructor {} {
226    # be sure to clean up entries for this widget's download paths
227    foreach path $_dnpaths {
228        catch {unset _dnpath2state($this-$path)}
229    }
230}
231
232# ----------------------------------------------------------------------
233# USAGE: value ?-check? ?<newval>?
234#
235# Clients use this to query/set the value for this widget.  With
236# no args, it returns the current value for the widget.  If the
237# <newval> is specified, it sets the value of the widget and
238# sends a <<Value>> event.  If the -check flag is included, the
239# new value is not actually applied, but just checked for correctness.
240# ----------------------------------------------------------------------
241itcl::body Rappture::Loader::value {args} {
242    set onlycheck 0
243    set i [lsearch -exact $args -check]
244    if {$i >= 0} {
245        set onlycheck 1
246        set args [lreplace $args $i $i]
247    }
248
249    if {[llength $args] == 1} {
250        if {$onlycheck} {
251            # someday we may add validation...
252            return
253        }
254        set newval [lindex $args 0]
255        $itk_component(combo) value $newval
256        return $newval
257
258    } elseif {[llength $args] != 0} {
259        error "wrong # args: should be \"value ?-check? ?newval?\""
260    }
261
262    #
263    # Query the value and return.
264    #
265    return [$itk_component(combo) value]
266}
267
268# ----------------------------------------------------------------------
269# USAGE: label
270#
271# Clients use this to query the label associated with this widget.
272# Reaches into the XML and pulls out the appropriate label string.
273# ----------------------------------------------------------------------
274itcl::body Rappture::Loader::label {} {
275    set label [$_owner xml get $_path.about.label]
276    if {"" == $label} {
277        set label "Example"
278    }
279    return $label
280}
281
282# ----------------------------------------------------------------------
283# USAGE: tooltip
284#
285# Clients use this to query the tooltip associated with this widget.
286# Reaches into the XML and pulls out the appropriate description
287# string.  Returns the string that should be used with the
288# Rappture::Tooltip facility.
289# ----------------------------------------------------------------------
290itcl::body Rappture::Loader::tooltip {} {
291    # query tooltip on-demand based on current choice
292    return "@[itcl::code $this _tooltip]"
293}
294
295# ----------------------------------------------------------------------
296# USAGE: _newValue
297#
298# Invoked automatically whenever the value in the combobox changes.
299# Tries to load the selected example into the tool's data structure.
300# Sends a <<Value>> event to notify clients of the change.
301# ----------------------------------------------------------------------
302itcl::body Rappture::Loader::_newValue {} {
303    set newval [$itk_component(combo) value]
304    set obj [$itk_component(combo) translate $newval]
305    if {$obj == "@upload"} {
306        if {[Rappture::filexfer::enabled]} {
307            set tool [Rappture::Tool::resources -appname]
308            Rappture::filexfer::upload \
309                $tool $_uppath [itcl::code $this _uploadValue]
310        }
311
312        # put the combobox back to its last value
313        $itk_component(combo) component entry configure -state normal
314        $itk_component(combo) component entry delete 0 end
315        $itk_component(combo) component entry insert end $_lastlabel
316        $itk_component(combo) component entry configure -state disabled
317
318    } elseif {$obj == "@download"} {
319        if {[llength $_dnpaths] == 1} {
320            _downloadValues
321        } else {
322            $itk_component(hull).download activate $itk_component(combo) below
323        }
324
325        # put the combobox back to its last value
326        $itk_component(combo) component entry configure -state normal
327        $itk_component(combo) component entry delete 0 end
328        $itk_component(combo) component entry insert end $_lastlabel
329        $itk_component(combo) component entry configure -state disabled
330
331    } elseif {$obj == "---"} {
332        # put the combobox back to its last value
333        $itk_component(combo) component entry configure -state normal
334        $itk_component(combo) component entry delete 0 end
335        $itk_component(combo) component entry insert end $_lastlabel
336        $itk_component(combo) component entry configure -state disabled
337    } elseif {$obj != "" && $itk_option(-tool) != ""} {
338        $itk_option(-tool) load $obj
339        set _lastlabel $newval
340    }
341
342    event generate $itk_component(hull) <<Value>>
343}
344
345# ----------------------------------------------------------------------
346# USAGE: _tooltip
347#
348# Returns the tooltip for this widget, given the current choice in
349# the selector.  This is normally called by the Rappture::Tooltip
350# facility whenever it is about to pop up a tooltip for this widget.
351# ----------------------------------------------------------------------
352itcl::body Rappture::Loader::_tooltip {} {
353    set str [string trim [$_owner xml get $_path.about.description]]
354
355    # get the description for the current choice, if there is one
356    set newval [$itk_component(combo) value]
357    set obj [$itk_component(combo) translate $newval]
358    if {$obj != ""} {
359        if {$obj == "@upload"} {
360            append str "\n\nUse this option to upload data from your desktop."
361        } else {
362            set label [$obj get about.label]
363            if {[string length $label] > 0} {
364                append str "\n\n$label"
365            }
366
367            set desc [$obj get about.description]
368            if {[string length $desc] > 0} {
369                if {[string length $label] > 0} {
370                    append str ":\n"
371                } else {
372                    append str "\n\n"
373                }
374                append str $desc
375            }
376        }
377    }
378    return [string trim $str]
379}
380
381# ----------------------------------------------------------------------
382# USAGE: _uploadValue ?<key> <value> <key> <value> ...?
383#
384# Invoked automatically whenever the user has uploaded data from
385# the "Upload..." option.  Takes the data value (passed as an
386# argument) and loads into the destination widget.
387# ----------------------------------------------------------------------
388itcl::body Rappture::Loader::_uploadValue {args} {
389    array set data $args
390
391    if {[info exists data(error)]} {
392        Rappture::Tooltip::cue $itk_component(combo) $data(error)
393    }
394
395    if {[info exists data(path)] && [info exists data(data)]} {
396        Rappture::Tooltip::cue hide  ;# take down note about the popup window
397        $itk_option(-tool) valuefor $data(path) $data(data)
398
399        $itk_component(combo) component entry configure -state normal
400        $itk_component(combo) component entry delete 0 end
401        $itk_component(combo) component entry insert end "Uploaded data"
402        $itk_component(combo) component entry configure -state disabled
403        set _lastlabel "Uploaded data"
404    }
405}
406
407# ----------------------------------------------------------------------
408# USAGE: _downloadValues
409#
410# Used internally to download all values checked by the popup that
411# controls downloading.  Sends the values for the various controls
412# out to the user by popping up separate browser windows.
413# ----------------------------------------------------------------------
414itcl::body Rappture::Loader::_downloadValues {} {
415    # take down the popup (in case it was posted)
416    $itk_component(hull).download deactivate
417
418    set mesg ""
419    if {[Rappture::filexfer::enabled]} {
420        foreach path $_dnpaths {
421            if {$_dnpath2state($this-$path)} {
422                set info [$itk_option(-tool) valuefor $path]
423                set mesg [Rappture::filexfer::download $info input.txt]
424                if {"" != $mesg} { break }
425            }
426        }
427    }
428
429    if {"" != $mesg} {
430        Rappture::Tooltip::cue $itk_component(combo) $mesg
431    }
432}
433
434# ----------------------------------------------------------------------
435# OPTION: -tool
436# ----------------------------------------------------------------------
437itcl::configbody Rappture::Loader::tool {
438    if {[catch {$itk_option(-tool) isa Rappture::Tool} valid] || !$valid} {
439        error "object \"$itk_option(-tool)\" is not a Rappture Tool"
440    }
441}
442
443# ----------------------------------------------------------------------
444# CONFIGURATION OPTION: -state
445# ----------------------------------------------------------------------
446itcl::configbody Rappture::Loader::state {
447    set valid {normal disabled}
448    if {[lsearch -exact $valid $itk_option(-state)] < 0} {
449        error "bad value \"$itk_option(-state)\": should be [join $valid {, }]"
450    }
451    $itk_component(combo) configure -state $itk_option(-state)
452}
Note: See TracBrowser for help on using the repository browser.