source: trunk/gui/scripts/analyzer.tcl @ 193

Last change on this file since 193 was 193, checked in by mmc, 19 years ago
  • Added "Upload..." capability to the <loader> widget. You can now add an <upload> directive containing the path of the control that will receive data. A file is uploaded from the desktop and saved in the specified control.
  • Fixed download capability to work properly for all result types, including contour plots and molecules.
  • Added rappture::signal so we can catch SIGHUP and clean up the upload/download spool directory.
File size: 32.3 KB
Line 
1# ----------------------------------------------------------------------
2#  COMPONENT: analyzer - output area for Rappture
3#
4#  This widget acts as the output side of a Rappture application.
5#  When the input has changed, it displays a Simulate button that
6#  launches the simulation.  When a simulation is running, this
7#  area shows status.  When it is finished, the results appear
8#  in place of the button, according to the specs in the <analyze>
9#  XML data.
10# ======================================================================
11#  AUTHOR:  Michael McLennan, Purdue University
12#  Copyright (c) 2004-2005  Purdue Research Foundation
13#
14#  See the file "license.terms" for information on usage and
15#  redistribution of this file, and for a DISCLAIMER OF ALL WARRANTIES.
16# ======================================================================
17package require Itk
18
19option add *Analyzer.width 3.5i widgetDefault
20option add *Analyzer.height 4i widgetDefault
21option add *Analyzer.simControl "auto" widgetDefault
22option add *Analyzer.simControlBackground "" widgetDefault
23option add *Analyzer.simControlOutline gray widgetDefault
24option add *Analyzer.simControlActiveBackground #ffffcc widgetDefault
25option add *Analyzer.simControlActiveOutline black widgetDefault
26
27option add *Analyzer.font \
28    -*-helvetica-medium-r-normal-*-*-120-* widgetDefault
29option add *Analyzer.codeFont \
30    -*-courier-medium-r-normal-*-*-120-* widgetDefault
31option add *Analyzer.textFont \
32    -*-helvetica-medium-r-normal-*-*-120-* widgetDefault
33option add *Analyzer.boldTextFont \
34    -*-helvetica-bold-r-normal-*-*-120-* widgetDefault
35
36itcl::class Rappture::Analyzer {
37    inherit itk::Widget
38
39    itk_option define -codefont codeFont Font ""
40    itk_option define -textfont textFont Font ""
41    itk_option define -boldtextfont boldTextFont Font ""
42    itk_option define -simcontrol simControl SimControl ""
43    itk_option define -simcontroloutline simControlOutline Background ""
44    itk_option define -simcontrolbackground simControlBackground Background ""
45    itk_option define -simcontrolactiveoutline simControlActiveOutline Background ""
46    itk_option define -simcontrolactivebackground simControlActiveBackground Background ""
47    itk_option define -holdwindow holdWindow HoldWindow ""
48
49    constructor {tool args} { # defined below }
50    destructor { # defined below }
51
52    public method simulate {args}
53    public method reset {}
54    public method load {file}
55    public method clear {}
56    public method download {option}
57
58    protected method _plot {args}
59    protected method _reorder {comps}
60    protected method _autoLabel {xmlobj path title cntVar}
61    protected method _fixResult {}
62    protected method _fixSize {}
63    protected method _fixSimControl {}
64    protected method _simState {state args}
65    protected method _simOutput {message}
66
67    private variable _tool ""          ;# belongs to this tool
68    private variable _control "manual" ;# start mode
69    private variable _runs ""          ;# list of XML objects with results
70    private variable _pages 0          ;# number of pages for result sets
71    private variable _label2page       ;# maps output label => result set
72    private variable _plotlist ""      ;# items currently being plotted
73
74    private common job                 ;# array var used for blt::bgexec jobs
75}
76                                                                               
77itk::usual Analyzer {
78    keep -background -cursor foreground -font
79}
80
81# ----------------------------------------------------------------------
82# CONSTRUCTOR
83# ----------------------------------------------------------------------
84itcl::body Rappture::Analyzer::constructor {tool args} {
85    set _tool $tool
86
87    itk_option add hull.width hull.height
88    pack propagate $itk_component(hull) no
89
90    frame $itk_interior.simol -borderwidth 1 -relief flat
91    pack $itk_interior.simol -fill x
92
93    frame $itk_interior.simol.simbg -borderwidth 0
94    pack $itk_interior.simol.simbg -expand yes -fill both
95
96    itk_component add simulate {
97        button $itk_interior.simol.simbg.simulate -text "Simulate" \
98            -command [itcl::code $this simulate]
99    }
100    pack $itk_component(simulate) -side left -padx 4 -pady 4
101
102    itk_component add simstatus {
103        text $itk_interior.simol.simbg.simstatus -borderwidth 0 \
104            -highlightthickness 0 -height 1 -width 1 -wrap none \
105            -state disabled
106    } {
107        usual
108        ignore -highlightthickness
109        rename -font -textfont textFont Font
110    }
111    pack $itk_component(simstatus) -side left -expand yes -fill x
112
113    $itk_component(simstatus) tag configure popup \
114        -underline 1 -foreground blue
115
116    $itk_component(simstatus) tag bind popup \
117        <Enter> {%W configure -cursor center_ptr}
118    $itk_component(simstatus) tag bind popup \
119        <Leave> {%W configure -cursor ""}
120    $itk_component(simstatus) tag bind popup \
121        <ButtonPress> {after idle {Rappture::Tooltip::tooltip show %W}}
122
123
124    itk_component add notebook {
125        Rappture::Notebook $itk_interior.nb
126    }
127    pack $itk_interior.nb -expand yes -fill both
128
129    # ------------------------------------------------------------------
130    # ABOUT PAGE
131    # ------------------------------------------------------------------
132    set w [$itk_component(notebook) insert end about]
133
134    Rappture::Scroller $w.info -xscrollmode off -yscrollmode auto
135    pack $w.info -expand yes -fill both -padx 4 -pady 20
136    itk_component add toolinfo {
137        text $w.info.text -width 1 -height 1 -wrap word \
138            -borderwidth 0 -highlightthickness 0
139    } {
140        usual
141        ignore -borderwidth -relief
142        rename -font -textfont textFont Font
143    }
144    $w.info contents $w.info.text
145
146    # ------------------------------------------------------------------
147    # SIMULATION PAGE
148    # ------------------------------------------------------------------
149    set w [$itk_component(notebook) insert end simulate]
150    frame $w.cntls
151    pack $w.cntls -side bottom -fill x -pady 12
152    frame $w.cntls.sep -background black -height 1
153    pack $w.cntls.sep -side top -fill x
154
155    itk_component add abort {
156        button $w.cntls.abort -text "Abort" \
157            -command [itcl::code $_tool abort]
158    }
159    pack $itk_component(abort) -side left -expand yes -padx 4 -pady 4
160
161    Rappture::Scroller $w.info -xscrollmode auto -yscrollmode auto
162    pack $w.info -expand yes -fill both -padx 4 -pady 4
163    itk_component add runinfo {
164        text $w.info.text -width 1 -height 1 -wrap none \
165            -borderwidth 0 -highlightthickness 0 \
166            -state disabled
167    } {
168        usual
169        ignore -borderwidth -relief
170        rename -font -codefont codeFont Font
171    }
172    $w.info contents $w.info.text
173
174    itk_component add progress {
175        Rappture::Progress $w.progress
176    }
177
178    # ------------------------------------------------------------------
179    # ANALYZE PAGE
180    # ------------------------------------------------------------------
181    set w [$itk_component(notebook) insert end analyze]
182
183    frame $w.top
184    pack $w.top -side top -fill x -pady 8
185    label $w.top.l -text "Result:" -font $itk_option(-font)
186    pack $w.top.l -side left
187
188    itk_component add resultselector {
189        Rappture::Combobox $w.top.sel -width 10 -editable no
190    } {
191        usual
192        rename -font -textfont textFont Font
193    }
194    pack $itk_component(resultselector) -side left -expand yes -fill x
195    bind $itk_component(resultselector) <<Value>> [itcl::code $this _fixResult]
196
197    if {[Rappture::filexfer::enabled]} {
198        itk_component add download {
199            button $w.top.dl -text "Download..." -anchor w \
200                -command [itcl::code $this download now]
201        }
202        pack $itk_component(download) -side right -padx {4 0}
203        Rappture::Tooltip::for $itk_component(download) "Downloads the current result to a new web browser window on your desktop.  From there, you can easily print or save results.
204
205NOTE:  Your web browser must allow pop-ups from this site.  If your output does not appear, look for a 'pop-up blocked' message and enable pop-ups."
206
207        bind $itk_component(download) <Enter> \
208            [itcl::code $this download coming]
209    }
210
211    itk_component add results {
212        Rappture::Panes $w.pane
213    }
214    pack $itk_component(results) -expand yes -fill both
215    set f [$itk_component(results) pane 0]
216
217    itk_component add resultpages {
218        Rappture::Notebook $f.nb
219    }
220    pack $itk_component(resultpages) -expand yes -fill both
221
222    set f [$itk_component(results) insert end -fraction 0.1]
223    itk_component add resultset {
224        Rappture::ResultSet $f.rset \
225            -clearcommand [itcl::code $this clear] \
226            -settingscommand [itcl::code $this _plot] \
227            -promptcommand [itcl::code $this _simState]
228    }
229    pack $itk_component(resultset) -expand yes -fill both
230    bind $itk_component(resultset) <<Control>> [itcl::code $this _fixSize]
231
232    eval itk_initialize $args
233
234    $itk_component(runinfo) tag configure ERROR -foreground red
235    $itk_component(runinfo) tag configure text -font $itk_option(-textfont)
236
237    #
238    # Load up tool info on the first page.
239    #
240    $itk_component(toolinfo) tag configure title \
241        -font $itk_option(-boldtextfont)
242
243    set mesg [$tool xml get tool.title]
244    if {"" != $mesg} {
245        $itk_component(toolinfo) insert end $mesg title
246        $itk_component(toolinfo) insert end "\n\n"
247    }
248
249    set mesg [$tool xml get tool.about]
250    if {"" != $mesg} {
251        $itk_component(toolinfo) insert end $mesg
252    }
253    $itk_component(toolinfo) configure -state disabled
254    $itk_component(notebook) current about
255
256    # tool can run on "manual" (default) or "auto"
257    set cntl [$tool xml get tool.control]
258    if {"" == $cntl} {
259        set cntl [$tool xml get tool.control.type]
260    }
261    if {"" != $cntl} {
262        set _control $cntl
263    }
264
265    # reset everything to a clean state
266    reset
267}
268
269# ----------------------------------------------------------------------
270# DESTRUCTOR
271# ----------------------------------------------------------------------
272itcl::body Rappture::Analyzer::destructor {} {
273    foreach obj $_runs {
274        itcl::delete object $obj
275    }
276    after cancel [itcl::code $this simulate]
277}
278
279# ----------------------------------------------------------------------
280# USAGE: simulate ?-ifneeded?
281# USAGE: simulate ?<path1> <value1> <path2> <value2> ...?
282#
283# Kicks off the simulator by executing the tool.command associated
284# with the tool.  If any arguments are specified, they are used to
285# set parameters for the simulation.  While the simulation is running,
286# it shows status.  When the simulation is finished, it switches
287# automatically to "analyze" mode and shows the results.
288# ----------------------------------------------------------------------
289itcl::body Rappture::Analyzer::simulate {args} {
290    if {$args == "-ifneeded"} {
291        # check to see if simulation is really needed
292        $_tool sync
293        if {[$itk_component(resultset) contains [$_tool xml object]]} {
294            # not needed -- show results and return
295            $itk_component(notebook) current analyze
296            return
297        }
298        set args ""
299    }
300
301    # simulation is needed -- go to simulation page
302    $itk_component(notebook) current simulate
303
304    # no progress messages yet
305    pack forget $itk_component(progress)
306    lappend args -output [itcl::code $this _simOutput]
307
308    _simState off
309    $itk_component(runinfo) configure -state normal
310    $itk_component(runinfo) delete 1.0 end
311    $itk_component(runinfo) insert end "Running simulation...\n\n" text
312    $itk_component(runinfo) configure -state disabled
313
314    # if the hold window is set, then put up a busy cursor
315    if {$itk_option(-holdwindow) != ""} {
316        blt::busy hold $itk_option(-holdwindow)
317        raise $itk_component(hull)
318        update
319    }
320
321    # execute the job
322    foreach {status result} [eval $_tool run $args] break
323
324    # if job was aborted, then allow simulation again
325    if {$result == "ABORT"} {
326        _simState on "Aborted"
327    }
328
329    # read back the results from run.xml
330    if {$status == 0 && $result != "ABORT"} {
331        if {[regexp {=RAPPTURE-RUN=>([^\n]+)} $result match file]} {
332            set status [catch {load $file} msg]
333            if {$status != 0} {
334                global errorInfo
335                set result "$msg\n$errorInfo"
336            }
337        } else {
338            set status 1
339            set result "Can't find result file in output:\n\n$result"
340        }
341    }
342
343    # back to normal
344    if {$itk_option(-holdwindow) != ""} {
345        blt::busy release $itk_option(-holdwindow)
346    }
347    $itk_component(abort) configure -state disabled
348
349    if {$status != 0} {
350        $itk_component(runinfo) configure -state normal
351        $itk_component(runinfo) delete 1.0 end
352        $itk_component(runinfo) insert end "Problem launching job:\n\n" text
353        _simOutput $result
354        $itk_component(runinfo) configure -state disabled
355        $itk_component(runinfo) see 1.0
356    } else {
357        $itk_component(notebook) current analyze
358    }
359
360    # do this last -- after _simOutput above
361    pack forget $itk_component(progress)
362}
363
364# ----------------------------------------------------------------------
365# USAGE: reset
366#
367# Used to reset the analyzer whenever the input to a simulation has
368# changed.  Sets the mode back to "simulate", so the user has to
369# simulate again to see the output.  If the <start> option is set
370# to "auto", the simulation is invoked immediately.
371# ----------------------------------------------------------------------
372itcl::body Rappture::Analyzer::reset {} {
373    # check to see if simulation is really needed
374    $_tool sync
375    if {![$itk_component(resultset) contains [$_tool xml object]]} {
376        # if control mode is "auto", then simulate right away
377        if {[string match auto* $_control]} {
378            # auto control -- don't need button
379            pack forget $itk_interior.simol
380
381            after cancel [itcl::code $this simulate]
382            after idle [itcl::code $this simulate]
383        } else {
384            _simState on "new input parameters"
385        }
386    } else {
387        _simState off
388    }
389}
390
391# ----------------------------------------------------------------------
392# USAGE: load <file>
393#
394# Loads the data from the given <file> into the appropriate results
395# sets.  If necessary, new results sets are created to store the data.
396# ----------------------------------------------------------------------
397itcl::body Rappture::Analyzer::load {file} {
398    # only show the last result? then clear first
399    if {[$_tool xml get tool.analyzer] == "last"} {
400        clear
401    }
402
403    # try to load new results from the given file
404    set xmlobj [Rappture::library $file]
405    lappend _runs $xmlobj
406
407    # go through the analysis and find all result sets
408    set haveresults 0
409    foreach item [_reorder [$xmlobj children output]] {
410        switch -glob -- $item {
411            log* {
412                _autoLabel $xmlobj output.$item "Output Log" counters
413            }
414            string* {
415                _autoLabel $xmlobj output.$item "String" counters
416            }
417            curve* - field* {
418                _autoLabel $xmlobj output.$item "Plot" counters
419            }
420            structure* {
421                _autoLabel $xmlobj output.$item "Structure" counters
422            }
423            table* {
424                _autoLabel $xmlobj output.$item "Energy Levels" counters
425            }
426        }
427        set label [$xmlobj get output.$item.about.group]
428        if {"" == $label} {
429            set label [$xmlobj get output.$item.about.label]
430        }
431
432        set hidden [$xmlobj get output.$item.hide]
433        set hidden [expr {"" != $hidden && $hidden}]
434
435        if {"" != $label && !$hidden} {
436            set haveresults 1
437        }
438    }
439
440    # if there are any valid results, add them to the resultset
441    if {$haveresults} {
442        set size [$itk_component(resultset) size]
443        set index [$itk_component(resultset) add $xmlobj]
444
445        # add each result to a result viewer
446        foreach item [_reorder [$xmlobj children output]] {
447            set label [$xmlobj get output.$item.about.group]
448            if {"" == $label} {
449                set label [$xmlobj get output.$item.about.label]
450            }
451
452            set hidden [$xmlobj get output.$item.hide]
453            set hidden [expr {"" != $hidden && $hidden}]
454
455            if {"" != $label && !$hidden} {
456                if {![info exists _label2page($label)]} {
457                    set name "page[incr _pages]"
458                    set page [$itk_component(resultpages) insert end $name]
459                    set _label2page($label) $page
460                    Rappture::ResultViewer $page.rviewer
461                    pack $page.rviewer -expand yes -fill both -pady 4
462
463                    $itk_component(resultselector) choices insert end \
464                        $name $label
465                }
466
467                # add/replace the latest result into this viewer
468                set page $_label2page($label)
469
470                if {![info exists reset($page)]} {
471                    $page.rviewer clear $index
472                    set reset($page) 1
473                }
474                $page.rviewer add $index $xmlobj output.$item
475            }
476        }
477    }
478
479    # show the first page by default
480    set first [$itk_component(resultselector) choices get -label 0]
481    if {$first != ""} {
482        set page [$itk_component(resultselector) choices get -value 0]
483        $itk_component(resultpages) current $page
484        $itk_component(resultselector) value $first
485    }
486}
487
488# ----------------------------------------------------------------------
489# USAGE: clear
490#
491# Discards all results previously loaded into the analyzer.
492# ----------------------------------------------------------------------
493itcl::body Rappture::Analyzer::clear {} {
494    foreach obj $_runs {
495        itcl::delete object $obj
496    }
497    set _runs ""
498
499    $itk_component(resultset) clear
500    $itk_component(results) fraction end 0.1
501
502    foreach label [array names _label2page] {
503        set page $_label2page($label)
504        $page.rviewer clear
505    }
506    $itk_component(resultselector) value ""
507    $itk_component(resultselector) choices delete 0 end
508    catch {unset _label2page}
509    set _plotlist ""
510
511    #
512    # HACK ALERT!!
513    # The following statement should be in place, but it causes
514    # vtk to dump core.  Leave it out until we can fix the core dump.
515    # In the mean time, we leak memory...
516    #
517    #$itk_component(resultpages) delete -all
518    #set _pages 0
519
520    _simState on
521    _fixSimControl
522    reset
523}
524
525# ----------------------------------------------------------------------
526# USAGE: download coming
527# USAGE: download now
528#
529# Spools the current result so the user can download it.
530# ----------------------------------------------------------------------
531itcl::body Rappture::Analyzer::download {option} {
532    if {[Rappture::filexfer::enabled]} {
533        set title [$itk_component(resultselector) value]
534        set page [$itk_component(resultselector) translate $title]
535
536        switch -- $option {
537            coming {
538                #
539                # Warn result that a download is coming, in case
540                # it needs to take a screen snap.
541                #
542                if {$page != ""} {
543                    set f [$itk_component(resultpages) page $page]
544                    $f.rviewer download coming
545                }
546            }
547            now {
548                #
549                # Perform the actual download.
550                #
551                if {$page != ""} {
552                    set ext ""
553                    set f [$itk_component(resultpages) page $page]
554                    foreach {ext data} [$f.rviewer download now] break
555                    if {"" == $ext} {
556                        Rappture::Tooltip::cue $itk_component(download) \
557                            "Can't download this result."
558                        return
559                    }
560                    regsub -all {[\ -\/\:-\@\{-\~]} $title {} title
561                    set file "$title$ext"
562                } else {
563                    # this shouldn't happen
564                    set file error.html
565                    set data "<h1>Not Found</h1>There is no result selected."
566                }
567
568                if {[catch {Rappture::filexfer::spool $data $file} result]} {
569                    if {"no clients" == $result} {
570                        Rappture::Tooltip::cue $itk_component(download) \
571                            "Can't download this result.  Looks like you might be having trouble with the version of Java installed for your browser."
572                    } else {
573                        error $result "    (while spooling result \"$title\")"
574                    }
575                }
576            }
577            default {
578                error "bad option \"$option\": should be coming, now"
579            }
580        }
581    }
582}
583
584# ----------------------------------------------------------------------
585# USAGE: _plot ?<index> <options> <index> <options>...?
586#
587# Used internally to update the plot shown in the current result
588# viewer whenever the resultset settings have changed.  Causes the
589# desired results to show up on screen.
590# ----------------------------------------------------------------------
591itcl::body Rappture::Analyzer::_plot {args} {
592    set _plotlist $args
593
594    set page [$itk_component(resultselector) value]
595    set page [$itk_component(resultselector) translate $page]
596    if {"" != $page} {
597        set f [$itk_component(resultpages) page $page]
598        $f.rviewer plot clear
599        foreach {index opts} $_plotlist {
600            $f.rviewer plot add $index $opts
601        }
602    }
603}
604
605# ----------------------------------------------------------------------
606# USAGE: _reorder <compList>
607#
608# Used internally to change the order of a series of output components
609# found in the <output> section.  Moves the <log> elements to the end
610# and returns the updated list.
611# ----------------------------------------------------------------------
612itcl::body Rappture::Analyzer::_reorder {comps} {
613    set i 0
614    set max [llength $comps]
615    while {$i < $max} {
616        set c [lindex $comps $i]
617        if {[string match log* $c]} {
618            set comps [lreplace $comps $i $i]
619            lappend comps $c
620            incr max -1
621        } else {
622            incr i
623        }
624    }
625    return $comps
626}
627
628# ----------------------------------------------------------------------
629# USAGE: _autoLabel <xmlobj> <path> <title> <cntVar>
630#
631# Used internally to check for an about.label property at the <path>
632# in <xmlobj>.  If this object doesn't have a label, then one is
633# supplied using the given <title>.  The <cntVar> is an array of
634# counters in the calling scopes for titles that have been used
635# in the past.  This is used to create titles like "Plot #2" the
636# second time it is encountered.
637#
638# The <xmlobj> is updated so that the label is inserted directly in
639# the tree.
640# ----------------------------------------------------------------------
641itcl::body Rappture::Analyzer::_autoLabel {xmlobj path title cntVar} {
642    upvar $cntVar counters
643
644    set group [$xmlobj get $path.about.group]
645    set label [$xmlobj get $path.about.label]
646    if {"" == $label} {
647        # no label -- make one up using the title specified
648        if {![info exists counters($group-$title)]} {
649            set counters($group-$title) 1
650            set label $title
651        } else {
652            set label "$title (#[incr counters($group-$title)])"
653        }
654        $xmlobj put $path.about.label $label
655    } else {
656        # handle the case of two identical labels in <output>
657        if {![info exists counters($group-$label)]} {
658            set counters($group-$label) 1
659        } else {
660            set label "$label (#[incr counters($group-$label)])"
661            $xmlobj put $path.about.label $label
662        }
663    }
664    return $label
665}
666
667# ----------------------------------------------------------------------
668# USAGE: _fixResult
669#
670# Used internally to change the result page being displayed whenever
671# the user selects a page from the results combobox.
672# ----------------------------------------------------------------------
673itcl::body Rappture::Analyzer::_fixResult {} {
674    set page [$itk_component(resultselector) value]
675    set page [$itk_component(resultselector) translate $page]
676    if {$page != ""} {
677        blt::busy hold [winfo toplevel $itk_component(hull)]; update idletasks
678        $itk_component(resultpages) current $page
679
680        set f [$itk_component(resultpages) page $page]
681        $f.rviewer plot clear
682        eval $f.rviewer plot add $_plotlist
683        blt::busy release [winfo toplevel $itk_component(hull)]
684    }
685}
686
687# ----------------------------------------------------------------------
688# USAGE: _fixSize
689#
690# Used internally to change the size of the result set area whenever
691# a new control appears.  Adjusts the size available for the result
692# set up to some maximum.
693# ----------------------------------------------------------------------
694itcl::body Rappture::Analyzer::_fixSize {} {
695    set f [$itk_component(results) fraction end]
696    if {$f < 0.4} {
697        $itk_component(results) fraction end [expr {$f+0.15}]
698    }
699    _fixSimControl
700}
701
702# ----------------------------------------------------------------------
703# USAGE: _simState <boolean> ?<message>? ?<settings>?
704#
705# Used internally to change the "Simulation" button on or off.
706# If the <boolean> is on, then any <message> and <settings> are
707# displayed as well.  The <message> is a note to the user about
708# what will be simulated, and the <settings> are a list of
709# tool parameter settings of the form {path1 val1 path2 val2 ...}.
710# When these are in place, the next Simulate operation will use
711# these settings.  This helps fill in missing data values.
712# ----------------------------------------------------------------------
713itcl::body Rappture::Analyzer::_simState {state args} {
714    if {$state} {
715        $itk_interior.simol configure \
716            -background $itk_option(-simcontrolactiveoutline)
717        $itk_interior.simol.simbg configure \
718            -background $itk_option(-simcontrolactivebackground)
719        $itk_component(simulate) configure \
720            -highlightbackground $itk_option(-simcontrolactivebackground)
721        $itk_component(simstatus) configure \
722            -background $itk_option(-simcontrolactivebackground)
723
724        $itk_component(abort) configure -state disabled
725        $itk_component(simulate) configure -state normal \
726            -command [itcl::code $this simulate]
727
728        #
729        # If there's a special message, then put it up next to the button.
730        #
731        set mesg [lindex $args 0]
732        if {"" != $mesg} {
733            $itk_component(simstatus) configure -state normal
734            $itk_component(simstatus) delete 1.0 end
735            $itk_component(simstatus) insert end $mesg
736
737            #
738            # If there are any settings, then install them in the
739            # "Simulate" button.  Also, pop them up as a tooltip
740            # for the message.
741            #
742            set settings [lindex $args 1]
743            if {[llength $settings] > 0} {
744                $itk_component(simulate) configure \
745                    -command [eval itcl::code $this simulate $settings]
746
747                set details ""
748                foreach {path val} $settings {
749                    set str [$_tool xml get $path.about.label]
750                    if {"" == $str} {
751                        set str [$_tool xml element -as id $path]
752                    }
753                    append details "$str = $val\n"
754                }
755                set details [string trim $details]
756
757                Rappture::Tooltip::for $itk_component(simstatus) $details
758                $itk_component(simstatus) insert end " "
759                $itk_component(simstatus) insert end "(details...)" popup
760            }
761            $itk_component(simstatus) configure -state disabled
762        }
763    } else {
764        if {"" != $itk_option(-simcontrolbackground)} {
765            set simcbg $itk_option(-simcontrolbackground)
766        } else {
767            set simcbg $itk_option(-background)
768        }
769        $itk_interior.simol configure \
770            -background $itk_option(-simcontroloutline)
771        $itk_interior.simol.simbg configure -background $simcbg
772        $itk_component(simulate) configure -highlightbackground $simcbg
773        $itk_component(simstatus) configure -background $simcbg
774
775        $itk_component(simulate) configure -state disabled
776        $itk_component(abort) configure -state normal
777
778        $itk_component(simstatus) configure -state normal
779        $itk_component(simstatus) delete 1.0 end
780        $itk_component(simstatus) configure -state disabled
781        Rappture::Tooltip::for $itk_component(simstatus) ""
782    }
783}
784
785# ----------------------------------------------------------------------
786# USAGE: _simOutput <message>
787#
788# Invoked automatically whenever output comes in while running the
789# tool.  Extracts any =RAPPTURE-???=> messages from the output and
790# sends the output to the display.  For example, any
791# =RAPPTURE-PROGRESS=> message pops up the progress meter and updates
792# it to show the latest progress message.  This is useful for
793# long-running tools, to let the user know how much longer the
794# simulation will take.
795# ----------------------------------------------------------------------
796itcl::body Rappture::Analyzer::_simOutput {message} {
797    #
798    # Scan through and pick out any =RAPPTURE-PROGRESS=> messages first.
799    #
800    while {[regexp -indices \
801               {=RAPPTURE-PROGRESS=>([0-9]+) +([^\n]*)(\n|$)} $message \
802                match percent mesg]} {
803
804        foreach {i0 i1} $percent break
805        set percent [string range $message $i0 $i1]
806
807        foreach {i0 i1} $mesg break
808        set mesg [string range $message $i0 $i1]
809
810        pack $itk_component(progress) -fill x -padx 10 -pady 10
811        $itk_component(progress) settings -percent $percent -message $mesg
812
813        foreach {i0 i1} $match break
814        set message [string replace $message $i0 $i1]
815    }
816
817    #
818    # Break up the remaining lines according to =RAPPTURE-ERROR=> messages.
819    # Show errors in a special color.
820    #
821    $itk_component(runinfo) configure -state normal
822
823    while {[regexp -indices \
824               {=RAPPTURE-([a-zA-Z]+)=>([^\n]*)(\n|$)} $message \
825                match type mesg]} {
826
827        foreach {i0 i1} $match break
828        set first [string range $message 0 [expr {$i0-1}]]
829        if {[string length $first] > 0} {
830            $itk_component(runinfo) insert end $first
831            $itk_component(runinfo) insert end \n
832        }
833
834        foreach {t0 t1} $type break
835        set type [string range $message $t0 $t1]
836        foreach {m0 m1} $mesg break
837        set mesg [string range $message $m0 $m1]
838        if {[string length $mesg] > 0 && $type != "RUN"} {
839            $itk_component(runinfo) insert end $mesg $type
840            $itk_component(runinfo) insert end \n $type
841        }
842
843        set message [string range $message [expr {$i1+1}] end]
844    }
845
846    if {[string length $message] > 0} {
847        $itk_component(runinfo) insert end $message
848        if {[$itk_component(runinfo) get end-2char] != "\n"} {
849            $itk_component(runinfo) insert end "\n"
850        }
851        $itk_component(runinfo) see end
852    }
853    $itk_component(runinfo) configure -state disabled
854}
855
856# ----------------------------------------------------------------------
857# USAGE: _fixSimControl
858#
859# Used internally to add or remove the simulation control at the
860# top of the analysis area.  This is controlled by the -simcontrol
861# option.
862# ----------------------------------------------------------------------
863itcl::body Rappture::Analyzer::_fixSimControl {} {
864    switch -- $itk_option(-simcontrol) {
865        on {
866            pack $itk_interior.simol -fill x -before $itk_interior.nb
867        }
868        off {
869            pack forget $itk_interior.simol
870        }
871        auto {
872            #
873            # If we have two or more radiodials, then there is a
874            # chance of encountering a combination of parameters
875            # with no data, requiring simulation.
876            #
877            if {[$itk_component(resultset) size -controls] >= 2} {
878                pack $itk_interior.simol -fill x -before $itk_interior.nb
879            } else {
880                pack forget $itk_interior.simol
881            }
882        }
883        default {
884            error "bad value \"$itk_option(-simcontrol)\": should be on, off, auto"
885        }
886    }
887}
888
889# ----------------------------------------------------------------------
890# CONFIGURATION OPTION: -simcontrol
891#
892# Controls whether or not the Simulate button is showing.  In some
893# cases, it is not needed.
894# ----------------------------------------------------------------------
895itcl::configbody Rappture::Analyzer::simcontrol {
896    _fixSimControl
897}
Note: See TracBrowser for help on using the repository browser.