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

Last change on this file since 608 was 437, checked in by mmc, 18 years ago

Added a new <enable> parameter to all inputs. Controls can now be
enabled/disabled based on the status of other controls. If a group
is disabled, it disappears entirely. If a parameter is enabled to
a hard-coded "off" value, then it acts like a hidden (secret)
parameter.

File size: 18.4 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
26    public method value {args}
27
28    public method label {}
29    public method tooltip {}
30
31    protected method _newValue {}
32    protected method _uploadValue {string}
33    protected method _tooltip {}
34
35    private variable _owner ""    ;# thing managing this control
36    private variable _path ""     ;# path in XML to this loader
37    private variable _lastlabel "";# label of last example loaded
38
39    private variable _uppath ""   ;# path to Upload... component
40    private variable _updesc ""   ;# description for Upload... data
41    private variable _upfilter "" ;# filter used for upload data
42
43    private variable _dnpath ""   ;# path to Download... component
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        set topath [$_owner xml get $path.$comp.to]
115        if {"" != $topath} {
116            set _uppath $topath
117
118            set desc [$_owner xml get $path.$comp.prompt]
119            if {"" == $desc} {
120                set desc "Use this form to upload data"
121                set dest [$owner xml get $_uppath.about.label]
122                if {"" != $dest} {
123                    append desc " into the $dest area"
124                }
125                append desc "."
126            }
127            set _updesc $desc
128
129            $itk_component(combo) choices insert end @upload "Upload..."
130            break
131        }
132    }
133
134    #
135    # If this loader has a <download> section, then create that
136    # entry next.
137    #
138    foreach comp [$_owner xml children -type download $path] {
139        set frompath [$_owner xml get $path.$comp.from]
140        if {"" != $frompath} {
141            set _dnpath $frompath
142            $itk_component(combo) choices insert end @download "Download..."
143            break
144        }
145    }
146
147    if {[$itk_component(combo) choices size] > 0} {
148        $itk_component(combo) choices insert end "---" "---"
149    }
150
151    #
152    # Scan through and extract example objects, and load them into
153    # the combobox.
154    #
155    set flist ""
156    foreach comp [$_owner xml children -type example $path] {
157        lappend flist [$_owner xml get $path.$comp]
158    }
159
160    # if there are no examples, then look for *.xml
161    if {[llength $flist] == 0} {
162        set flist *.xml
163    }
164
165    catch {unset entries}
166    set _counter 0
167    foreach ftail $flist {
168        set fpath [file join $fdir examples $ftail]
169
170        foreach fname [glob -nocomplain $fpath] {
171            if {[string equal $fname $newfile]} {
172                continue
173            }
174            if {[file exists $fname]} {
175                if {[catch {set obj [Rappture::library $fname]} result]} {
176                    puts stderr "WARNING: can't load example file \"$fname\""
177                    puts stderr "  $result"
178                } else {
179                    set label [$obj get about.label]
180                    if {$label == ""} {
181                        set label "Example #[incr _counter]"
182                    }
183
184                    # if this is new, add it
185                    if {![info exists entries($label)]} {
186                        set entries($label) $obj
187                    }
188
189                    # translate default file name => default label
190                    if {[string equal $defval [file tail $fname]]} {
191                        $_owner xml put $path.default $label
192                    }
193                }
194            } else {
195                puts stderr "WARNING: missing example file \"$fname\""
196            }
197        }
198    }
199    foreach label [lsort -dictionary [array names entries]] {
200        $itk_component(combo) choices insert end $entries($label) $label
201    }
202
203    #
204    # Assign the default value to this widget, if there is one.
205    #
206    set str [$_owner xml get $path.default]
207    if {$str != ""} { after 1000 [itcl::code $this value $str] }
208}
209
210# ----------------------------------------------------------------------
211# USAGE: value ?-check? ?<newval>?
212#
213# Clients use this to query/set the value for this widget.  With
214# no args, it returns the current value for the widget.  If the
215# <newval> is specified, it sets the value of the widget and
216# sends a <<Value>> event.  If the -check flag is included, the
217# new value is not actually applied, but just checked for correctness.
218# ----------------------------------------------------------------------
219itcl::body Rappture::Loader::value {args} {
220    set onlycheck 0
221    set i [lsearch -exact $args -check]
222    if {$i >= 0} {
223        set onlycheck 1
224        set args [lreplace $args $i $i]
225    }
226
227    if {[llength $args] == 1} {
228        if {$onlycheck} {
229            # someday we may add validation...
230            return
231        }
232        set newval [lindex $args 0]
233        $itk_component(combo) value $newval
234        return $newval
235
236    } elseif {[llength $args] != 0} {
237        error "wrong # args: should be \"value ?-check? ?newval?\""
238    }
239
240    #
241    # Query the value and return.
242    #
243    return [$itk_component(combo) value]
244}
245
246# ----------------------------------------------------------------------
247# USAGE: label
248#
249# Clients use this to query the label associated with this widget.
250# Reaches into the XML and pulls out the appropriate label string.
251# ----------------------------------------------------------------------
252itcl::body Rappture::Loader::label {} {
253    set label [$_owner xml get $_path.about.label]
254    if {"" == $label} {
255        set label "Example"
256    }
257    return $label
258}
259
260# ----------------------------------------------------------------------
261# USAGE: tooltip
262#
263# Clients use this to query the tooltip associated with this widget.
264# Reaches into the XML and pulls out the appropriate description
265# string.  Returns the string that should be used with the
266# Rappture::Tooltip facility.
267# ----------------------------------------------------------------------
268itcl::body Rappture::Loader::tooltip {} {
269    # query tooltip on-demand based on current choice
270    return "@[itcl::code $this _tooltip]"
271}
272
273# ----------------------------------------------------------------------
274# USAGE: _newValue
275#
276# Invoked automatically whenever the value in the combobox changes.
277# Tries to load the selected example into the tool's data structure.
278# Sends a <<Value>> event to notify clients of the change.
279# ----------------------------------------------------------------------
280itcl::body Rappture::Loader::_newValue {} {
281    set newval [$itk_component(combo) value]
282    set obj [$itk_component(combo) translate $newval]
283    if {$obj == "@upload"} {
284        if {[Rappture::filexfer::enabled]} {
285            set status [catch {Rappture::filexfer::upload \
286                $_updesc [itcl::code $this _uploadValue]} result]
287            if {$status == 0} {
288                Rappture::Tooltip::cue $itk_component(combo) \
289                    "Upload starting...\nA web browser page should pop up on your desktop.  Use that form to handle the upload operation.\n\nIf the upload form doesn't pop up, make sure that you're allowing pop ups from this site.  If it still doesn't pop up, you may be having trouble with the version of Java installed for your browser.  See our Support area for details.\n\nClick anywhere to dismiss this message."
290            } else {
291                if {$result == "no clients"} {
292                    Rappture::Tooltip::cue $itk_component(combo) \
293                        "Can't upload files.  Looks like you might be having trouble with the version of Java installed for your browser."
294                } elseif {"old client" == $result} {
295                    Rappture::Tooltip::cue $itk_component(combo) "For this to work properly, you must first restart your Web browser.  You don't need to close down this session.  Simply shut down all windows for your Web browser, then restart the browser and navigate back to this page.  You'll find it on \"my nanoHUB\" listed under \"my sessions\".  Once the browser is restarted, the upload should work properly."
296                } elseif {"old clients" == $result} {
297                    Rappture::Tooltip::cue $itk_component(combo) "There are multiple browser pages connected to this session, and one of them has browser that needs to be restarted.\n\nWhoever didn't get the upload form should restart their Web browser.  You don't need to close down this session.  Simply shut down all windows for the Web browser, then restart the browser and navigate back to this page.  You'll find it on \"my nanoHUB\" listed under \"my sessions\".  Once the browser is restarted, the upload should work properly."
298                } else {
299                    bgerror $result
300                }
301            }
302        } else {
303            Rappture::Tooltip::cue $itk_component(combo) \
304                "Can't upload data.  Upload is not enabled.  Is your SESSION variable set?  Is there an error in your session resources file?"
305        }
306
307        # put the combobox back to its last value
308        $itk_component(combo) component entry configure -state normal
309        $itk_component(combo) component entry delete 0 end
310        $itk_component(combo) component entry insert end $_lastlabel
311        $itk_component(combo) component entry configure -state disabled
312
313    } elseif {$obj == "@download"} {
314        if {[Rappture::filexfer::enabled]} {
315            set info [$itk_option(-tool) valuefor $_dnpath]
316            set status [catch {Rappture::filexfer::spool $info input.txt} result]
317            if {$status != 0} {
318                if {$result == "no clients"} {
319                    Rappture::Tooltip::cue $itk_component(combo) \
320                        "Can't download data.  Looks like you might be having trouble with the version of Java installed for your browser."
321                } elseif {"old client" == $result} {
322                    Rappture::Tooltip::cue $itk_component(combo) "For this to work properly, you must first restart your Web browser.  You don't need to close down this session.  Simply shut down all windows for your Web browser, then restart the browser and navigate back to this page.  You'll find it on \"my nanoHUB\" listed under \"my sessions\".  Once the browser is restarted, the download should work properly."
323                } elseif {"old clients" == $result} {
324                    Rappture::Tooltip::cue $itk_component(combo) "There are multiple browser pages connected to this session, and one of them has browser that needs to be restarted.\n\nWhoever didn't get the download should restart their Web browser.  You don't need to close down this session.  Simply shut down all windows for the Web browser, then restart the browser and navigate back to this page.  You'll find it on \"my nanoHUB\" listed under \"my sessions\".  Once the browser is restarted, the download should work properly."
325                } else {
326                    bgerror $result
327                }
328            }
329        } else {
330            Rappture::Tooltip::cue $itk_component(combo) \
331                "Can't download data.  Download is not enabled.  Is your SESSION variable set?  Is there an error in your session resources file?"
332        }
333
334        # put the combobox back to its last value
335        $itk_component(combo) component entry configure -state normal
336        $itk_component(combo) component entry delete 0 end
337        $itk_component(combo) component entry insert end $_lastlabel
338        $itk_component(combo) component entry configure -state disabled
339
340    } elseif {$obj == "---"} {
341        # put the combobox back to its last value
342        $itk_component(combo) component entry configure -state normal
343        $itk_component(combo) component entry delete 0 end
344        $itk_component(combo) component entry insert end $_lastlabel
345        $itk_component(combo) component entry configure -state disabled
346    } elseif {$obj != "" && $itk_option(-tool) != ""} {
347        $itk_option(-tool) load $obj
348        set _lastlabel $newval
349    }
350
351    event generate $itk_component(hull) <<Value>>
352}
353
354# ----------------------------------------------------------------------
355# USAGE: _tooltip
356#
357# Returns the tooltip for this widget, given the current choice in
358# the selector.  This is normally called by the Rappture::Tooltip
359# facility whenever it is about to pop up a tooltip for this widget.
360# ----------------------------------------------------------------------
361itcl::body Rappture::Loader::_tooltip {} {
362    set str [string trim [$_owner xml get $_path.about.description]]
363
364    # get the description for the current choice, if there is one
365    set newval [$itk_component(combo) value]
366    set obj [$itk_component(combo) translate $newval]
367    if {$obj != ""} {
368        if {$obj == "@upload"} {
369            append str "\n\nUse this option to upload data from your desktop."
370        } else {
371            set label [$obj get about.label]
372            if {[string length $label] > 0} {
373                append str "\n\n$label"
374            }
375
376            set desc [$obj get about.description]
377            if {[string length $desc] > 0} {
378                if {[string length $label] > 0} {
379                    append str ":\n"
380                } else {
381                    append str "\n\n"
382                }
383                append str $desc
384            }
385        }
386    }
387    return [string trim $str]
388}
389
390# ----------------------------------------------------------------------
391# USAGE: _uploadValue ?<key> <value> <key> <value> ...?
392#
393# Invoked automatically whenever the user has uploaded data from
394# the "Upload..." option.  Takes the data value (passed as an
395# argument) and loads into the destination widget.
396# ----------------------------------------------------------------------
397itcl::body Rappture::Loader::_uploadValue {args} {
398    Rappture::Tooltip::cue hide  ;# take down the note about the popup window
399
400    array set data $args
401
402    if {[string length [string trim $data(data)]] == 0} {
403        switch -- $data(which) {
404            file {
405                set mesg "You indicated that you were uploading a file, but y"
406            }
407            text {
408                set mesg "You indicated that you were uploading text, but y"
409            }
410            default {
411                set mesg "Y"
412            }
413        }
414        Rappture::Tooltip::cue $itk_component(combo) \
415            "${mesg}ou didn't fill in any data on the upload form."
416        return
417    }
418
419    #
420    # BE CAREFUL:  This string may have binary characters that
421    #   aren't appropriate for a string editor.  Right now, XML
422    #   will barf on these characters.  Clip them out and be
423    #   done with it.
424    #
425    set string $data(data)
426    regsub -all {[\000-\010\013\014\016-\037\177-\377]} $string {} string
427    regsub -all "\r" $string "\n" string
428    $itk_option(-tool) valuefor $_uppath $string
429
430    $itk_component(combo) component entry configure -state normal
431    $itk_component(combo) component entry delete 0 end
432    $itk_component(combo) component entry insert end "Uploaded data"
433    $itk_component(combo) component entry configure -state disabled
434    set _lastlabel "Uploaded data"
435}
436
437# ----------------------------------------------------------------------
438# OPTION: -tool
439# ----------------------------------------------------------------------
440itcl::configbody Rappture::Loader::tool {
441    if {[catch {$itk_option(-tool) isa Rappture::Tool} valid] || !$valid} {
442        error "object \"$itk_option(-tool)\" is not a Rappture Tool"
443    }
444}
445
446# ----------------------------------------------------------------------
447# CONFIGURATION OPTION: -state
448# ----------------------------------------------------------------------
449itcl::configbody Rappture::Loader::state {
450    set valid {normal disabled}
451    if {[lsearch -exact $valid $itk_option(-state)] < 0} {
452        error "bad value \"$itk_option(-state)\": should be [join $valid {, }]"
453    }
454    $itk_component(combo) configure -state $itk_option(-state)
455}
Note: See TracBrowser for help on using the repository browser.