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

Last change on this file since 1208 was 1208, checked in by dkearney, 16 years ago

adding autolabels for Number and Integer so user does not get an error if they forget to add a label to their output number or integer, output.number.about.label for example

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