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

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