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

Last change on this file since 728 was 728, checked in by mmc, 17 years ago

Fixed the automatic bug reporting system to avoid reporting bugs caught
in a workspace, or in a tool with an explicit <reportJobFailures> set
to 0. We use this for tools like Spice3F4, where we expect lots of
pilot error.

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