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

Last change on this file since 1077 was 1077, checked in by mmc, 16 years ago

Fixed the Rappture::filexfer facility so that if importfile/exportfile
commands are not available, it reverts to local Load/Save? operations.
This is important for applications that are not deployed in a hub, but
used instead in a standard desktop environment.

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