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

Last change on this file since 428 was 428, checked in by mmc, 18 years ago
  • Added <sequence> for playing movie outputs and other sequences of related results.
  • Added <resize> option to <image> elements. This can be used to resize input items to a smaller size, so they don't take up so much real estate on the form.
  • Fixed a bug in right/below cases for popup balloons.
  • Reduced the tooltip delay time to 750ms to interact better with Rick's attention span.
  • Fixed the sash between grips to light up when you touch it, so it's easier to see.
File size: 38.9 KB
Line 
1# ----------------------------------------------------------------------
2#  COMPONENT: analyzer - output area for Rappture
3#
4#  This widget acts as the output side of a Rappture application.
5#  When the input has changed, it displays a Simulate button that
6#  launches the simulation.  When a simulation is running, this
7#  area shows status.  When it is finished, the results appear
8#  in place of the button, according to the specs in the <analyze>
9#  XML data.
10# ======================================================================
11#  AUTHOR:  Michael McLennan, Purdue University
12#  Copyright (c) 2004-2005  Purdue Research Foundation
13#
14#  See the file "license.terms" for information on usage and
15#  redistribution of this file, and for a DISCLAIMER OF ALL WARRANTIES.
16# ======================================================================
17package require Itk
18
19option add *Analyzer.width 3.5i widgetDefault
20option add *Analyzer.height 4i widgetDefault
21option add *Analyzer.simControl "auto" widgetDefault
22option add *Analyzer.simControlBackground "" widgetDefault
23option add *Analyzer.simControlOutline gray widgetDefault
24option add *Analyzer.simControlActiveBackground #ffffcc widgetDefault
25option add *Analyzer.simControlActiveOutline black widgetDefault
26
27option add *Analyzer.font \
28    -*-helvetica-medium-r-normal-*-*-120-* widgetDefault
29option add *Analyzer.codeFont \
30    -*-courier-medium-r-normal-*-*-120-* widgetDefault
31option add *Analyzer.textFont \
32    -*-helvetica-medium-r-normal-*-*-120-* widgetDefault
33option add *Analyzer.boldTextFont \
34    -*-helvetica-bold-r-normal-*-*-120-* widgetDefault
35
36itcl::class Rappture::Analyzer {
37    inherit itk::Widget
38
39    itk_option define -codefont codeFont Font ""
40    itk_option define -textfont textFont Font ""
41    itk_option define -boldtextfont boldTextFont Font ""
42    itk_option define -simcontrol simControl SimControl ""
43    itk_option define -simcontroloutline simControlOutline Background ""
44    itk_option define -simcontrolbackground simControlBackground Background ""
45    itk_option define -simcontrolactiveoutline simControlActiveOutline Background ""
46    itk_option define -simcontrolactivebackground simControlActiveBackground Background ""
47    itk_option define -holdwindow holdWindow HoldWindow ""
48
49    constructor {tool args} { # defined below }
50    destructor { # defined below }
51
52    public method simulate {args}
53    public method reset {}
54    public method load {file}
55    public method clear {}
56    public method download {option args}
57
58    protected method _plot {args}
59    protected method _reorder {comps}
60    protected method _autoLabel {xmlobj path title cntVar}
61    protected method _fixResult {}
62    protected method _fixSize {}
63    protected method _fixSimControl {}
64    protected method _simState {state args}
65    protected method _simOutput {message}
66    protected method _resultTooltip {}
67    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 now $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    } else {
394        $itk_component(notebook) current analyze
395    }
396
397    # do this last -- after _simOutput above
398    pack forget $itk_component(progress)
399}
400
401# ----------------------------------------------------------------------
402# USAGE: reset
403#
404# Used to reset the analyzer whenever the input to a simulation has
405# changed.  Sets the mode back to "simulate", so the user has to
406# simulate again to see the output.  If the <start> option is set
407# to "auto", the simulation is invoked immediately.
408# ----------------------------------------------------------------------
409itcl::body Rappture::Analyzer::reset {} {
410    # check to see if simulation is really needed
411    $_tool sync
412    if {![$itk_component(resultset) contains [$_tool xml object]]} {
413        # if control mode is "auto", then simulate right away
414        if {[string match auto* $_control]} {
415            # auto control -- don't need button
416            pack forget $itk_interior.simol
417
418            after cancel [itcl::code $this simulate]
419            after idle [itcl::code $this simulate]
420        } else {
421            _simState on "new input parameters"
422        }
423    } else {
424        _simState off
425    }
426}
427
428# ----------------------------------------------------------------------
429# USAGE: load <file>
430#
431# Loads the data from the given <file> into the appropriate results
432# sets.  If necessary, new results sets are created to store the data.
433# ----------------------------------------------------------------------
434itcl::body Rappture::Analyzer::load {file} {
435    # only show the last result? then clear first
436    if {[$_tool xml get tool.analyzer] == "last"} {
437        clear
438    }
439
440    # try to load new results from the given file
441    set xmlobj [Rappture::library $file]
442    lappend _runs $xmlobj
443
444    # go through the analysis and find all result sets
445    set haveresults 0
446    foreach item [_reorder [$xmlobj children output]] {
447        switch -glob -- $item {
448            log* {
449                _autoLabel $xmlobj output.$item "Output Log" counters
450            }
451            string* {
452                _autoLabel $xmlobj output.$item "String" counters
453            }
454            curve* - field* {
455                _autoLabel $xmlobj output.$item "Plot" counters
456            }
457            structure* {
458                _autoLabel $xmlobj output.$item "Structure" counters
459            }
460            table* {
461                _autoLabel $xmlobj output.$item "Energy Levels" counters
462            }
463            sequence* {
464                _autoLabel $xmlobj output.$item "Sequence" counters
465            }
466        }
467        set label [$xmlobj get output.$item.about.group]
468        if {"" == $label} {
469            set label [$xmlobj get output.$item.about.label]
470        }
471
472        set hidden [$xmlobj get output.$item.hide]
473        set hidden [expr {"" != $hidden && $hidden}]
474
475        if {"" != $label && !$hidden} {
476            set haveresults 1
477        }
478    }
479
480    # if there are any valid results, add them to the resultset
481    if {$haveresults} {
482        set index [$itk_component(resultset) add $xmlobj]
483
484        # add each result to a result viewer
485        foreach item [_reorder [$xmlobj children output]] {
486            set label [$xmlobj get output.$item.about.group]
487            if {"" == $label} {
488                set label [$xmlobj get output.$item.about.label]
489            }
490
491            set hidden [$xmlobj get output.$item.hide]
492            set hidden [expr {"" != $hidden && $hidden}]
493
494            if {"" != $label && !$hidden} {
495                if {![info exists _label2page($label)]} {
496                    set name "page[incr _pages]"
497                    set page [$itk_component(resultpages) insert end $name]
498                    set _label2page($label) $page
499                    set _label2desc($label) \
500                        [$xmlobj get output.$item.about.description]
501                    Rappture::ResultViewer $page.rviewer
502                    pack $page.rviewer -expand yes -fill both -pady 4
503
504                    set end [$itk_component(resultselector) \
505                        choices index -value ---]
506                    if {$end < 0} {
507                        set end "end"
508                    }
509                    $itk_component(resultselector) choices insert $end \
510                        $name $label
511                }
512
513                # add/replace the latest result into this viewer
514                set page $_label2page($label)
515
516                if {![info exists reset($page)]} {
517                    $page.rviewer clear $index
518                    set reset($page) 1
519                }
520                $page.rviewer add $index $xmlobj output.$item
521            }
522        }
523    }
524
525    # show the first page by default
526    set max [$itk_component(resultselector) choices size]
527    for {set i 0} {$i < $max} {incr i} {
528        set first [$itk_component(resultselector) choices get -label $i]
529        if {$first != ""} {
530            set page [$itk_component(resultselector) choices get -value $i]
531            set char [string index $page 0]
532            if {$char != "@" && $char != "-"} {
533                $itk_component(resultpages) current $page
534                $itk_component(resultselector) value $first
535                break
536            }
537        }
538    }
539}
540
541# ----------------------------------------------------------------------
542# USAGE: clear
543#
544# Discards all results previously loaded into the analyzer.
545# ----------------------------------------------------------------------
546itcl::body Rappture::Analyzer::clear {} {
547    foreach obj $_runs {
548        itcl::delete object $obj
549    }
550    set _runs ""
551
552    $itk_component(resultset) clear
553
554    # reset the size of the controls area
555    set ht [winfo height $itk_component(results)]
556    set cntlht [$itk_component(resultset) size -controlarea]
557    set frac [expr {double($cntlht)/$ht}]
558    $itk_component(results) fraction end $frac
559
560    foreach label [array names _label2page] {
561        set page $_label2page($label)
562        $page.rviewer clear
563    }
564    $itk_component(resultselector) value ""
565    $itk_component(resultselector) choices delete 0 end
566    catch {unset _label2page}
567    catch {unset _label2desc}
568    set _plotlist ""
569
570    if {[Rappture::filexfer::enabled]} {
571        $itk_component(resultselector) choices insert end \
572            --- "---"
573        $itk_component(resultselector) choices insert end \
574            @download "Download..."
575    }
576    set _lastlabel ""
577
578    #
579    # HACK ALERT!!
580    # The following statement should be in place, but it causes
581    # vtk to dump core.  Leave it out until we can fix the core dump.
582    # In the mean time, we leak memory...
583    #
584    #$itk_component(resultpages) delete -all
585    #set _pages 0
586
587    _simState on
588    _fixSimControl
589    reset
590}
591
592# ----------------------------------------------------------------------
593# USAGE: download coming
594# USAGE: download now ?widget?
595#
596# Spools the current result so the user can download it.
597# ----------------------------------------------------------------------
598itcl::body Rappture::Analyzer::download {option args} {
599    if {[Rappture::filexfer::enabled]} {
600        set title [$itk_component(resultselector) value]
601        set page [$itk_component(resultselector) translate $title]
602
603        switch -- $option {
604            coming {
605                #
606                # Warn result that a download is coming, in case
607                # it needs to take a screen snap.
608                #
609                if {![regexp {^(|@download|---)$} $page]} {
610                    set f [$itk_component(resultpages) page $page]
611                    $f.rviewer download coming
612                }
613            }
614            now {
615                set widget $itk_component(download)
616                if {[llength $args] > 0} {
617                    set widget [lindex $args 0]
618                    if {[catch {winfo class $widget}]} {
619                        set widget $itk_component(download)
620                    }
621                }
622                #
623                # Perform the actual download.
624                #
625                if {$page != ""} {
626                    set ext ""
627                    set f [$itk_component(resultpages) page $page]
628                    foreach {ext data} [$f.rviewer download now] break
629                    if {"" == $ext} {
630                        if {"" != $widget} {
631                            Rappture::Tooltip::cue $widget \
632                                "Can't download this result."
633                        }
634                        return
635                    }
636                    regsub -all {[\ -\/\:-\@\{-\~]} $title {} title
637                    set file "$title$ext"
638                } else {
639                    # this shouldn't happen
640                    set file error.html
641                    set data "<h1>Not Found</h1>There is no result selected."
642                }
643
644                if {[catch {Rappture::filexfer::spool $data $file} result]} {
645                    if {"no clients" == $result} {
646                        if {"" != $widget} {
647                            Rappture::Tooltip::cue $widget "Can't download this result.  Looks like you might be having trouble with the version of Java installed for your browser."
648                        }
649                    } elseif {"old client" == $result} {
650                        if {"" != $widget} {
651                            Rappture::Tooltip::cue $widget "For this to work properly, you must first restart your Web browser.  You don't need to close down this session.  Simply shut down all windows for your Web browser, then restart the browser and navigate back to this page.  You'll find it on \"my nanoHUB\" listed under \"my sessions\".  Once the browser is restarted, the download should work properly."
652                        }
653                    } elseif {"old clients" == $result} {
654                        if {"" != $widget} {
655                            Rappture::Tooltip::cue $widget "There are multiple browser pages connected to this session, and one of them has browser that needs to be restarted.\n\nWhoever didn't get the download should restart their Web browser.  You don't need to close down this session.  Simply shut down all windows for the Web browser, then restart the browser and navigate back to this page.  You'll find it on \"my nanoHUB\" listed under \"my sessions\".  Once the browser is restarted, the download should work properly."
656                        }
657                    } else {
658                        error $result "    (while spooling result \"$title\")"
659                    }
660                }
661            }
662            default {
663                error "bad option \"$option\": should be coming, now"
664            }
665        }
666    }
667}
668
669# ----------------------------------------------------------------------
670# USAGE: _plot ?<index> <options> <index> <options>...?
671#
672# Used internally to update the plot shown in the current result
673# viewer whenever the resultset settings have changed.  Causes the
674# desired results to show up on screen.
675# ----------------------------------------------------------------------
676itcl::body Rappture::Analyzer::_plot {args} {
677    set _plotlist $args
678
679    set page [$itk_component(resultselector) value]
680    set page [$itk_component(resultselector) translate $page]
681    if {"" != $page} {
682        set f [$itk_component(resultpages) page $page]
683        $f.rviewer plot clear
684        foreach {index opts} $_plotlist {
685            $f.rviewer plot add $index $opts
686        }
687    }
688}
689
690# ----------------------------------------------------------------------
691# USAGE: _reorder <compList>
692#
693# Used internally to change the order of a series of output components
694# found in the <output> section.  Moves the <log> elements to the end
695# and returns the updated list.
696# ----------------------------------------------------------------------
697itcl::body Rappture::Analyzer::_reorder {comps} {
698    set i 0
699    set max [llength $comps]
700    while {$i < $max} {
701        set c [lindex $comps $i]
702        if {[string match log* $c]} {
703            set comps [lreplace $comps $i $i]
704            lappend comps $c
705            incr max -1
706        } else {
707            incr i
708        }
709    }
710    return $comps
711}
712
713# ----------------------------------------------------------------------
714# USAGE: _autoLabel <xmlobj> <path> <title> <cntVar>
715#
716# Used internally to check for an about.label property at the <path>
717# in <xmlobj>.  If this object doesn't have a label, then one is
718# supplied using the given <title>.  The <cntVar> is an array of
719# counters in the calling scopes for titles that have been used
720# in the past.  This is used to create titles like "Plot #2" the
721# second time it is encountered.
722#
723# The <xmlobj> is updated so that the label is inserted directly in
724# the tree.
725# ----------------------------------------------------------------------
726itcl::body Rappture::Analyzer::_autoLabel {xmlobj path title cntVar} {
727    upvar $cntVar counters
728
729    set group [$xmlobj get $path.about.group]
730    set label [$xmlobj get $path.about.label]
731    if {"" == $label} {
732        # no label -- make one up using the title specified
733        if {![info exists counters($group-$title)]} {
734            set counters($group-$title) 1
735            set label $title
736        } else {
737            set label "$title (#[incr counters($group-$title)])"
738        }
739        $xmlobj put $path.about.label $label
740    } else {
741        # handle the case of two identical labels in <output>
742        if {![info exists counters($group-$label)]} {
743            set counters($group-$label) 1
744        } else {
745            set label "$label (#[incr counters($group-$label)])"
746            $xmlobj put $path.about.label $label
747        }
748    }
749    return $label
750}
751
752# ----------------------------------------------------------------------
753# USAGE: _fixResult
754#
755# Used internally to change the result page being displayed whenever
756# the user selects a page from the results combobox.
757# ----------------------------------------------------------------------
758itcl::body Rappture::Analyzer::_fixResult {} {
759    set name [$itk_component(resultselector) value]
760    set page ""
761    if {"" != $name} {
762        set page [$itk_component(resultselector) translate $name]
763    }
764    if {$page == "@download"} {
765        # put the combobox back to its last value
766        $itk_component(resultselector) component entry configure -state normal
767        $itk_component(resultselector) component entry delete 0 end
768        $itk_component(resultselector) component entry insert end $_lastlabel
769        $itk_component(resultselector) component entry configure -state disabled
770        # perform the actual download
771        download now $itk_component(resultselector)
772    } elseif {$page == "---"} {
773        # put the combobox back to its last value
774        $itk_component(resultselector) component entry configure -state normal
775        $itk_component(resultselector) component entry delete 0 end
776        $itk_component(resultselector) component entry insert end $_lastlabel
777        $itk_component(resultselector) component entry configure -state disabled
778    } elseif {$page != ""} {
779        set _lastlabel $name
780        set win [winfo toplevel $itk_component(hull)]
781        blt::busy hold $win; update idletasks
782        $itk_component(resultpages) current $page
783
784        set f [$itk_component(resultpages) page $page]
785        $f.rviewer plot clear
786        eval $f.rviewer plot add $_plotlist
787        blt::busy release [winfo toplevel $itk_component(hull)]
788    }
789}
790
791# ----------------------------------------------------------------------
792# USAGE: _fixSize
793#
794# Used internally to change the size of the result set area whenever
795# a new control appears.  Adjusts the size available for the result
796# set up to some maximum.
797# ----------------------------------------------------------------------
798itcl::body Rappture::Analyzer::_fixSize {} {
799    set ht [winfo height $itk_component(results)]
800    if {$ht <= 1} { set ht [winfo reqheight $itk_component(results)] }
801    set cntlht [$itk_component(resultset) size -controlarea]
802    set frac [expr {double($cntlht)/$ht}]
803
804    if {$frac < 0.4} {
805        $itk_component(results) fraction end $frac
806    }
807    _fixSimControl
808}
809
810# ----------------------------------------------------------------------
811# USAGE: _simState <boolean> ?<message>? ?<settings>?
812#
813# Used internally to change the "Simulation" button on or off.
814# If the <boolean> is on, then any <message> and <settings> are
815# displayed as well.  The <message> is a note to the user about
816# what will be simulated, and the <settings> are a list of
817# tool parameter settings of the form {path1 val1 path2 val2 ...}.
818# When these are in place, the next Simulate operation will use
819# these settings.  This helps fill in missing data values.
820# ----------------------------------------------------------------------
821itcl::body Rappture::Analyzer::_simState {state args} {
822    if {$state} {
823        $itk_interior.simol configure \
824            -background $itk_option(-simcontrolactiveoutline)
825        $itk_interior.simol.simbg configure \
826            -background $itk_option(-simcontrolactivebackground)
827        $itk_component(simulate) configure \
828            -highlightbackground $itk_option(-simcontrolactivebackground)
829        $itk_component(simstatus) configure \
830            -background $itk_option(-simcontrolactivebackground)
831
832        $itk_component(abort) configure -state disabled
833        $itk_component(simulate) configure -state normal \
834            -command [itcl::code $this simulate]
835
836        #
837        # If there's a special message, then put it up next to the button.
838        #
839        set mesg [lindex $args 0]
840        if {"" != $mesg} {
841            $itk_component(simstatus) configure -state normal
842            $itk_component(simstatus) delete 1.0 end
843            $itk_component(simstatus) insert end $mesg
844
845            #
846            # If there are any settings, then install them in the
847            # "Simulate" button.  Also, pop them up as a tooltip
848            # for the message.
849            #
850            set settings [lindex $args 1]
851            if {[llength $settings] > 0} {
852                $itk_component(simulate) configure \
853                    -command [eval itcl::code $this simulate $settings]
854
855                set details ""
856                foreach {path val} $settings {
857                    set str [$_tool xml get $path.about.label]
858                    if {"" == $str} {
859                        set str [$_tool xml element -as id $path]
860                    }
861                    append details "$str = $val\n"
862                }
863                set details [string trim $details]
864
865                Rappture::Tooltip::for $itk_component(simstatus) $details
866                $itk_component(simstatus) insert end " "
867                $itk_component(simstatus) insert end "(details...)" popup
868            }
869            $itk_component(simstatus) configure -state disabled
870        }
871    } else {
872        if {"" != $itk_option(-simcontrolbackground)} {
873            set simcbg $itk_option(-simcontrolbackground)
874        } else {
875            set simcbg $itk_option(-background)
876        }
877        $itk_interior.simol configure \
878            -background $itk_option(-simcontroloutline)
879        $itk_interior.simol.simbg configure -background $simcbg
880        $itk_component(simulate) configure -highlightbackground $simcbg
881        $itk_component(simstatus) configure -background $simcbg
882
883        $itk_component(simulate) configure -state disabled
884        $itk_component(abort) configure -state normal
885
886        $itk_component(simstatus) configure -state normal
887        $itk_component(simstatus) delete 1.0 end
888        $itk_component(simstatus) configure -state disabled
889        Rappture::Tooltip::for $itk_component(simstatus) ""
890    }
891}
892
893# ----------------------------------------------------------------------
894# USAGE: _simOutput <message>
895#
896# Invoked automatically whenever output comes in while running the
897# tool.  Extracts any =RAPPTURE-???=> messages from the output and
898# sends the output to the display.  For example, any
899# =RAPPTURE-PROGRESS=> message pops up the progress meter and updates
900# it to show the latest progress message.  This is useful for
901# long-running tools, to let the user know how much longer the
902# simulation will take.
903# ----------------------------------------------------------------------
904itcl::body Rappture::Analyzer::_simOutput {message} {
905    #
906    # Scan through and pick out any =RAPPTURE-PROGRESS=> messages first.
907    #
908    while {[regexp -indices \
909               {=RAPPTURE-PROGRESS=>([0-9]+) +([^\n]*)(\n|$)} $message \
910                match percent mesg]} {
911
912        foreach {i0 i1} $percent break
913        set percent [string range $message $i0 $i1]
914
915        foreach {i0 i1} $mesg break
916        set mesg [string range $message $i0 $i1]
917
918        pack $itk_component(progress) -fill x -padx 10 -pady 10
919        $itk_component(progress) settings -percent $percent -message $mesg
920
921        foreach {i0 i1} $match break
922        set message [string replace $message $i0 $i1]
923    }
924
925    #
926    # Break up the remaining lines according to =RAPPTURE-ERROR=> messages.
927    # Show errors in a special color.
928    #
929    $itk_component(runinfo) configure -state normal
930
931    while {[regexp -indices \
932               {=RAPPTURE-([a-zA-Z]+)=>([^\n]*)(\n|$)} $message \
933                match type mesg]} {
934
935        foreach {i0 i1} $match break
936        set first [string range $message 0 [expr {$i0-1}]]
937        if {[string length $first] > 0} {
938            $itk_component(runinfo) insert end $first
939            $itk_component(runinfo) insert end \n
940        }
941
942        foreach {t0 t1} $type break
943        set type [string range $message $t0 $t1]
944        foreach {m0 m1} $mesg break
945        set mesg [string range $message $m0 $m1]
946        if {[string length $mesg] > 0 && $type != "RUN"} {
947            $itk_component(runinfo) insert end $mesg $type
948            $itk_component(runinfo) insert end \n $type
949        }
950
951        set message [string range $message [expr {$i1+1}] end]
952    }
953
954    if {[string length $message] > 0} {
955        $itk_component(runinfo) insert end $message
956        if {[$itk_component(runinfo) get end-2char] != "\n"} {
957            $itk_component(runinfo) insert end "\n"
958        }
959        $itk_component(runinfo) see end
960    }
961    $itk_component(runinfo) configure -state disabled
962}
963
964# ----------------------------------------------------------------------
965# USAGE: _resultTooltip
966#
967# Used internally to build the tooltip string displayed for the
968# result selector.  If the current page has an associated description,
969# then it is displayed beneath the result.
970#
971# Returns the string for the tooltip.
972# ----------------------------------------------------------------------
973itcl::body Rappture::Analyzer::_resultTooltip {} {
974    set tip ""
975    set name [$itk_component(resultselector) value]
976    if {[info exists _label2desc($name)] &&
977         [string length $_label2desc($name)] > 0} {
978        append tip "$_label2desc($name)\n\n"
979    }
980    if {[array size _label2page] > 1} {
981        append tip "Use this control to display other output results."
982    }
983    return $tip
984}
985
986# ----------------------------------------------------------------------
987# USAGE: _mkdir <directory>
988#
989# Used internally to create the <directory> in the file system.
990# The parent directory is also created, as needed.
991# ----------------------------------------------------------------------
992itcl::body Rappture::Analyzer::_mkdir {dir} {
993    set parent [file dirname $dir]
994    if {"." != $parent && "/" != $parent} {
995        if {![file exists $parent]} {
996            _mkdir $parent
997        }
998    }
999    file mkdir $dir
1000}
1001
1002# ----------------------------------------------------------------------
1003# USAGE: _fixSimControl
1004#
1005# Used internally to add or remove the simulation control at the
1006# top of the analysis area.  This is controlled by the -simcontrol
1007# option.
1008# ----------------------------------------------------------------------
1009itcl::body Rappture::Analyzer::_fixSimControl {} {
1010    switch -- $itk_option(-simcontrol) {
1011        on {
1012            pack $itk_interior.simol -fill x -before $itk_interior.nb
1013        }
1014        off {
1015            pack forget $itk_interior.simol
1016        }
1017        auto {
1018            #
1019            # If we have two or more radiodials, then there is a
1020            # chance of encountering a combination of parameters
1021            # with no data, requiring simulation.
1022            #
1023            if {[$itk_component(resultset) size -controls] >= 2} {
1024                pack $itk_interior.simol -fill x -before $itk_interior.nb
1025            } else {
1026                pack forget $itk_interior.simol
1027            }
1028        }
1029        default {
1030            error "bad value \"$itk_option(-simcontrol)\": should be on, off, auto"
1031        }
1032    }
1033}
1034
1035# ----------------------------------------------------------------------
1036# CONFIGURATION OPTION: -simcontrol
1037#
1038# Controls whether or not the Simulate button is showing.  In some
1039# cases, it is not needed.
1040# ----------------------------------------------------------------------
1041itcl::configbody Rappture::Analyzer::simcontrol {
1042    _fixSimControl
1043}
Note: See TracBrowser for help on using the repository browser.