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

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