source: branches/blt4/gui/scripts/analyzer.tcl @ 1759

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