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

Last change on this file since 822 was 822, checked in by gah, 13 years ago
File size: 39.5 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 {{when -eventually}}
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              && ![string equal $_control "manual-resim"]} {
321            # not needed -- show results and return
322            $itk_component(notebook) current analyze
323            return
324        }
325        set args ""
326    }
327
328    # simulation is needed -- go to simulation page
329    $itk_component(notebook) current simulate
330
331    # no progress messages yet
332    pack forget $itk_component(progress)
333    lappend args -output [itcl::code $this _simOutput]
334
335    _simState off
336    $itk_component(runinfo) configure -state normal
337    $itk_component(runinfo) delete 1.0 end
338    $itk_component(runinfo) insert end "Running simulation...\n\n" text
339    $itk_component(runinfo) configure -state disabled
340
341    # if the hold window is set, then put up a busy cursor
342    if {$itk_option(-holdwindow) != ""} {
343        blt::busy hold $itk_option(-holdwindow)
344        raise $itk_component(hull)
345        update
346    }
347
348    # execute the job
349    foreach {status result} [eval $_tool run $args] break
350
351    # if job was aborted, then allow simulation again
352    if {$result == "ABORT"} {
353        _simState on "Aborted"
354    }
355
356    # read back the results from run.xml
357    if {$status == 0 && $result != "ABORT"} {
358        if {[regexp {=RAPPTURE-RUN=>([^\n]+)} $result match file]} {
359            set status [catch {load $file} msg]
360            if {$status != 0} {
361                global errorInfo
362                set result "$msg\n$errorInfo"
363            }
364
365            # if there's a results_directory defined in the resources
366            # file, then move the run.xml file there for storage
367            if {"" != $_resultdir} {
368                catch {
369                    if {![file exists $_resultdir]} {
370                        _mkdir $_resultdir
371                    }
372                    file rename -force -- $file $_resultdir
373                }
374            }
375        } else {
376            set status 1
377            set result "Can't find result file in output.\nDid you call Rappture::result in your simulator?"
378        }
379    }
380
381    # back to normal
382    if {$itk_option(-holdwindow) != ""} {
383        blt::busy release $itk_option(-holdwindow)
384    }
385    $itk_component(abort) configure -state disabled
386
387    if {$status != 0} {
388        $itk_component(runinfo) configure -state normal
389        $itk_component(runinfo) delete 1.0 end
390        $itk_component(runinfo) insert end "Problem launching job:\n\n" text
391        _simOutput $result
392        $itk_component(runinfo) configure -state disabled
393        $itk_component(runinfo) see 1.0
394
395        # Try to create a support ticket for this error.
396        # It may be a real problem.
397        if {[Rappture::bugreport::shouldReport for jobs]} {
398            Rappture::bugreport::register "Problem launching job:\n\n$result\n== RAPPTURE INPUT ==\n[$_tool xml xml]"
399        }
400    } else {
401        $itk_component(notebook) current analyze
402    }
403
404    # do this last -- after _simOutput above
405    pack forget $itk_component(progress)
406}
407
408# ----------------------------------------------------------------------
409# USAGE: reset ?-eventually|-now?
410#
411# Used to reset the analyzer whenever the input to a simulation has
412# changed.  Sets the mode back to "simulate", so the user has to
413# simulate again to see the output.  If the <start> option is set
414# to "auto", the simulation is invoked immediately.
415# ----------------------------------------------------------------------
416itcl::body Rappture::Analyzer::reset {{when -eventually}} {
417    if {$when == "-eventually"} {
418        after cancel [list catch [itcl::code $this reset -now]]
419        after idle [list catch [itcl::code $this reset -now]]
420        return
421    }
422
423    # check to see if simulation is really needed
424    $_tool sync
425    if {![$itk_component(resultset) contains [$_tool xml object]]
426          || [string equal $_control "manual-resim"]} {
427        # if control mode is "auto", then simulate right away
428        if {[string match auto* $_control]} {
429            # auto control -- don't need button
430            pack forget $itk_interior.simol
431
432            after cancel [itcl::code $this simulate]
433            after idle [itcl::code $this simulate]
434        } else {
435            _simState on "new input parameters"
436        }
437    } else {
438        _simState off
439    }
440}
441
442# ----------------------------------------------------------------------
443# USAGE: load <file>
444#
445# Loads the data from the given <file> into the appropriate results
446# sets.  If necessary, new results sets are created to store the data.
447# ----------------------------------------------------------------------
448itcl::body Rappture::Analyzer::load {file} {
449    # only show the last result? then clear first
450    if {[$_tool xml get tool.analyzer] == "last"} {
451        clear
452    }
453
454    # try to load new results from the given file
455    set xmlobj [Rappture::library $file]
456    lappend _runs $xmlobj
457
458    # go through the analysis and find all result sets
459    set haveresults 0
460    foreach item [_reorder [$xmlobj children output]] {
461        switch -glob -- $item {
462            log* {
463                _autoLabel $xmlobj output.$item "Output Log" counters
464            }
465            string* {
466                _autoLabel $xmlobj output.$item "String" counters
467            }
468            histogram* - curve* - field* {
469                _autoLabel $xmlobj output.$item "Plot" counters
470            }
471            structure* {
472                _autoLabel $xmlobj output.$item "Structure" counters
473            }
474            table* {
475                _autoLabel $xmlobj output.$item "Energy Levels" counters
476            }
477            sequence* {
478                _autoLabel $xmlobj output.$item "Sequence" counters
479            }
480        }
481        set label [$xmlobj get output.$item.about.group]
482        if {"" == $label} {
483            set label [$xmlobj get output.$item.about.label]
484        }
485
486        set hidden [$xmlobj get output.$item.hide]
487        set hidden [expr {"" != $hidden && $hidden}]
488
489        if {"" != $label && !$hidden} {
490            set haveresults 1
491        }
492    }
493
494    # if there are any valid results, add them to the resultset
495    if {$haveresults} {
496        set index [$itk_component(resultset) add $xmlobj]
497
498        # add each result to a result viewer
499        foreach item [_reorder [$xmlobj children output]] {
500            set label [$xmlobj get output.$item.about.group]
501            if {"" == $label} {
502                set label [$xmlobj get output.$item.about.label]
503            }
504
505            set hidden [$xmlobj get output.$item.hide]
506            set hidden [expr {"" != $hidden && $hidden}]
507
508            if {"" != $label && !$hidden} {
509                if {![info exists _label2page($label)]} {
510                    set name "page[incr _pages]"
511                    set page [$itk_component(resultpages) insert end $name]
512                    set _label2page($label) $page
513                    set _label2desc($label) \
514                        [$xmlobj get output.$item.about.description]
515                    Rappture::ResultViewer $page.rviewer
516                    pack $page.rviewer -expand yes -fill both -pady 4
517
518                    set end [$itk_component(resultselector) \
519                        choices index -value ---]
520                    if {$end < 0} {
521                        set end "end"
522                    }
523                    $itk_component(resultselector) choices insert $end \
524                        $name $label
525                }
526
527                # add/replace the latest result into this viewer
528                set page $_label2page($label)
529
530                if {![info exists reset($page)]} {
531                    $page.rviewer clear $index
532                    set reset($page) 1
533                }
534                $page.rviewer add $index $xmlobj output.$item
535            }
536        }
537    }
538
539    # show the first page by default
540    set max [$itk_component(resultselector) choices size]
541    for {set i 0} {$i < $max} {incr i} {
542        set first [$itk_component(resultselector) choices get -label $i]
543        if {$first != ""} {
544            set page [$itk_component(resultselector) choices get -value $i]
545            set char [string index $page 0]
546            if {$char != "@" && $char != "-"} {
547                $itk_component(resultpages) current $page
548                $itk_component(resultselector) value $first
549                set _lastlabel $first
550                break
551            }
552        }
553    }
554}
555
556# ----------------------------------------------------------------------
557# USAGE: clear
558#
559# Discards all results previously loaded into the analyzer.
560# ----------------------------------------------------------------------
561itcl::body Rappture::Analyzer::clear {} {
562    foreach obj $_runs {
563        itcl::delete object $obj
564    }
565    set _runs ""
566
567    $itk_component(resultset) clear
568
569    # reset the size of the controls area
570    set ht [winfo height $itk_component(results)]
571    set cntlht [$itk_component(resultset) size -controlarea]
572    set frac [expr {double($cntlht)/$ht}]
573    $itk_component(results) fraction end $frac
574
575    foreach label [array names _label2page] {
576        set page $_label2page($label)
577        $page.rviewer clear
578    }
579    $itk_component(resultselector) value ""
580    $itk_component(resultselector) choices delete 0 end
581    catch {unset _label2page}
582    catch {unset _label2desc}
583    set _plotlist ""
584
585    if {[Rappture::filexfer::enabled]} {
586        $itk_component(resultselector) choices insert end \
587            --- "---"
588        $itk_component(resultselector) choices insert end \
589            @download "Download..."
590    }
591    set _lastlabel ""
592
593    #
594    # HACK ALERT!!
595    # The following statement should be in place, but it causes
596    # vtk to dump core.  Leave it out until we can fix the core dump.
597    # In the mean time, we leak memory...
598    #
599    #$itk_component(resultpages) delete -all
600    #set _pages 0
601
602    _simState on
603    _fixSimControl
604    reset
605}
606
607# ----------------------------------------------------------------------
608# USAGE: download coming
609# USAGE: download controls <downloadCommand>
610# USAGE: download start ?widget?
611# USAGE: download now ?widget?
612#
613# Spools the current result so the user can download it.
614# ----------------------------------------------------------------------
615itcl::body Rappture::Analyzer::download {option args} {
616    if {[Rappture::filexfer::enabled]} {
617        set title [$itk_component(resultselector) value]
618        set page [$itk_component(resultselector) translate $title]
619
620        switch -- $option {
621            coming {
622                #
623                # Warn result that a download is coming, in case
624                # it needs to take a screen snap.
625                #
626                if {![regexp {^(|@download|---)$} $page]} {
627                    set f [$itk_component(resultpages) page $page]
628                    $f.rviewer download coming
629                }
630            }
631            controls {
632                # no controls for this download yet
633                return ""
634            }
635            start {
636                set widget $itk_component(download)
637                if {[llength $args] > 0} {
638                    set widget [lindex $args 0]
639                    if {[catch {winfo class $widget}]} {
640                        set widget $itk_component(download)
641                    }
642                }
643                #
644                # See if this download has any controls.  If so, then
645                # post them now and let the user continue the download
646                # after selecting a file format.
647                #
648                if {$page != ""} {
649                    set ext ""
650                    set f [$itk_component(resultpages) page $page]
651                    set popup [$f.rviewer download controls \
652                        [itcl::code $this download now $widget]]
653
654                    if {"" != $popup} {
655                        $popup activate $widget below
656                    } else {
657                        download now $widget
658                    }
659                } else {
660                    # this shouldn't happen
661                    set file error.html
662                    set data "<h1>Not Found</h1>There is no result selected."
663                }
664            }
665            now {
666                set widget $itk_component(download)
667                if {[llength $args] > 0} {
668                    set widget [lindex $args 0]
669                    if {[catch {winfo class $widget}]} {
670                        set widget $itk_component(download)
671                    }
672                }
673                #
674                # Perform the actual download.
675                #
676                if {$page != ""} {
677                    set ext ""
678                    set f [$itk_component(resultpages) page $page]
679                    foreach {ext data} [$f.rviewer download now] break
680                    if {"" == $ext} {
681                        if {"" != $widget} {
682                            Rappture::Tooltip::cue $widget \
683                                "Can't download this result."
684                        }
685                        return
686                    }
687                    regsub -all {[\ -\/\:-\@\{-\~]} $title {} title
688                    set file "$title$ext"
689                } else {
690                    # this shouldn't happen
691                    set file error.html
692                    set data "<h1>Not Found</h1>There is no result selected."
693                }
694
695                set mesg [Rappture::filexfer::download $data $file]
696                if {[string length $mesg] > 0} {
697                    Rappture::Tooltip::cue $widget $mesg
698                }
699            }
700            default {
701                error "bad option \"$option\": should be coming, controls, now, start"
702            }
703        }
704    }
705}
706
707# ----------------------------------------------------------------------
708# USAGE: _plot ?<index> <options> <index> <options>...?
709#
710# Used internally to update the plot shown in the current result
711# viewer whenever the resultset settings have changed.  Causes the
712# desired results to show up on screen.
713# ----------------------------------------------------------------------
714itcl::body Rappture::Analyzer::_plot {args} {
715    set _plotlist $args
716
717    set page [$itk_component(resultselector) value]
718    set page [$itk_component(resultselector) translate $page]
719    if {"" != $page} {
720        set f [$itk_component(resultpages) page $page]
721        $f.rviewer plot clear
722        foreach {index opts} $_plotlist {
723            $f.rviewer plot add $index $opts
724        }
725    }
726}
727
728# ----------------------------------------------------------------------
729# USAGE: _reorder <compList>
730#
731# Used internally to change the order of a series of output components
732# found in the <output> section.  Moves the <log> elements to the end
733# and returns the updated list.
734# ----------------------------------------------------------------------
735itcl::body Rappture::Analyzer::_reorder {comps} {
736    set i 0
737    set max [llength $comps]
738    while {$i < $max} {
739        set c [lindex $comps $i]
740        if {[string match log* $c]} {
741            set comps [lreplace $comps $i $i]
742            lappend comps $c
743            incr max -1
744        } else {
745            incr i
746        }
747    }
748    return $comps
749}
750
751# ----------------------------------------------------------------------
752# USAGE: _autoLabel <xmlobj> <path> <title> <cntVar>
753#
754# Used internally to check for an about.label property at the <path>
755# in <xmlobj>.  If this object doesn't have a label, then one is
756# supplied using the given <title>.  The <cntVar> is an array of
757# counters in the calling scopes for titles that have been used
758# in the past.  This is used to create titles like "Plot #2" the
759# second time it is encountered.
760#
761# The <xmlobj> is updated so that the label is inserted directly in
762# the tree.
763# ----------------------------------------------------------------------
764itcl::body Rappture::Analyzer::_autoLabel {xmlobj path title cntVar} {
765    upvar $cntVar counters
766
767    set group [$xmlobj get $path.about.group]
768    set label [$xmlobj get $path.about.label]
769    if {"" == $label} {
770        # no label -- make one up using the title specified
771        if {![info exists counters($group-$title)]} {
772            set counters($group-$title) 1
773            set label $title
774        } else {
775            set label "$title (#[incr counters($group-$title)])"
776        }
777        $xmlobj put $path.about.label $label
778    } else {
779        # handle the case of two identical labels in <output>
780        if {![info exists counters($group-$label)]} {
781            set counters($group-$label) 1
782        } else {
783            set label "$label (#[incr counters($group-$label)])"
784            $xmlobj put $path.about.label $label
785        }
786    }
787    return $label
788}
789
790# ----------------------------------------------------------------------
791# USAGE: _fixResult
792#
793# Used internally to change the result page being displayed whenever
794# the user selects a page from the results combobox.
795# ----------------------------------------------------------------------
796itcl::body Rappture::Analyzer::_fixResult {} {
797    set name [$itk_component(resultselector) value]
798    set page ""
799    if {"" != $name} {
800        set page [$itk_component(resultselector) translate $name]
801    }
802    if {$page == "@download"} {
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        # perform the actual download
809        download start $itk_component(resultselector)
810    } elseif {$page == "---"} {
811        # put the combobox back to its last value
812        $itk_component(resultselector) component entry configure -state normal
813        $itk_component(resultselector) component entry delete 0 end
814        $itk_component(resultselector) component entry insert end $_lastlabel
815        $itk_component(resultselector) component entry configure -state disabled
816    } elseif {$page != ""} {
817        set _lastlabel $name
818        set win [winfo toplevel $itk_component(hull)]
819        blt::busy hold $win; update idletasks
820        $itk_component(resultpages) current $page
821
822        set f [$itk_component(resultpages) page $page]
823        $f.rviewer plot clear
824        eval $f.rviewer plot add $_plotlist
825        blt::busy release [winfo toplevel $itk_component(hull)]
826    }
827}
828
829# ----------------------------------------------------------------------
830# USAGE: _fixSize
831#
832# Used internally to change the size of the result set area whenever
833# a new control appears.  Adjusts the size available for the result
834# set up to some maximum.
835# ----------------------------------------------------------------------
836itcl::body Rappture::Analyzer::_fixSize {} {
837    set ht [winfo height $itk_component(results)]
838    if {$ht <= 1} { set ht [winfo reqheight $itk_component(results)] }
839    set cntlht [$itk_component(resultset) size -controlarea]
840    set frac [expr {double($cntlht)/$ht}]
841
842    if {$frac < 0.4} {
843        $itk_component(results) fraction end $frac
844    }
845    _fixSimControl
846}
847
848# ----------------------------------------------------------------------
849# USAGE: _simState <boolean> ?<message>? ?<settings>?
850#
851# Used internally to change the "Simulation" button on or off.
852# If the <boolean> is on, then any <message> and <settings> are
853# displayed as well.  The <message> is a note to the user about
854# what will be simulated, and the <settings> are a list of
855# tool parameter settings of the form {path1 val1 path2 val2 ...}.
856# When these are in place, the next Simulate operation will use
857# these settings.  This helps fill in missing data values.
858# ----------------------------------------------------------------------
859itcl::body Rappture::Analyzer::_simState {state args} {
860    if {$state} {
861        $itk_interior.simol configure \
862            -background $itk_option(-simcontrolactiveoutline)
863        $itk_interior.simol.simbg configure \
864            -background $itk_option(-simcontrolactivebackground)
865        $itk_component(simulate) configure \
866            -highlightbackground $itk_option(-simcontrolactivebackground)
867        $itk_component(simstatus) configure \
868            -background $itk_option(-simcontrolactivebackground)
869
870        $itk_component(abort) configure -state disabled
871        $itk_component(simulate) configure -state normal \
872            -command [itcl::code $this simulate]
873
874        #
875        # If there's a special message, then put it up next to the button.
876        #
877        set mesg [lindex $args 0]
878        if {"" != $mesg} {
879            $itk_component(simstatus) configure -state normal
880            $itk_component(simstatus) delete 1.0 end
881            $itk_component(simstatus) insert end $mesg
882
883            #
884            # If there are any settings, then install them in the
885            # "Simulate" button.  Also, pop them up as a tooltip
886            # for the message.
887            #
888            set settings [lindex $args 1]
889            if {[llength $settings] > 0} {
890                $itk_component(simulate) configure \
891                    -command [eval itcl::code $this simulate $settings]
892
893                set details ""
894                foreach {path val} $settings {
895                    set str [$_tool xml get $path.about.label]
896                    if {"" == $str} {
897                        set str [$_tool xml element -as id $path]
898                    }
899                    append details "$str = $val\n"
900                }
901                set details [string trim $details]
902
903                Rappture::Tooltip::for $itk_component(simstatus) $details
904                $itk_component(simstatus) insert end " "
905                $itk_component(simstatus) insert end "(details...)" popup
906            }
907            $itk_component(simstatus) configure -state disabled
908        }
909    } else {
910        if {"" != $itk_option(-simcontrolbackground)} {
911            set simcbg $itk_option(-simcontrolbackground)
912        } else {
913            set simcbg $itk_option(-background)
914        }
915        $itk_interior.simol configure \
916            -background $itk_option(-simcontroloutline)
917        $itk_interior.simol.simbg configure -background $simcbg
918        $itk_component(simulate) configure -highlightbackground $simcbg
919        $itk_component(simstatus) configure -background $simcbg
920
921        $itk_component(simulate) configure -state disabled
922        $itk_component(abort) configure -state normal
923
924        $itk_component(simstatus) configure -state normal
925        $itk_component(simstatus) delete 1.0 end
926        $itk_component(simstatus) configure -state disabled
927        Rappture::Tooltip::for $itk_component(simstatus) ""
928    }
929}
930
931# ----------------------------------------------------------------------
932# USAGE: _simOutput <message>
933#
934# Invoked automatically whenever output comes in while running the
935# tool.  Extracts any =RAPPTURE-???=> messages from the output and
936# sends the output to the display.  For example, any
937# =RAPPTURE-PROGRESS=> message pops up the progress meter and updates
938# it to show the latest progress message.  This is useful for
939# long-running tools, to let the user know how much longer the
940# simulation will take.
941# ----------------------------------------------------------------------
942itcl::body Rappture::Analyzer::_simOutput {message} {
943    #
944    # Scan through and pick out any =RAPPTURE-PROGRESS=> messages first.
945    #
946    while {[regexp -indices \
947               {=RAPPTURE-PROGRESS=> *([-+]?[0-9]+) +([^\n]*)(\n|$)} $message \
948                match percent mesg]} {
949
950        foreach {i0 i1} $percent break
951        set percent [string range $message $i0 $i1]
952
953        foreach {i0 i1} $mesg break
954        set mesg [string range $message $i0 $i1]
955
956        pack $itk_component(progress) -fill x -padx 10 -pady 10
957        $itk_component(progress) settings -percent $percent -message $mesg
958
959        foreach {i0 i1} $match break
960        set message [string replace $message $i0 $i1]
961    }
962
963    #
964    # Break up the remaining lines according to =RAPPTURE-ERROR=> messages.
965    # Show errors in a special color.
966    #
967    $itk_component(runinfo) configure -state normal
968
969    while {[regexp -indices \
970               {=RAPPTURE-([a-zA-Z]+)=>([^\n]*)(\n|$)} $message \
971                match type mesg]} {
972
973        foreach {i0 i1} $match break
974        set first [string range $message 0 [expr {$i0-1}]]
975        if {[string length $first] > 0} {
976            $itk_component(runinfo) insert end $first
977            $itk_component(runinfo) insert end \n
978        }
979
980        foreach {t0 t1} $type break
981        set type [string range $message $t0 $t1]
982        foreach {m0 m1} $mesg break
983        set mesg [string range $message $m0 $m1]
984        if {[string length $mesg] > 0 && $type != "RUN"} {
985            $itk_component(runinfo) insert end $mesg $type
986            $itk_component(runinfo) insert end \n $type
987        }
988
989        set message [string range $message [expr {$i1+1}] end]
990    }
991
992    if {[string length $message] > 0} {
993        $itk_component(runinfo) insert end $message
994        if {[$itk_component(runinfo) get end-2char] != "\n"} {
995            $itk_component(runinfo) insert end "\n"
996        }
997        $itk_component(runinfo) see end
998    }
999    $itk_component(runinfo) configure -state disabled
1000}
1001
1002# ----------------------------------------------------------------------
1003# USAGE: _resultTooltip
1004#
1005# Used internally to build the tooltip string displayed for the
1006# result selector.  If the current page has an associated description,
1007# then it is displayed beneath the result.
1008#
1009# Returns the string for the tooltip.
1010# ----------------------------------------------------------------------
1011itcl::body Rappture::Analyzer::_resultTooltip {} {
1012    set tip ""
1013    set name [$itk_component(resultselector) value]
1014    if {[info exists _label2desc($name)] &&
1015         [string length $_label2desc($name)] > 0} {
1016        append tip "$_label2desc($name)\n\n"
1017    }
1018    if {[array size _label2page] > 1} {
1019        append tip "Use this control to display other output results."
1020    }
1021    return $tip
1022}
1023
1024# ----------------------------------------------------------------------
1025# USAGE: _mkdir <directory>
1026#
1027# Used internally to create the <directory> in the file system.
1028# The parent directory is also created, as needed.
1029# ----------------------------------------------------------------------
1030itcl::body Rappture::Analyzer::_mkdir {dir} {
1031    set parent [file dirname $dir]
1032    if {"." != $parent && "/" != $parent} {
1033        if {![file exists $parent]} {
1034            _mkdir $parent
1035        }
1036    }
1037    file mkdir $dir
1038}
1039
1040# ----------------------------------------------------------------------
1041# USAGE: _fixSimControl
1042#
1043# Used internally to add or remove the simulation control at the
1044# top of the analysis area.  This is controlled by the -simcontrol
1045# option.
1046# ----------------------------------------------------------------------
1047itcl::body Rappture::Analyzer::_fixSimControl {} {
1048    switch -- $itk_option(-simcontrol) {
1049        on {
1050            pack $itk_interior.simol -fill x -before $itk_interior.nb
1051        }
1052        off {
1053            pack forget $itk_interior.simol
1054        }
1055        auto {
1056            #
1057            # If we have two or more radiodials, then there is a
1058            # chance of encountering a combination of parameters
1059            # with no data, requiring simulation.
1060            #
1061            if {[$itk_component(resultset) size -controls] >= 2} {
1062                pack $itk_interior.simol -fill x -before $itk_interior.nb
1063            } else {
1064                pack forget $itk_interior.simol
1065            }
1066        }
1067        default {
1068            error "bad value \"$itk_option(-simcontrol)\": should be on, off, auto"
1069        }
1070    }
1071}
1072
1073# ----------------------------------------------------------------------
1074# CONFIGURATION OPTION: -simcontrol
1075#
1076# Controls whether or not the Simulate button is showing.  In some
1077# cases, it is not needed.
1078# ----------------------------------------------------------------------
1079itcl::configbody Rappture::Analyzer::simcontrol {
1080    _fixSimControl
1081}
Note: See TracBrowser for help on using the repository browser.