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

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