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

Last change on this file since 50 was 50, checked in by mmc, 19 years ago

Added support for file transfer with the desktop. Each Rappture
application acts like an http server, configured to listen on
a particular port according to the parameters found in the file
~/data/sessions/$SESSION/resources. When the server is active,
the GUI has a "Download..." button in the results area. A Java
client (in the filexfer directory) connects to the server and
listens for download requests. When the user clicks on "Download...",
the desired result is spooled to a file, and a Java client pops up
a web page requesting the file. This downloads the result to the
user's desktop.

Note that if the $SESSION environment variable is not set, these
changes do nothing.

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