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 | # ====================================================================== |
---|
13 | package require Itk |
---|
14 | |
---|
15 | option add *Loader.textForeground black widgetDefault |
---|
16 | option add *Loader.textBackground white widgetDefault |
---|
17 | |
---|
18 | itcl::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 | |
---|
46 | itk::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 | # ---------------------------------------------------------------------- |
---|
56 | itcl::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 | # ---------------------------------------------------------------------- |
---|
219 | itcl::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 | # ---------------------------------------------------------------------- |
---|
252 | itcl::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 | # ---------------------------------------------------------------------- |
---|
268 | itcl::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 | # ---------------------------------------------------------------------- |
---|
280 | itcl::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 | # ---------------------------------------------------------------------- |
---|
361 | itcl::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 | # ---------------------------------------------------------------------- |
---|
397 | itcl::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 | # ---------------------------------------------------------------------- |
---|
440 | itcl::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 | # ---------------------------------------------------------------------- |
---|
449 | itcl::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 | } |
---|