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

Last change on this file since 1742 was 1742, checked in by mmc, 14 years ago

Added preview of outputs to the irappture builder. Fixed a problem
with the file chooser for the "save as" dialog. Added a distinction
between errors and warnings when looking for problems in the tool
definition.

Fixed a few problems in RapptureGUI affecting the scroller and the
way it refreshes itself when the frame within it suddenly shrinks.
Fixed the histogram to avoid errors when the histogram data is
empty. Fixed the analyzer so you can create it without setting
the -notebookpage option. All of these errors showed up in the
irappture builder.

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