source: branches/1.6/gui/scripts/analyzer.tcl @ 6205

Last change on this file since 6205 was 6205, checked in by gah, 8 years ago

fix new puq handling routine in task.tcl

File size: 76.6 KB
Line 
1# -*- mode: tcl; indent-tabs-mode: nil -*-
2# ----------------------------------------------------------------------
3#  COMPONENT: analyzer - output area for Rappture
4#
5#  This widget acts as the output side of a Rappture application.
6#  When the input has changed, it displays a Simulate button that
7#  launches the simulation.  When a simulation is running, this
8#  area shows status.  When it is finished, the results appear
9#  in place of the button, according to the specs in the <analyze>
10#  XML data.
11# ======================================================================
12#  AUTHOR:  Michael McLennan, Purdue University
13#  Copyright (c) 2004-2012  HUBzero Foundation, LLC
14#
15#  See the file "license.terms" for information on usage and
16#  redistribution of this file, and for a DISCLAIMER OF ALL WARRANTIES.
17# ======================================================================
18package require Itk
19
20option add *Analyzer.width 3.5i widgetDefault
21option add *Analyzer.height 4i widgetDefault
22option add *Analyzer.simControl "auto" widgetDefault
23option add *Analyzer.simControlBackground "" widgetDefault
24option add *Analyzer.simControlOutline gray widgetDefault
25option add *Analyzer.simControlActiveBackground #ffffcc widgetDefault
26option add *Analyzer.simControlActiveOutline black widgetDefault
27option add *Analyzer.notebookpage "about" widgetDefault
28
29option add *Analyzer.font \
30    -*-helvetica-medium-r-normal-*-12-* widgetDefault
31option add *Analyzer.codeFont \
32    -*-courier-medium-r-normal-*-12-* widgetDefault
33option add *Analyzer.textFont \
34    -*-helvetica-medium-r-normal-*-12-* widgetDefault
35option add *Analyzer.boldTextFont \
36    -*-helvetica-bold-r-normal-*-12-* widgetDefault
37
38itcl::class Rappture::Analyzer {
39    inherit itk::Widget
40
41    itk_option define -codefont codeFont Font ""
42    itk_option define -textfont textFont Font ""
43    itk_option define -boldtextfont boldTextFont Font ""
44    itk_option define -simcontrol simControl SimControl ""
45    itk_option define -simcontroloutline simControlOutline Background ""
46    itk_option define -simcontrolbackground simControlBackground Background ""
47    itk_option define -simcontrolactiveoutline simControlActiveOutline Background ""
48    itk_option define -simcontrolactivebackground simControlActiveBackground Background ""
49    itk_option define -holdwindow holdWindow HoldWindow ""
50    itk_option define -notebookpage notebookPage NotebookPage ""
51
52    private variable _done 0
53    private variable _tree ""
54    private variable _saved
55    private variable _name ""
56    private variable _revision 0;       # Tool revision
57   
58    constructor {tool args} {
59        # defined below
60    }
61    destructor {
62        # defined below
63    }
64
65    public method simulate {args}
66    public method reset {{when -eventually}}
67    public method load {xmlobj}
68    public method reload { fileName }
69    public method clear {{xmlobj "all"}}
70    public method download {option args}
71    public method buildMenu { w url appName }
72
73    protected method _plot {args}
74    protected method _reorder {comps}
75    protected method _autoLabel {xmlobj path title cntVar}
76    protected method _fixResult {}
77    protected method _fixResultSet {args}
78    protected method _fixSize {}
79    protected method _fixSimControl {}
80    protected method _fixNotebook {}
81    protected method _simState {state args}
82    protected method _simOutput {message}
83    protected method _resultTooltip {}
84    protected method _isPdbTrajectory {data}
85    protected method _isLammpsTrajectory {data}
86    protected method _pdbToSequence {xmlobj path id child data}
87    protected method _lammpsToSequence {xmlobj path id child data}
88    protected method _trajToSequence {xmlobj {path ""}}
89    protected method _pop_uq_dialog {win}
90    protected method _setWaitVariable {state}
91    protected method _adjust_level {win}
92
93    private variable _tool ""          ;# belongs to this tool
94    private variable _appName ""       ;# Name of application
95    private variable _control "manual" ;# start mode
96    private variable _resultset ""     ;# ResultSet object with all results
97    private variable _pages 0          ;# number of pages for result sets
98    private variable _label2page       ;# maps output label => result set
99    private variable _label2desc       ;# maps output label => description
100    private variable _label2item       ;# maps output label => output.xxx item
101    private variable _lastlabel ""     ;# label of last example loaded
102    private variable _plotlist ""      ;# items currently being plotted
103    private variable _lastPlot
104    private common job                 ;# array var used for blt::bgexec jobs
105    private variable _uq_active 0      ;# a UQ variables has been used
106    private variable _wait_uq 0
107
108    private method BuildSimulationTable { w }
109    private method Cancel {}
110    private method CheckSimsetDetails {}
111    private method EditSimset {}
112    private method FindSimsetsForApp { appName }
113    private method GetSimset { name }
114    private method LoadSimulations { runfiles }
115    private method Ok {}
116    private method PostMenu { menu }
117    private method ReadSimsetFile { fileName }
118    private method SaveSimulations {}
119    private method SelectSimsetForDeletion {}
120    private method SelectSimsetForLoading {}
121    private method SelectSimsetNameAndSave {}
122    private method SelectSimsetToPublish {}
123    private method WriteSimsetFile { appName fileName publish }
124    private method OverwriteSaveFile {}
125    private method BuildQuestionDialog { popup }
126    private method Save {}
127    private method CleanName { name }
128}
129
130itk::usual Analyzer {
131    keep -background -cursor foreground -font
132}
133
134# ----------------------------------------------------------------------
135# CONSTRUCTOR
136# ----------------------------------------------------------------------
137itcl::body Rappture::Analyzer::constructor {tool args} {
138    set _tool $tool
139    set _tree [blt::tree create]
140
141    # use this to store all simulation results
142    set _resultset [Rappture::ResultSet ::\#auto]
143    $_resultset notify add $this [itcl::code $this _fixResultSet]
144
145    # widget settings...
146    itk_option add hull.width hull.height
147    pack propagate $itk_component(hull) no
148
149    frame $itk_interior.simol -borderwidth 1 -relief flat
150    pack $itk_interior.simol -fill x
151
152    itk_component add simbg {
153        frame $itk_interior.simol.simbg -borderwidth 0
154    } {
155        usual
156        rename -background -simcontrolcolor simControlColor Color
157    }
158    pack $itk_component(simbg) -expand yes -fill both
159
160    set simtxt [string trim [$tool xml get tool.action.label]]
161    if {"" == $simtxt} {
162        set simtxt "Simulate"
163    }
164    itk_component add simulate {
165        button $itk_component(simbg).simulate -text $simtxt \
166            -command [itcl::code $this simulate]
167    } {
168        usual
169        rename -highlightbackground -simcontrolcolor simControlColor Color
170    }
171    pack $itk_component(simulate) -side left -padx 4 -pady 4
172
173    # BE CAREFUL: Shift focus when we click on "Simulate".
174    #   This shifts focus away from input widgets and causes them to
175    #   finalize and log any pending changes.  A better way would be
176    #   to have the "sync" operation finalize/sync, but this works
177    #   for now.
178    bind $itk_component(simulate) <ButtonPress> {focus %W}
179
180    # if there's a hub url, then add "About" and "Questions" links
181    global rapptureInfo
182    if { $rapptureInfo(appName) == "" } {
183        set _appName [$_tool xml get "tool.id"]
184    } else {
185        set _appName $rapptureInfo(appName)
186    }
187    set num [$_tool xml get "tool.version.application.revision"]
188    if { $num == "" } {
189        set num 0
190    }
191    set _revision $num
192    set url [Rappture::Tool::resources -huburl]
193
194    itk_component add hubcntls {
195        frame $itk_component(simbg).hubcntls
196    } {
197        usual
198        rename -background -simcontrolcolor simControlColor Color
199    }
200    pack $itk_component(hubcntls) -side right -padx 4
201   
202    itk_component add help {
203        menubutton $itk_component(hubcntls).help \
204            -image [Rappture::icon hamburger_menu] \
205            -highlightthickness 0 \
206            -menu $itk_component(hubcntls).help.menu
207    } {
208        usual
209        ignore -highlightthickness
210        rename -background -simcontrolcolor simControlColor Color
211    }
212    pack $itk_component(help) -side left
213    buildMenu $itk_component(help).menu $url $_appName
214   
215    if 0 {
216        # To be eliminated with menu changes.
217    itk_component add about {
218        button $itk_component(hubcntls).about \
219            -text "About this tool" \
220            -command [list Rappture::filexfer::webpage \
221                          "$url/tools/$_appName"]
222    } {
223        usual
224        ignore -font
225        rename -background -simcontrolcolor simControlColor Color
226        rename -highlightbackground -simcontrolcolor simControlColor Color
227    }
228    pack $itk_component(about) -side top -anchor w
229   
230    itk_component add questions {
231        button $itk_component(hubcntls).questions -text Questions? \
232            -command [list Rappture::filexfer::webpage \
233                          "$url/resources/$_appName/questions"]
234    } {
235        usual
236        ignore -font
237        rename -background -simcontrolcolor simControlColor Color
238        rename -highlightbackground -simcontrolcolor simControlColor Color
239    }
240    pack $itk_component(questions) -side top -anchor w
241    if { $url == "" || $_appName == "" } {
242        $itk_component(questions) configure -state disabled
243        $itk_component(about) configure -state disabled
244    } else {
245        $itk_component(questions) configure -state normal
246        $itk_component(about) configure -state normal
247    }       
248    }
249    itk_component add simstatus {
250        text $itk_component(simbg).simstatus -borderwidth 0 \
251            -highlightthickness 0 -height 1 -width 1 -wrap none \
252            -state disabled
253    } {
254        usual
255        ignore -highlightthickness
256        rename -background -simcontrolcolor simControlColor Color
257        rename -font -textfont textFont Font
258    }
259    pack $itk_component(simstatus) -side left -expand yes -fill x
260
261    $itk_component(simstatus) tag configure popup \
262        -underline 1 -foreground blue
263
264    $itk_component(simstatus) tag bind popup \
265        <Enter> {%W configure -cursor center_ptr}
266    $itk_component(simstatus) tag bind popup \
267        <Leave> {%W configure -cursor ""}
268    $itk_component(simstatus) tag bind popup \
269        <ButtonPress> {after idle {Rappture::Tooltip::tooltip show %W}}
270
271
272    itk_component add notebook {
273        Rappture::Notebook $itk_interior.nb
274    }
275    pack $itk_interior.nb -expand yes -fill both
276
277    # ------------------------------------------------------------------
278    # ABOUT PAGE
279    # ------------------------------------------------------------------
280    set w [$itk_component(notebook) insert end about]
281
282    Rappture::Scroller $w.info -xscrollmode off -yscrollmode auto
283    pack $w.info -expand yes -fill both -padx 4 -pady 20
284    itk_component add toolinfo {
285        text $w.info.text -width 1 -height 1 -wrap word \
286            -borderwidth 0 -highlightthickness 0
287    } {
288        usual
289        ignore -borderwidth -relief
290        rename -font -textfont textFont Font
291    }
292    $w.info contents $w.info.text
293
294    # ------------------------------------------------------------------
295    # SIMULATION PAGE
296    # ------------------------------------------------------------------
297    set w [$itk_component(notebook) insert end simulate]
298    frame $w.cntls
299    pack $w.cntls -side bottom -fill x -pady 12
300    frame $w.cntls.sep -background black -height 1
301    pack $w.cntls.sep -side top -fill x
302
303    itk_component add abort {
304        button $w.cntls.abort -text "Abort" \
305            -command [itcl::code $_tool abort]
306    }
307    pack $itk_component(abort) -side left -expand yes -padx 4 -pady 4
308
309    Rappture::Scroller $w.info -xscrollmode auto -yscrollmode auto
310    pack $w.info -expand yes -fill both -padx 4 -pady 4
311    itk_component add runinfo {
312        text $w.info.text -width 1 -height 1 -wrap none \
313            -borderwidth 0 -highlightthickness 0 \
314            -state disabled
315    } {
316        usual
317        ignore -borderwidth -relief
318        rename -font -codefont codeFont Font
319    }
320    $w.info contents $w.info.text
321
322    itk_component add progress {
323        Rappture::Progress $w.progress
324    }
325
326    # ------------------------------------------------------------------
327    # ANALYZE PAGE
328    # ------------------------------------------------------------------
329    set w [$itk_component(notebook) insert end analyze]
330
331    frame $w.top
332    pack $w.top -side top -fill x -pady 8
333    label $w.top.l -text "Result:" -font $itk_option(-font)
334    pack $w.top.l -side left
335
336    itk_component add viewselector {
337        Rappture::Combobox $w.top.sel -width 10 -editable no
338    } {
339        usual
340        rename -font -textfont textFont Font
341    }
342    pack $itk_component(viewselector) -side left -expand yes -fill x
343    bind $itk_component(viewselector) <<Value>> [itcl::code $this _fixResult]
344    bind $itk_component(viewselector) <Enter> \
345        [itcl::code $this download coming]
346
347    Rappture::Tooltip::for $itk_component(viewselector) \
348        "@[itcl::code $this _resultTooltip]"
349
350    $itk_component(viewselector) choices insert end \
351        --- "---"
352
353    itk_component add download {
354        button $w.top.dl -image [Rappture::icon download] -anchor e \
355            -borderwidth 1 -relief flat -overrelief raised \
356            -command [itcl::code $this download start $w.top.dl]
357    }
358    pack $itk_component(download) -side right -padx {4 0}
359    bind $itk_component(download) <Enter> \
360        [itcl::code $this download coming]
361
362    $itk_component(viewselector) choices insert end \
363        @download [Rappture::filexfer::label download]
364
365    if {[Rappture::filexfer::enabled]} {
366        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.
367
368NOTE:  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."
369    } else {
370        Rappture::Tooltip::for $itk_component(download) "Saves the current result to a file on your desktop."
371    }
372
373    itk_component add results {
374        Rappture::Panes $w.pane \
375            -sashwidth 2 -sashrelief solid -sashpadding {2 0}
376    } {
377        usual
378        ignore -sashwidth -sashrelief -sashpadding
379    }
380    pack $itk_component(results) -expand yes -fill both
381    set f [$itk_component(results) pane 0]
382
383    itk_component add resultpages {
384        Rappture::Notebook $f.nb
385    }
386    pack $itk_component(resultpages) -expand yes -fill both
387    set f [$itk_component(results) insert end -fraction 0.1]
388    itk_component add resultselector {
389        Rappture::ResultSelector $f.rsel -resultset $_resultset \
390            -settingscommand [itcl::code $this _plot]
391    }
392    pack $itk_component(resultselector) -expand yes -fill both
393    bind $itk_component(resultselector) <<Layout>> [itcl::code $this _fixSize]
394    bind $itk_component(results) <Configure> [itcl::code $this _fixSize]
395
396    eval itk_initialize $args
397
398    $itk_component(runinfo) tag configure ERROR -foreground red
399    $itk_component(runinfo) tag configure text -font $itk_option(-textfont)
400
401    #
402    # Load up tool info on the first page.
403    #
404    $itk_component(toolinfo) tag configure title \
405        -font $itk_option(-boldtextfont)
406
407    set mesg [string trim [$tool xml get tool.title]]
408    if {"" != $mesg} {
409        $itk_component(toolinfo) insert end $mesg title
410        $itk_component(toolinfo) insert end "\n\n"
411    }
412
413    set mesg [string trim [$tool xml get tool.about]]
414    if {"" != $mesg} {
415        $itk_component(toolinfo) insert end $mesg
416    }
417    $itk_component(toolinfo) configure -state disabled
418    $itk_component(notebook) current about
419
420    # tool can run on "manual" (default) or "auto"
421    set cntl [string trim [$tool xml get tool.control]]
422    if {"" == $cntl} {
423        set cntl [string trim [$tool xml get tool.control.type]]
424    }
425    if {"" != $cntl} {
426        set _control $cntl
427    }
428
429    # reset everything to a clean state
430    reset
431}
432
433# ----------------------------------------------------------------------
434# DESTRUCTOR
435# ----------------------------------------------------------------------
436itcl::body Rappture::Analyzer::destructor {} {
437    after cancel [itcl::code $this simulate]
438    $_resultset notify remove $this
439    itcl::delete object $_resultset
440}
441
442# ----------------------------------------------------------------------
443# USAGE: simulate ?-ifneeded?
444# USAGE: simulate ?<path1> <value1> <path2> <value2> ...?
445#
446# Kicks off the simulator by executing the tool.command associated
447# with the tool.  If any arguments are specified, they are used to
448# set parameters for the simulation.  While the simulation is running,
449# it shows status.  When the simulation is finished, it switches
450# automatically to "analyze" mode and shows the results.
451# ----------------------------------------------------------------------
452itcl::body Rappture::Analyzer::simulate {args} {
453    #puts "simulate args='$args'"
454
455    set uq [$_tool get_uq -uq_type smolyak -uq_args 2]
456
457    # pop up UQ window
458    if {[$uq num_runs] > 1} {
459        set _uq_active 1
460        set status [$uq run_dialog $itk_component(simulate)]
461        if {$status == 0} {
462            # cancelled
463            return
464        }
465        lappend args -uq_type [$uq type]
466        lappend args -uq_args [$uq args]
467        # Need to put these UQ values into the driver file
468        # so the call to resultset::contains will be correct.
469        set _xml [$_tool xml object]
470        $_xml put uq.type.current [$uq type]
471        $_xml put uq.args.current [$uq args]
472        $_xml put uq.args.about.label "level"
473        $_xml put uq.args.about.description "Polynomial Degree of Smolyak GPC method."
474    }
475    #puts "simulate args=$args"
476
477    if {[lindex $args 0] == "-ifneeded"} {
478        # check to see if simulation is really needed
479        $_tool sync
480        if {[$_resultset contains [$_tool xml object]]
481              && ![string equal $_control "manual-resim"]} {
482            # not needed -- show results and return
483            $itk_component(notebook) current analyze
484            return
485        }
486        set args [lreplace $args 0 0]
487    }
488
489    # simulation is needed -- go to simulation page
490    $itk_component(notebook) current simulate
491
492    # no progress messages yet
493    pack forget $itk_component(progress)
494    lappend args -output [itcl::code $this _simOutput]
495
496    _simState off
497    $itk_component(runinfo) configure -state normal
498    $itk_component(runinfo) delete 1.0 end
499    $itk_component(runinfo) insert end "Running simulation...\n\n" text
500    $itk_component(runinfo) configure -state disabled
501
502    # if the hold window is set, then put up a busy cursor
503    if {$itk_option(-holdwindow) != ""} {
504        blt::busy hold $itk_option(-holdwindow)
505        raise $itk_component(hull)
506    }
507
508    # execute the job
509    #puts "$_tool run $args"
510
511    foreach {status result} [eval $_tool run $args] break
512
513    # if job was aborted, then allow simulation again
514    if {$result == "ABORT"} {
515        _simState on "Aborted"
516    }
517
518    # load results from run.xml into analyzer
519    if {$status == 0 && $result != "ABORT"} {
520        set status [catch {load $result} result]
521    }
522
523    # back to normal
524    if {$itk_option(-holdwindow) != ""} {
525        blt::busy release $itk_option(-holdwindow)
526    }
527    $itk_component(abort) configure -state disabled
528
529    if {$status != 0} {
530        $itk_component(runinfo) configure -state normal
531        # Don't erase program error messages.
532        # $itk_component(runinfo) delete 1.0 end
533        $itk_component(runinfo) insert end "\n\nProblem launching job:\n\n" text
534        _simOutput $result
535        $itk_component(runinfo) configure -state disabled
536        $itk_component(runinfo) see 1.0
537
538        # Try to create a support ticket for this error.
539        # It may be a real problem.
540        if {[Rappture::bugreport::shouldReport for jobs]} {
541            set ::errorInfo "\n\n== RAPPTURE INPUT ==\n[$_tool xml xml]"
542            Rappture::bugreport::register "Problem launching job:\n$result"
543            Rappture::bugreport::attachment [$_tool xml xml]
544            Rappture::bugreport::send
545        }
546    } else {
547        $itk_component(notebook) current analyze
548    }
549
550    # do this last -- after _simOutput above
551    pack forget $itk_component(progress)
552}
553
554
555# ----------------------------------------------------------------------
556# USAGE: reset ?-eventually|-now?
557#
558# Used to reset the analyzer whenever the input to a simulation has
559# changed.  Sets the mode back to "simulate", so the user has to
560# simulate again to see the output.  If the <start> option is set
561# to "auto", the simulation is invoked immediately.
562# ----------------------------------------------------------------------
563itcl::body Rappture::Analyzer::reset {{when -eventually}} {
564    if {$when == "-eventually"} {
565        after cancel [list catch [itcl::code $this reset -now]]
566        after idle [list catch [itcl::code $this reset -now]]
567        return
568    }
569
570    # check to see if simulation is really needed
571    $_tool sync
572    if {![$_resultset contains [$_tool xml object]]
573          || [string equal $_control "manual-resim"]} {
574        # if control mode is "auto", then simulate right away
575        if {[string match auto* $_control]} {
576            # auto control -- don't need button
577            pack forget $itk_interior.simol
578
579            after cancel [itcl::code $this simulate]
580            after idle [itcl::code $this simulate]
581        } else {
582            _simState on "new input parameters"
583        }
584    } else {
585        _simState off
586    }
587}
588
589# ----------------------------------------------------------------------
590# USAGE: load <xmlobj>
591#
592# Loads the data from the given <xmlobj> into the appropriate results
593# sets.  If necessary, new results sets are created to store the data.
594# ----------------------------------------------------------------------
595itcl::body Rappture::Analyzer::load {xmlobj} {
596    # only show the last result? then clear first
597    if {[string trim [$_tool xml get tool.analyzer]] == "last"} {
598        clear
599    }
600    #puts "Analyzer::load"
601    $_resultset add $xmlobj
602
603    # NOTE: Adding will trigger a !change event on the ResultSet
604    # object, which will trigger calls to _fixResultSet to add
605    # the results to display.
606}
607
608# ----------------------------------------------------------------------
609# USAGE: clear ?<xmlobj>?
610#
611# Discards one or more results previously loaded into the analyzer.
612# If an <xmlobj> is specified, then that one result is cleared.
613# Otherwise, all results are cleared.
614# ----------------------------------------------------------------------
615itcl::body Rappture::Analyzer::clear {{xmlobj "all"}} {
616    if {$xmlobj eq "" || $xmlobj eq "all"} {
617        $_resultset clear
618    } else {
619        $_resultset clear $xmlobj
620    }
621
622    # NOTE: Clearing will trigger a !change event on the ResultSet
623    # object, which will trigger calls to _fixResultSet to clean up
624    # the results being displayed.
625}
626
627# ----------------------------------------------------------------------
628# USAGE: download coming
629# USAGE: download controls <downloadCommand>
630# USAGE: download start ?widget?
631# USAGE: download now ?widget?
632#
633# Spools the current result so the user can download it.
634# ----------------------------------------------------------------------
635itcl::body Rappture::Analyzer::download {option args} {
636    set title [$itk_component(viewselector) value]
637    set page [$itk_component(viewselector) translate $title]
638
639    switch -- $option {
640        coming {
641            #
642            # Warn result that a download is coming, in case
643            # it needs to take a screen snap.
644            #
645            if {![regexp {^(|@download|---)$} $page]} {
646                set f [$itk_component(resultpages) page $page]
647                $f.rviewer download coming
648            }
649        }
650        controls {
651            # no controls for this download yet
652            return ""
653        }
654        start {
655            set widget $itk_component(download)
656            if {[llength $args] > 0} {
657                set widget [lindex $args 0]
658                if {[catch {winfo class $widget}]} {
659                    set widget $itk_component(download)
660                }
661            }
662            #
663            # See if this download has any controls.  If so, then
664            # post them now and let the user continue the download
665            # after selecting a file format.
666            #
667            if {$page != ""} {
668                set ext ""
669                set f [$itk_component(resultpages) page $page]
670                set arg [itcl::code $this download now $widget]
671                set popup [$f.rviewer download controls $arg]
672                if {"" != $popup} {
673                    $popup activate $widget below
674                } else {
675                    download now $widget
676                }
677            } else {
678                # this shouldn't happen
679                set file error.html
680                set data "<h1>Not Found</h1>There is no result selected."
681            }
682        }
683        now {
684            set widget $itk_component(download)
685            if {[llength $args] > 0} {
686                set widget [lindex $args 0]
687                if {[catch {winfo class $widget}]} {
688                    set widget $itk_component(download)
689                }
690            }
691            #
692            # Perform the actual download.
693            #
694            if {$page != ""} {
695                set ext ""
696                set f [$itk_component(resultpages) page $page]
697                set item [$itk_component(viewselector) value]
698                set result [$f.rviewer download now $widget $_appName $item]
699                if { $result == "" } {
700                    return;                # User cancelled the download.
701                }
702                foreach {ext data} $result break
703                if {"" == $ext} {
704                    if {"" != $widget} {
705                        Rappture::Tooltip::cue $widget \
706                            "Can't download this result."
707                    }
708                    return
709                }
710                regsub -all {[\ -\/\:-\@\{-\~]} $title {} title
711                set file "$title$ext"
712            } else {
713                # this shouldn't happen
714                set file error.html
715                set data "<h1>Not Found</h1>There is no result selected."
716            }
717
718            Rappture::Logger::log download [$itk_component(viewselector) value]
719            set mesg [Rappture::filexfer::download $data $file]
720            if {[string length $mesg] > 0} {
721                Rappture::Tooltip::cue $widget $mesg
722            }
723        }
724        default {
725            error "bad option \"$option\": should be coming, controls, now, start"
726        }
727    }
728}
729
730# ----------------------------------------------------------------------
731# USAGE: _plot ?<index> <options> <index> <options>...?
732#
733# Used internally to update the plot shown in the current result
734# viewer whenever the resultselector settings have changed.  Causes the
735# desired results to show up on screen.
736# ----------------------------------------------------------------------
737itcl::body Rappture::Analyzer::_plot {args} {
738    #puts "analyzer::_plot"
739    set _plotlist $args
740
741    set page [$itk_component(viewselector) value]
742    set page [$itk_component(viewselector) translate $page]
743    if {"" != $page} {
744        set f [$itk_component(resultpages) page $page]
745        $f.rviewer plot clear
746        foreach {index opts} $_plotlist {
747            $f.rviewer plot add $index $opts
748        }
749    }
750}
751
752# ----------------------------------------------------------------------
753# USAGE: _reorder <compList>
754#
755# Used internally to change the order of a series of output components
756# found in the <output> section.  Moves the <log> elements to the end
757# and returns the updated list.
758# ----------------------------------------------------------------------
759itcl::body Rappture::Analyzer::_reorder {comps} {
760    set i 0
761    set max [llength $comps]
762    while {$i < $max} {
763        set c [lindex $comps $i]
764        if {[string match log* $c]} {
765            set comps [lreplace $comps $i $i]
766            lappend comps $c
767            incr max -1
768        } else {
769            incr i
770        }
771    }
772    return $comps
773}
774
775# ----------------------------------------------------------------------
776# USAGE: _autoLabel <xmlobj> <path> <title> <cntVar>
777#
778# Used internally to check for an about.label property at the <path>
779# in <xmlobj>.  If this object doesn't have a label, then one is
780# supplied using the given <title>.  The <cntVar> is an array of
781# counters in the calling scopes for titles that have been used
782# in the past.  This is used to create titles like "Plot #2" the
783# second time it is encountered.
784#
785# The <xmlobj> is updated so that the label is inserted directly in
786# the tree.
787# ----------------------------------------------------------------------
788itcl::body Rappture::Analyzer::_autoLabel {xmlobj path title cntVar} {
789    upvar $cntVar counters
790
791    set group [$xmlobj get $path.about.group]
792    set label [$xmlobj get $path.about.label]
793    if {"" == $label} {
794        # no label -- make one up using the title specified
795        if {![info exists counters($group-$title)]} {
796            set counters($group-$title) 1
797            set label $title
798        } else {
799            set label "$title (#[incr counters($group-$title)])"
800        }
801        $xmlobj put $path.about.label $label
802    } else {
803        # handle the case of two identical labels in <output>
804        if {![info exists counters($group-$label)]} {
805            set counters($group-$label) 1
806        } else {
807            set label "$label (#[incr counters($group-$label)])"
808            $xmlobj put $path.about.label $label
809        }
810    }
811    return $label
812}
813
814# ----------------------------------------------------------------------
815# USAGE: _fixResult
816#
817# Used internally to change the result page being displayed whenever
818# the user selects a page from the results combobox.
819# ----------------------------------------------------------------------
820itcl::body Rappture::Analyzer::_fixResult {} {
821    set name [$itk_component(viewselector) value]
822    set page ""
823    if {"" != $name} {
824        set page [$itk_component(viewselector) translate $name]
825    }
826    if {$page == "@download"} {
827        # put the combobox back to its last value
828        $itk_component(viewselector) component entry configure -state normal
829        $itk_component(viewselector) component entry delete 0 end
830        $itk_component(viewselector) component entry insert end $_lastlabel
831        $itk_component(viewselector) component entry configure -state disabled
832        # perform the actual download
833        download start $itk_component(download)
834    } elseif {$page == "---"} {
835        # put the combobox back to its last value
836        $itk_component(viewselector) component entry configure -state normal
837        $itk_component(viewselector) component entry delete 0 end
838        $itk_component(viewselector) component entry insert end $_lastlabel
839        $itk_component(viewselector) component entry configure -state disabled
840    } elseif {$page != ""} {
841        set _lastlabel $name
842        $itk_component(resultpages) current $page
843        set f [$itk_component(resultpages) page $page]
844        # We don't want to replot if we're using an existing viewer with the
845        # the same list of objects to plot.  So track the viewer and the list.
846        if { ![info exists _lastPlot($f)] || $_plotlist != $_lastPlot($f) } {
847            set _lastPlot($f) $_plotlist
848            set win [winfo toplevel $itk_component(hull)]
849            blt::busy hold $win
850            #puts "rviewer = $f.rviewer"
851            #puts "_plotlist = $_plotlist"
852            $f.rviewer plot clear
853            eval $f.rviewer plot add $_plotlist
854            blt::busy release $win
855        }
856        Rappture::Logger::log output $_label2item($name)
857        Rappture::Tooltip::for $itk_component(viewselector) \
858            "@[itcl::code $this _resultTooltip]" -log $_label2item($name)
859    }
860}
861
862# ----------------------------------------------------------------------
863# USAGE: _fixResultSet ?<eventData>...?
864#
865# Used internally to react to changes within the ResultSet.  When a
866# result is added, a new result viewer is created for the object.
867# When all results are cleared, the viewers are deleted.
868# ----------------------------------------------------------------------
869itcl::body Rappture::Analyzer::_fixResultSet {args} {
870    #puts "Analyzer::_fixResultSet $args"
871    array set eventData $args
872    switch -- $eventData(op) {
873        add {
874            set xmlobj $eventData(what)
875
876            # Detect molecule elements that contain trajectory data
877            # and convert to sequences.
878            _trajToSequence $xmlobj output
879
880            # Go through the analysis and find all result sets.
881            set haveresults 0
882            foreach item [_reorder [$xmlobj children output]] {
883                if {[$xmlobj get output.$item.about.uqtype] == ""} {
884                    switch -glob -- $item {
885                        log* {
886                            _autoLabel $xmlobj output.$item "Output Log" counters
887                        }
888                        number* {
889                            _autoLabel $xmlobj output.$item "Number" counters
890                        }
891                        integer* {
892                            _autoLabel $xmlobj output.$item "Integer" counters
893                        }
894                        mesh* {
895                            _autoLabel $xmlobj output.$item "Mesh" counters
896                        }
897                        string* {
898                            _autoLabel $xmlobj output.$item "String" counters
899                        }
900                        histogram* - curve* - field* {
901                            _autoLabel $xmlobj output.$item "Plot" counters
902                        }
903                        drawing* {
904                            _autoLabel $xmlobj output.$item "Drawing" counters
905                        }
906                        structure* {
907                            _autoLabel $xmlobj output.$item "Structure" counters
908                        }
909                        table* {
910                            _autoLabel $xmlobj output.$item "Energy Levels" counters
911                        }
912                        sequence* {
913                            _autoLabel $xmlobj output.$item "Sequence" counters
914                        }
915                    }
916                }
917                set label [$xmlobj get output.$item.about.group]
918                if {"" == $label} {
919                    set label [$xmlobj get output.$item.about.label]
920                }
921
922                set hidden [$xmlobj get output.$item.hide]
923                set hidden [expr {"" != $hidden && $hidden}]
924
925                if {"" != $label && !$hidden} {
926                    set haveresults 1
927                }
928            }
929
930            # if there are any valid results, add them to the resultset
931            if {$haveresults} {
932                set index [$_resultset get simnum $xmlobj]
933
934                # add each result to a result viewer
935                foreach item [_reorder [$xmlobj children output]] {
936                    set label [$xmlobj get output.$item.about.group]
937                    if {"" == $label} {
938                        set label [$xmlobj get output.$item.about.label]
939                    }
940                    set hidden [$xmlobj get output.$item.hide]
941                    if {$hidden == ""} {
942                        set hidden 0
943                    }
944                    if {"" != $label && !$hidden} {
945                        set uq_part [$xmlobj get output.$item.about.uqtype]
946
947                        #puts "label=$label uq_part=$uq_part"
948
949                        if {![info exists _label2page($label)]} {
950                            #puts "Adding label: '$label'"
951                            set name "page[incr _pages]"
952                            #puts "Inserting $name into resultpages"
953                            set page [$itk_component(resultpages) \
954                                insert end $name]
955                            set _label2page($label) $page
956                            set _label2item($label) output.$item
957                            set _label2desc($label) \
958                                [$xmlobj get output.$item.about.description]
959                            Rappture::ResultViewer $page.rviewer
960                            pack $page.rviewer -expand yes -fill both -pady 4
961
962                            set end [$itk_component(viewselector) \
963                                choices index -value ---]
964                            if {$end < 0} {
965                                set end "end"
966                            }
967                            $itk_component(viewselector) choices insert $end \
968                                $name $label
969                        }
970
971                        # add/replace the latest result into this viewer
972                        set page $_label2page($label)
973
974                        if {![info exists reset($page)]} {
975                            $page.rviewer clear $index
976                            set reset($page) 1
977                        }
978                        $page.rviewer add $index $xmlobj output.$item $label $uq_part
979                    }
980                }
981            }
982
983            # show the first page by default
984            set max [$itk_component(viewselector) choices size]
985            for {set i 0} {$i < $max} {incr i} {
986                set first [$itk_component(viewselector) choices get -label $i]
987                if {$first != ""} {
988                    set page [$itk_component(viewselector) choices get -value $i]
989                    set char [string index $page 0]
990                    if {$char != "@" && $char != "-"} {
991                        $itk_component(resultpages) current $page
992                        $itk_component(viewselector) value $first
993                        set _lastlabel $first
994                        break
995                    }
996                }
997            }
998        }
999        clear {
1000            if {$eventData(what) ne "all"} {
1001                # delete this result from all viewers
1002                array set params $eventData(what)
1003                foreach label [array names _label2page] {
1004                    set page $_label2page($label)
1005                    $page.rviewer clear $params(simnum)
1006                }
1007            }
1008
1009            if {[$_resultset size] == 0} {
1010                # reset the size of the controls area
1011                set ht [winfo height $itk_component(results)]
1012                set cntlht [$itk_component(resultselector) size -controlarea]
1013                set frac [expr {double($cntlht)/$ht}]
1014                $itk_component(results) fraction end $frac
1015
1016                foreach label [array names _label2page] {
1017                    set page $_label2page($label)
1018                    destroy $page.rviewer
1019                }
1020                $itk_component(resultpages) delete -all
1021                set _pages 0
1022
1023                $itk_component(viewselector) value ""
1024                $itk_component(viewselector) choices delete 0 end
1025                catch {unset _label2page}
1026                catch {unset _label2item}
1027                catch {unset _label2desc}
1028                set _plotlist ""
1029
1030                $itk_component(viewselector) choices insert end --- "---"
1031                $itk_component(viewselector) choices insert end \
1032                    @download [Rappture::filexfer::label download]
1033                set _lastlabel ""
1034            }
1035
1036            # fix Simulate button state
1037            reset
1038        }
1039        default {
1040            error "don't know how to handle op \"$eventData(op)\""
1041        }
1042    }
1043}
1044
1045# ----------------------------------------------------------------------
1046# USAGE: _fixSize
1047#
1048# Used internally to change the size of the result set area whenever
1049# a new control appears.  Adjusts the size available for the result
1050# set up to some maximum.
1051# ----------------------------------------------------------------------
1052itcl::body Rappture::Analyzer::_fixSize {} {
1053    set ht [winfo height $itk_component(results)]
1054    if {$ht <= 1} { set ht [winfo reqheight $itk_component(results)] }
1055    set cntlht [$itk_component(resultselector) size -controlarea]
1056    set frac [expr {double($cntlht)/$ht}]
1057
1058    if {$frac < 0.4} {
1059        $itk_component(results) fraction end $frac
1060    }
1061    _fixSimControl
1062}
1063
1064# ----------------------------------------------------------------------
1065# USAGE: _simState <boolean> ?<message>? ?<settings>?
1066#
1067# Used internally to change the "Simulation" button on or off.
1068# If the <boolean> is on, then any <message> and <settings> are
1069# displayed as well.  If the <boolean> is off, then only display
1070# the message. The <message> is a note to the user about
1071# what will be simulated, and the <settings> are a list of
1072# tool parameter settings of the form {path1 val1 path2 val2 ...}.
1073# When these are in place, the next Simulate operation will use
1074# these settings.  This helps fill in missing data values.
1075# ----------------------------------------------------------------------
1076itcl::body Rappture::Analyzer::_simState {state args} {
1077    if {$state} {
1078        $itk_interior.simol configure \
1079            -background $itk_option(-simcontrolactiveoutline)
1080        configure -simcontrolcolor $itk_option(-simcontrolactivebackground)
1081
1082        $itk_component(abort) configure -state disabled
1083        $itk_component(simulate) configure -state normal \
1084            -command [itcl::code $this simulate]
1085
1086        #
1087        # If there's a special message, then put it up next to the button.
1088        #
1089        set mesg [lindex $args 0]
1090        if {"" != $mesg} {
1091            $itk_component(simstatus) configure -state normal
1092            $itk_component(simstatus) delete 1.0 end
1093            $itk_component(simstatus) insert end $mesg
1094
1095            #
1096            # If there are any settings, then install them in the
1097            # "Simulate" button.  Also, pop them up as a tooltip
1098            # for the message.
1099            #
1100            set settings [lindex $args 1]
1101            if {[llength $settings] > 0} {
1102                $itk_component(simulate) configure \
1103                    -command [eval itcl::code $this simulate $settings]
1104
1105                set details ""
1106                foreach {path val} $settings {
1107                    set str [string trim [$_tool xml get $path.about.label]]
1108                    if {"" == $str} {
1109                        set str [$_tool xml element -as id $path]
1110                    }
1111                    append details "$str = $val\n"
1112                }
1113                set details [string trim $details]
1114
1115                Rappture::Tooltip::for $itk_component(simstatus) $details
1116                $itk_component(simstatus) insert end " "
1117                $itk_component(simstatus) insert end "(details...)" popup
1118            }
1119            $itk_component(simstatus) configure -state disabled
1120        }
1121    } else {
1122        if {"" != $itk_option(-simcontrolbackground)} {
1123            set simcbg $itk_option(-simcontrolbackground)
1124        } else {
1125            set simcbg $itk_option(-background)
1126        }
1127        $itk_interior.simol configure \
1128            -background $itk_option(-simcontroloutline)
1129        configure -simcontrolcolor $simcbg
1130
1131        if {$_uq_active == 0} {
1132            $itk_component(simulate) configure -state disabled
1133        }
1134        $itk_component(abort) configure -state normal
1135
1136        $itk_component(simstatus) configure -state normal
1137        $itk_component(simstatus) delete 1.0 end
1138        set mesg [lindex $args 0]
1139        if {"" != $mesg} {
1140            $itk_component(simstatus) insert end $mesg
1141        }
1142        $itk_component(simstatus) configure -state disabled
1143    }
1144}
1145
1146# ----------------------------------------------------------------------
1147# USAGE: _simOutput <message>
1148#
1149# Invoked automatically whenever output comes in while running the
1150# tool.  Extracts any =RAPPTURE-???=> messages from the output and
1151# sends the output to the display.  For example, any
1152# =RAPPTURE-PROGRESS=> message pops up the progress meter and updates
1153# it to show the latest progress message.  This is useful for
1154# long-running tools, to let the user know how much longer the
1155# simulation will take.
1156# ----------------------------------------------------------------------
1157itcl::body Rappture::Analyzer::_simOutput {message} {
1158    #
1159    # Scan through and pick out any =RAPPTURE-PROGRESS=> messages first.
1160    #
1161
1162    while {[regexp -indices \
1163               {=RAPPTURE-PROGRESS=> *([-+]?[0-9]+) +([^\n]*)(\n|$)} $message \
1164                match percent mesg]} {
1165
1166        foreach {i0 i1} $percent break
1167        set percent [string range $message $i0 $i1]
1168
1169        foreach {i0 i1} $mesg break
1170        set mesg [string range $message $i0 $i1]
1171
1172        pack $itk_component(progress) -fill x -padx 10 -pady 10
1173        $itk_component(progress) settings -percent $percent -message $mesg
1174
1175        foreach {i0 i1} $match break
1176        set message [string replace $message $i0 $i1]
1177    }
1178
1179    #
1180    # Now handle SUBMIT-PROGRESS
1181    #
1182    while {[regexp -indices {=SUBMIT-PROGRESS=> aborted=([0-9]+) finished=([0-9]+) failed=([0-9]+) executing=([0-9]+)\
1183        waiting=([0-9]+) setting_up=([0-9]+) setup=([0-9]+) %done=([0-9.]+) timestamp=([0-9.]+)(\n|$)} $message \
1184        match aborted finished failed executing waiting setting_up setup percent ts mesg]} {
1185
1186        set mesg ""
1187        foreach {i0 i1} $percent break
1188        set percent [string range $message $i0 $i1]
1189        foreach {i0 i1} $failed break
1190        set failed [string range $message $i0 $i1]
1191        foreach {i0 i1} $match break
1192        set message [string replace $message $i0 $i1]
1193
1194        if {$failed != 0} {set mesg "$failed jobs failed!"}
1195        if {$percent >= 100} { set mesg "Jobs finished.  Analyzing results..."}
1196
1197        pack $itk_component(progress) -fill x -padx 10 -pady 10
1198        $itk_component(progress) settings -percent $percent -message $mesg
1199    }
1200
1201    #
1202    # Break up the remaining lines according to =RAPPTURE-ERROR=> messages.
1203    # Show errors in a special color.
1204    #
1205    $itk_component(runinfo) configure -state normal
1206
1207    while {[regexp -indices \
1208               {=RAPPTURE-([a-zA-Z]+)=>([^\n]*)(\n|$)} $message \
1209                match type mesg]} {
1210
1211        foreach {i0 i1} $match break
1212        set first [string range $message 0 [expr {$i0-1}]]
1213        if {[string length $first] > 0} {
1214            $itk_component(runinfo) insert end $first
1215            $itk_component(runinfo) insert end \n
1216        }
1217
1218        foreach {t0 t1} $type break
1219        set type [string range $message $t0 $t1]
1220        foreach {m0 m1} $mesg break
1221        set mesg [string range $message $m0 $m1]
1222        if {[string length $mesg] > 0 && $type != "RUN"} {
1223            $itk_component(runinfo) insert end $mesg $type
1224            $itk_component(runinfo) insert end \n $type
1225        }
1226
1227        set message [string range $message [expr {$i1+1}] end]
1228    }
1229
1230    if {[string length $message] > 0} {
1231        $itk_component(runinfo) insert end $message
1232        if {[$itk_component(runinfo) get end-2char] != "\n"} {
1233            $itk_component(runinfo) insert end "\n"
1234        }
1235        $itk_component(runinfo) see end
1236    }
1237    $itk_component(runinfo) configure -state disabled
1238}
1239
1240# ----------------------------------------------------------------------
1241# USAGE: _resultTooltip
1242#
1243# Used internally to build the tooltip string displayed for the
1244# result selector.  If the current page has an associated description,
1245# then it is displayed beneath the result.
1246#
1247# Returns the string for the tooltip.
1248# ----------------------------------------------------------------------
1249itcl::body Rappture::Analyzer::_resultTooltip {} {
1250    set tip ""
1251    set name [$itk_component(viewselector) value]
1252    if {[info exists _label2desc($name)] &&
1253         [string length $_label2desc($name)] > 0} {
1254        append tip "$_label2desc($name)\n\n"
1255    }
1256    if {[array size _label2page] > 1} {
1257        append tip "Use this control to display other output results."
1258    }
1259    return $tip
1260}
1261
1262# ----------------------------------------------------------------------
1263# USAGE: _fixSimControl
1264#
1265# Used internally to add or remove the simulation control at the
1266# top of the analysis area.  This is controlled by the -simcontrol
1267# option.
1268# ----------------------------------------------------------------------
1269itcl::body Rappture::Analyzer::_fixSimControl {} {
1270    switch -- $itk_option(-simcontrol) {
1271        on {
1272            pack $itk_interior.simol -fill x -before $itk_interior.nb
1273        }
1274        off {
1275            pack forget $itk_interior.simol
1276        }
1277        auto {
1278            #
1279            # If we have two or more radiodials, then there is a
1280            # chance of encountering a combination of parameters
1281            # with no data, requiring simulation.
1282            #
1283            if {[$itk_component(resultselector) size -controls] >= 2} {
1284                pack $itk_interior.simol -fill x -before $itk_interior.nb
1285            } else {
1286                pack forget $itk_interior.simol
1287            }
1288        }
1289        default {
1290            error "bad value \"$itk_option(-simcontrol)\": should be on, off, auto"
1291        }
1292    }
1293}
1294
1295# ----------------------------------------------------------------------
1296# USAGE: _fixNotebook
1297#
1298# Used internally to switch the active notebook page
1299# ----------------------------------------------------------------------
1300itcl::body Rappture::Analyzer::_fixNotebook {} {
1301    switch -- $itk_option(-notebookpage) {
1302        about {
1303            $itk_component(notebook) current about
1304        }
1305        simulate {
1306            $itk_component(notebook) current simulate
1307        }
1308        analyze {
1309            $itk_component(notebook) current analyze
1310        }
1311        default {
1312            error "bad value \"$itk_option(-notebookpage)\": should be about, simulate, analyze"
1313        }
1314    }
1315}
1316
1317# ----------------------------------------------------------------------
1318# USAGE: _isPdbTrajectory <data>
1319#
1320# Used internally to determine whether pdb or lammps data represents a
1321# trajectory rather than a single frame
1322# ----------------------------------------------------------------------
1323itcl::body Rappture::Analyzer::_isPdbTrajectory {data} {
1324    if { [llength $data] == 0 } {
1325        return 0
1326    }
1327    set nModels 0
1328    foreach line $data {
1329        if { [string match "MODEL*" $line] }  {
1330            incr nModels
1331            if { $nModels > 1 } {
1332                # Stop if more than one model found.  No need to count them
1333                # all.
1334                return 1
1335            }
1336        }
1337    }
1338    return 0
1339}
1340
1341# ----------------------------------------------------------------------
1342# USAGE: _isLammpsTrajectory <data>
1343#
1344# Used internally to determine whether pdb or lammps data represents a
1345# trajectory rather than a single frame
1346# ----------------------------------------------------------------------
1347itcl::body Rappture::Analyzer::_isLammpsTrajectory { data } {
1348    if { [llength $data] == 0 } {
1349        return 0
1350    }
1351    set nModels 0
1352    foreach line $data {
1353        if { [regexp {^[\t ]*ITEM:[ \t]+TIMESTEP} $line] } {
1354            incr nModels
1355            if { $nModels > 1 } {
1356                # Stop if more than one model found.  No need to count them
1357                # all.
1358                return 1
1359            }
1360        }
1361    }
1362    return 0
1363}
1364
1365# ----------------------------------------------------------------------
1366# USAGE: _pdbToSequence <xmlobj> ?<path>?
1367#
1368# If the molecule element is a trajectory, delete the original
1369# and create a sequence of individual molecules.
1370# Used internally to detect any molecule output elements that contain
1371# trajectory data.  Trajectories will be converted into sequences of
1372# individual molecules.  All other elements will be unaffected. Scans
1373# the entire xml tree if a starting path is not specified.
1374# ----------------------------------------------------------------------
1375itcl::body Rappture::Analyzer::_pdbToSequence {xmlobj path id child data} {
1376
1377    set seqLabel [$xmlobj get ${child}.about.label]
1378    set descr    [$xmlobj get ${child}.about.description]
1379    set formula  [$xmlobj get ${child}.components.molecule.formula]
1380    $xmlobj remove $child
1381
1382    set sequence  $path.sequence($id)
1383    $xmlobj put ${sequence}.about.label $seqLabel
1384    $xmlobj put ${sequence}.about.description $descr
1385    $xmlobj put ${sequence}.index.label "Frame"
1386
1387    set frameNum 0
1388    set numLines [llength $data]
1389    for { set i 0 } { $i < $numLines } { incr i } {
1390        set line [lindex $data $i]
1391        set line [string trim $line]
1392        set contents {}
1393        if { [string match "MODEL*" $line] } {
1394            # Save the contents until we get an ENDMDL record.
1395            for {} { $i < $numLines } { incr i } {
1396                set line [lindex $data $i]
1397                set line [string trim $line]
1398                if { $line == "" } {
1399                    continue;           # Skip blank lines.
1400                }
1401                if { [string match "ENDMDL*" $line] } {
1402                    break;
1403                }
1404                append contents $line\n
1405            }
1406            set frame ${sequence}.element($frameNum)
1407            $xmlobj put ${frame}.index $frameNum
1408
1409            set molecule ${frame}.structure.components.molecule
1410            $xmlobj put ${molecule}.pdb $contents
1411            $xmlobj put ${molecule}.formula $formula
1412            incr frameNum
1413        }
1414    }
1415}
1416
1417# ----------------------------------------------------------------------
1418# USAGE: _lammpsToSequence <xmlobj> ?<path>?
1419#
1420# If the molecule element is a trajectory, delete the original
1421# and create a sequence of individual molecules.
1422# Used internally to detect any molecule output elements that contain
1423# trajectory data.  Trajectories will be converted into sequences of
1424# individual molecules.  All other elements will be unaffected. Scans
1425# the entire xml tree if a starting path is not specified.
1426# ----------------------------------------------------------------------
1427itcl::body Rappture::Analyzer::_lammpsToSequence {xmlobj path id child data} {
1428
1429    set seqLabel [$xmlobj get ${child}.about.label]
1430    set descr    [$xmlobj get ${child}.about.description]
1431    set typemap  [$xmlobj get ${child}.components.molecule.lammpstypemap]
1432    $xmlobj remove $child
1433
1434    set sequence ${path}.sequence($id)
1435    $xmlobj put ${sequence}.about.label $seqLabel
1436    $xmlobj put ${sequence}.about.description $descr
1437    $xmlobj put ${sequence}.index.label "Frame"
1438
1439    set frameNum 0
1440    set frameContents ""
1441    set inModel 0
1442    foreach line $data {
1443        set line [string trim $line]
1444        if { $line == "" } {
1445            continue;                   # Skip blank lines
1446        }
1447        if {[regexp {^[\t ]*ITEM:[ \t]+ATOMS} $line] } {
1448            if { $inModel && $frameContents != "" } {
1449                set frame ${sequence}.element($frameNum)
1450                $xmlobj put ${frame}.index $frameNum
1451
1452                set molecule ${frame}.structure.components.molecule
1453                $xmlobj put ${molecule}.lammps $frameContents
1454                $xmlobj put ${molecule}.lammpstypemap $typemap
1455
1456                incr frameNum
1457                set frameContents ""
1458            }
1459            set inModel 1
1460        } elseif { [scan $line "%d %d %f %f %f" a b c d e] == 5 } {
1461            if { !$inModel } {
1462                puts stderr "found \"$line\" without previous \"ITEM: ATOMS\""
1463                set inModel 1
1464            }
1465            append frameContents $line\n
1466        }
1467    }
1468    if { $frameContents != "" } {
1469        set frame ${sequence}.element($frameNum)
1470        $xmlobj put ${frame}.index $frameNum
1471
1472        set molecule ${frame}.structure.components.molecule
1473        $xmlobj put ${molecule}.lammps $frameContents
1474        $xmlobj put ${molecule}.lammpstypemap $typemap
1475    }
1476}
1477
1478# ----------------------------------------------------------------------
1479# USAGE: _trajToSequence <xmlobj> ?<path>?
1480#
1481#       Check for PDB and LAMMPS trajectories in molecule data and rewrite
1482#       the individual models as a sequence of molecules.  Used internally
1483#       to detect any molecule output elements that contain trajectory data.
1484#       Trajectories will be converted into sequences of individual molecules.
1485#       All other elements will be unaffected. Scans the entire xml tree if a
1486#       starting path is not specified.
1487#
1488# ----------------------------------------------------------------------
1489itcl::body Rappture::Analyzer::_trajToSequence {xmlobj {path ""}} {
1490    # Remove leading dot from path, if present.
1491    if { [string index $path 0] == "." } {
1492        set path [string range $path 1 end]
1493    }
1494    # Otherwise check each child.
1495    foreach child [$xmlobj children $path] {
1496        set current ${path}.${child}
1497        if { [string match "structure*" $child] } {
1498            set isTraj [$xmlobj get ${current}.components.molecule.trajectory]
1499            if { $isTraj == "" || !$isTraj } {
1500                continue;               # Not a trajectory.
1501            }
1502            # Look for trajectory if molecule element found.  Check both pdb
1503            # data and lammps data.
1504            set type [$xmlobj element -as type $current]
1505            set id   [$xmlobj element -as id $current]
1506            set pdbdata    [$xmlobj get ${current}.components.molecule.pdb]
1507            set lammpsdata [$xmlobj get ${current}.components.molecule.lammps]
1508            if { $pdbdata != "" && $lammpsdata != "" } {
1509                puts stderr \
1510                    "found both <pdb> and <lammps> elements: picking pdb"
1511            }
1512            set pdbdata [split $pdbdata \n]
1513            set lammpsdata [split $lammpsdata \n]
1514            if { [_isPdbTrajectory $pdbdata] } {
1515                _pdbToSequence $xmlobj $path $id $current $pdbdata
1516            } elseif { [_isLammpsTrajectory $lammpsdata] } {
1517                _lammpsToSequence $xmlobj $path $id $current $lammpsdata
1518            }
1519            continue
1520        }
1521        if 0 {
1522        # Recurse over all child nodes.
1523        _trajToSequence $xmlobj $current
1524        }
1525    }
1526}
1527
1528# ----------------------------------------------------------------------
1529# CONFIGURATION OPTION: -simcontrol
1530#
1531# Controls whether or not the Simulate button is showing.  In some
1532# cases, it is not needed.
1533# ----------------------------------------------------------------------
1534itcl::configbody Rappture::Analyzer::simcontrol {
1535    _fixSimControl
1536}
1537
1538# ----------------------------------------------------------------------
1539# CONFIGURATION OPTION: -notebookpage
1540#
1541# Controls which page of the analyzer notebook is shown. It is
1542# particularly needed when using rerun, when you don't want to
1543# "simulate -ifneeded" because an actual simulation might be
1544# kicked off due to differences between tool.xml and run.xml
1545# ----------------------------------------------------------------------
1546itcl::configbody Rappture::Analyzer::notebookpage {
1547    _fixNotebook
1548}
1549
1550itcl::body Rappture::Analyzer::PostMenu { m } {
1551    if { [FindSimsetsForApp $_appName] == 0 } {
1552        $m entryconfigure "Load Simulations" -state disable
1553        $m entryconfigure "Publish Simulations" -state disable
1554        $m entryconfigure "Delete Simulations" -state disabled
1555    } else {
1556        $m entryconfigure "Load Simulations" -state normal
1557        $m entryconfigure "Publish Simulations" -state normal
1558        $m entryconfigure "Delete Simulations" -state normal
1559    }
1560    if { [$_resultset size] == 0 } {
1561        $m entryconfigure "Save Simulations" -state disabled
1562    } else {
1563        $m entryconfigure "Save Simulations" -state normal
1564    }
1565}
1566       
1567#
1568# Build Help menu
1569#
1570itcl::body Rappture::Analyzer::buildMenu { m url appName } {
1571    menu $m \
1572        -tearoff 0 \
1573        -postcommand [itcl::code $this PostMenu $m]
1574    if { $appName == "" || $url == "" } {
1575        set state disabled
1576    } else {
1577        set state normal
1578    }
1579    set webcmd Rappture::filexfer::webpage
1580    set group "app-$_appName"
1581    $m add command -label "About this tool" \
1582        -command [list $webcmd "$url/tools/$appName"] \
1583        -state $state
1584    $m add command -label "Questions?" \
1585        -command [list $webcmd "$url/resources/$_appName/questions"] \
1586        -state $state
1587    $m add command -label "Tickets" -state $state \
1588        -command [list $webcmd "$url/feedback/report_problems?group=$group"]
1589    $m add command -label "Wish List" -state disabled
1590    $m add separator
1591    $m add command -label "Save Simulations" \
1592        -command [itcl::code $this SelectSimsetNameAndSave] \
1593        -state $state
1594    $m add command -label "Load Simulations" \
1595        -command [itcl::code $this SelectSimsetForLoading] \
1596        -state $state
1597    $m add command -label "Delete Simulations" \
1598        -command [itcl::code $this SelectSimsetForDeletion] \
1599        -state $state
1600    $m add command -label "Publish Simulations" \
1601        -command [itcl::code $this SelectSimsetToPublish] \
1602        -state $state
1603    return $m
1604}
1605
1606itcl::body Rappture::Analyzer::BuildSimulationTable { top } {
1607    # All weirdness is due to the Resultset object.
1608
1609    # First create nodes for each simulation.  The node label is the
1610    # simulation number (such as #1, #2, etc). 
1611    eval $_tree delete 0
1612    set labels "selected simnum"
1613    foreach {name index} [$_resultset diff values simnum] {
1614        set node [$_tree insert 0 -label $name]
1615        $_tree set $node "simnum" $name
1616        set index2name($index) $name
1617       
1618    }
1619    # Next fill in the xmlobj associated with each simulation.  We assume
1620    # that the order is the the same as the simulation number.
1621    set index 0
1622    foreach {xmlobj dummy} [$_resultset diff values xmlobj]  {
1623        set node [$_tree findchild 0 $index2name($index)]
1624        set runfile [$xmlobj get output.filename]
1625        set version [$xmlobj get output.version]
1626        $_tree set $node \
1627            "selected" 1 "xmlobj" $xmlobj "runfile" $runfile "version" $version
1628        incr index
1629    }
1630    # Finally for each different input, for each simulation add the
1631    # label and value for the specific input.
1632    foreach name [$_resultset diff names] {
1633        # Ignore non-input names.
1634        if { $name == "xmlobj" || $name == "simnum" } {
1635            continue
1636        }
1637        foreach node [$_tree children 0] {
1638            set xmlobj [$_tree get $node xmlobj]
1639            set label [$xmlobj get $name.about.label]
1640            set value [$xmlobj get $name.current]
1641            if { [$_tree exists $node $label] } {
1642                puts stderr "This can't be: $label already exists in $node"
1643            }
1644            if { [lsearch $labels $label] < 0 } {
1645                lappend labels $label
1646            }
1647            $_tree set $node $label $value
1648        }
1649    }
1650    frame $top
1651    set tv $top.tv
1652    blt::treeview $top.tv -tree $_tree \
1653        -height 1i \
1654        -xscrollcommand [list $top.xs set] \
1655        -yscrollcommand [list $top.ys set] \
1656        -font "Arial 10"
1657    scrollbar $top.xs -orient horizontal -command "$tv xview"
1658    scrollbar $top.ys -orient vertical -command "$tv yview"
1659       
1660    eval $tv column insert end $labels
1661    $tv style checkbox checkbox -showvalue no
1662    $tv column configure simnum -title "Simulation"
1663    $tv column configure selected -title "Save" -style checkbox \
1664        -width .5i -edit yes
1665    $tv column configure treeView -hide yes
1666    blt::table $top \
1667        0,0 $top.tv -fill both \
1668        0,1 $top.ys -fill y \
1669        1,0 $top.xs -fill x
1670    blt::table configure $top r* c* -resize none
1671    blt::table configure $top r0 c0 -resize both
1672}
1673
1674itcl::body Rappture::Analyzer::CleanName { name } {
1675    regsub -all {/} $name {_} name
1676    return $name
1677}
1678
1679#
1680# Get the results and display them in a table.
1681#
1682# Use the table to omit specific results
1683# Use file chooser to save to specific
1684itcl::body Rappture::Analyzer::SelectSimsetNameAndSave {} {
1685    if { [EditSimset] } {
1686        set appDir [file normalize ~/data/saved/$_appName]
1687        file mkdir $appDir
1688        set fileName [file join $appDir [CleanName $_saved(Name).sav]]
1689        if { [file exists $fileName] } {
1690            if { ![OverwriteSaveFile] } {
1691                return
1692            }
1693        }
1694        WriteSimsetFile $_appName $fileName 0
1695    }
1696}
1697
1698#
1699# Get the results and display them in a table.
1700#
1701# Use the table to omit specific results
1702# Use file chooser to save to specific
1703itcl::body Rappture::Analyzer::SelectSimsetToPublish {} {
1704    if { [GetSimset "publish"] } {
1705        global env
1706        set shareDir [file join /data/tools/shared $_appName $env(USER)]
1707        if { [catch {
1708            file mkdir $shareDir
1709            file attributes $shareDir -permissions o+r,g+rw
1710        } errs] != 0 } {
1711            puts stderr errs=$errs
1712            return
1713        }
1714        set fileName [file join $shareDir [CleanName $_saved(Name).sav]]
1715        if { [file exists $fileName] } {
1716            if { ![OverwriteSaveFile] } {
1717                return
1718            }
1719        }
1720        WriteSimsetFile $_appName $fileName 1
1721    }
1722}
1723
1724#
1725# Checks editor widgets to see if the name and description have been
1726# set.  If this is so it enables the save button in the editor.
1727#
1728itcl::body Rappture::Analyzer::CheckSimsetDetails {} {
1729    set popup .savesimset
1730    if { ![winfo exists $popup] } {
1731        return
1732    }
1733    set inner [$popup component inner]
1734    set name [string trim [$inner.name get]]
1735    set desc [string trim [$inner.desc get 0.0 end]]
1736    $inner.controls.save configure -state disabled
1737    if { $name == "" || $desc == "" } {
1738        return
1739    }
1740    $inner.controls.save configure -state normal
1741}
1742
1743#
1744# Gathers all the information from the simset editor into the _saved array
1745#
1746itcl::body Rappture::Analyzer::SaveSimulations {} {
1747    set popup .savesimset
1748    if { ![winfo exists $popup] } {
1749        return
1750    }
1751    set inner [$popup component inner]
1752    array unset _saved
1753    set name [string trim [$inner.name get]]
1754    set desc [string trim [$inner.desc get 0.0 end]]
1755    set _saved(Application) $_appName
1756    set _saved(Revision) $_revision
1757    set _saved(Date) [clock format [clock seconds]]
1758    set _saved(Name) $name
1759    set _saved(Description) $desc
1760    set files {}
1761    foreach node [$_tree children root] {
1762        set fileName [$_tree get $node runfile]
1763        lappend files $fileName
1764    }
1765    set _saved(Files) $files
1766    set _done 1
1767}
1768
1769itcl::body Rappture::Analyzer::Cancel {} {
1770    set _done 0
1771}
1772
1773itcl::body Rappture::Analyzer::Ok {} {
1774    set popup .selectsimset
1775    if { ![winfo exists $popup] } {
1776        return
1777    }
1778    set inner [$popup component inner]
1779    set tv $inner.tv
1780    if { ![$tv selection present] } {
1781        return
1782    }
1783    set node [$tv curselection]
1784    array unset _saved
1785    array set _saved [$_tree get $node]
1786    set root [file root $_saved(FileName)]
1787    set files {}
1788    foreach file $_saved(Files) {
1789        if { [file pathtype $file] == "relative" } {
1790            set file [file join $root $file]
1791        }
1792        lappend files $file
1793    }
1794    set _saved(Files) $files
1795    set _done 1
1796}
1797
1798#
1799# WriteSimsetFile --
1800#
1801#       Write the .sav file and the runfiles in the ~/data/saved/$_appName
1802#       directory.  The subdirectory where the runfiles are written is
1803#       the root of the .save file name.
1804#
1805itcl::body Rappture::Analyzer::WriteSimsetFile { appName fileName publish } {
1806    # The runfiles directory is the root of the filename.  For example, if
1807    # the simset file is /path/to/myName.sav, the runfile directory is
1808    # /path/to/myName
1809    set root [file root $fileName]
1810    if { [file exists $root] } {
1811        file delete -force $root
1812    }
1813    if { [catch {
1814        file mkdir $root
1815        set f [open $fileName "w"]
1816        puts $f [list "Name"        $_saved(Name)]
1817        puts $f [list "Description" $_saved(Description)]
1818        puts $f [list "Date"        $_saved(Date)]
1819        global env
1820        puts $f [list "Creator"     $env(USER)]
1821        puts $f [list "Application" $_saved(Application)]
1822        puts $f [list "Revision"    $_saved(Revision)]
1823        set runfiles ""
1824        foreach file $_saved(Files) {
1825            set tail [file tail $file]
1826            set dest [file join $root $tail]
1827            file copy -force $file $dest
1828            if { $publish } {
1829                file attributes $dest -permissions o+r,g+rw
1830            }
1831            lappend runfiles $tail
1832        }
1833        puts $f [list "Files" $runfiles]
1834        close $f
1835        if { $publish } {
1836            file attributes $fileName -permissions o+r,g+rw
1837        }
1838    } errs] != 0 } {
1839        global errorInfo
1840        puts stderr "errs=$errs errorInfo=$errorInfo"
1841    }
1842}
1843
1844itcl::body Rappture::Analyzer::EditSimset {} {
1845    set popup .savesimset
1846    if { [winfo exists $popup] } {
1847        destroy $popup
1848    }
1849    # Create a popup for the print dialog
1850    Rappture::Balloon $popup -title "Save set of simulations..."
1851    set inner [$popup component inner]
1852   
1853    label $inner.name_l -text "Simulation Set Name"
1854    entry $inner.name -background white
1855    label $inner.desc_l -text "Simulation Set Description" -height 5
1856    text $inner.desc  -background white
1857    label $inner.select_l -text "Selected Simulations"
1858    BuildSimulationTable $inner.select
1859    frame $inner.controls
1860    bind $inner.desc <KeyPress> [itcl::code $this CheckSimsetDetails]
1861    bind $inner.name <KeyPress> [itcl::code $this CheckSimsetDetails]
1862    bind $inner.desc <Motion> [itcl::code $this CheckSimsetDetails]
1863    bind $inner.name <Motion> [itcl::code $this CheckSimsetDetails]
1864    button $inner.controls.cancel -text "Cancel" \
1865        -command [itcl::code $this Cancel]
1866    button $inner.controls.save -text "Save" \
1867        -command [itcl::code $this SaveSimulations]
1868    blt::table $inner.controls \
1869        0,0 $inner.controls.cancel \
1870        0,1 $inner.controls.save
1871   
1872    blt::table $inner \
1873        0,0 $inner.name_l -anchor ne \
1874        0,1 $inner.name -fill x \
1875        1,0 $inner.desc_l -anchor ne \
1876        1,1 $inner.desc -fill both \
1877        2,0 $inner.select_l -anchor ne \
1878        2,1 $inner.select -fill both \
1879        3,1 $inner.controls  -fill x
1880    blt::table configure $inner r1 -height 1i
1881    blt::table configure $inner r2 -pad 20
1882    $popup configure \
1883        -deactivatecommand [itcl::code $this Cancel]
1884
1885    set inner [$popup component inner]
1886    if {[$_resultset size] > 1} {
1887        blt::table $inner \
1888            2,0 $inner.select_l -anchor ne \
1889            2,1 $inner.select -fill both
1890    } else {
1891        blt::table forget $inner.select $inner.select_l
1892    }
1893    CheckSimsetDetails
1894    update
1895    # Activate the popup and call for the output.
1896    $popup activate $itk_component(help) below
1897    Cancel
1898    tkwait variable [itcl::scope _done]
1899    set doSave $_done
1900    $popup deactivate
1901    return $doSave
1902}
1903
1904
1905itcl::body Rappture::Analyzer::ReadSimsetFile { fileName } {
1906    if { [catch {
1907        set f [open $fileName "r"]
1908        set contents [read $f]
1909        close $f
1910        array set _saved $contents
1911    } errs] != 0 } {
1912        return 0
1913    }
1914    if { ![info exists _saved(Files)] } {
1915        return 0
1916    }
1917    set root [file root $fileName]
1918    foreach file $_saved(Files) {
1919        if { [file pathtype $file] == "relative" } {
1920            set file [file join $root $file]
1921        }
1922        if { ![file readable $file] } {
1923            puts stderr "runfile $file isn't readable"
1924            return 0
1925        }
1926    }
1927    set _saved(FileName) $fileName
1928    return 1
1929}
1930
1931#
1932# Run files can be either explicitly named with their absolute or
1933# relative path.  If the path is relative it is assumed the parent
1934# directory is relative to the simset file.
1935#
1936#   /my/path/to/myfile.sav
1937#   /my/path/to/myfile/runfiles...
1938#
1939itcl::body Rappture::Analyzer::LoadSimulations { files } {
1940    set loadobjs {}
1941    set root [file root $_saved(FileName)]
1942    foreach runfile $files {
1943        if { [file pathtype $runfile] == "relative" } {
1944            set runfile [file join $root $runfile]
1945        }
1946        if { ![file exists $runfile] } {
1947            puts stderr "can't find run: \"$runfile\""
1948            continue
1949        }
1950        set status [catch {Rappture::library $runfile} result]
1951        lappend loadobjs $result
1952    }
1953    clear
1954    foreach runobj $loadobjs {
1955        load $runobj
1956    }
1957    configure -notebookpage analyze
1958    global win
1959    $win.pager current analyzer
1960   if 0 {
1961    # Load the inputs for the very last run
1962    global tool
1963    $tool load $runobj
1964}
1965}
1966
1967#
1968# Delete selected simulation set.
1969#
1970itcl::body Rappture::Analyzer::SelectSimsetForDeletion {} {
1971    if { [FindSimsetsForApp $_appName] == 0 } {
1972        return
1973    }
1974    if { [GetSimset "delete"] } {
1975        set root [file root $_saved(FileName)]
1976        file delete -force $root
1977        file delete -force $_saved(FileName)
1978    }
1979}
1980
1981#
1982# Find all .sav files for an application and load them into the tree.
1983#
1984itcl::body Rappture::Analyzer::FindSimsetsForApp { appName } {
1985    $_tree delete 0
1986    foreach fileName [glob -nocomplain ~/data/saved/$appName/*.sav] {
1987        if { [ReadSimsetFile $fileName] } {
1988            if { $_revision > 0 && $_revision != $_saved(Revision) } {
1989                continue;               # Revision doesn't match.
1990            }
1991            $_tree insert 0 -label $_saved(Name) -data [array get _saved]
1992        }
1993    }
1994    return [$_tree degree 0]
1995}
1996
1997#
1998# Create dialog to select a simset from the currently available simsets.
1999#
2000itcl::body Rappture::Analyzer::GetSimset { name } {
2001    set popup .selectsimset
2002    if { [winfo exists $popup] } {
2003        destroy $popup
2004    }
2005    # Create a popup for the print dialog
2006    set title [string tolower $name]
2007    Rappture::Balloon $popup -title "Select set of simulations to $title..."
2008    set inner [$popup component inner]
2009   
2010    set tv $inner.tv
2011    blt::treeview $inner.tv -tree $_tree \
2012        -height 1i \
2013        -width 5i \
2014        -xscrollcommand [list $inner.xs set] \
2015        -yscrollcommand [list $inner.ys set] \
2016        -font "Arial 10"
2017    scrollbar $inner.xs -orient horizontal -command "$tv xview"
2018    scrollbar $inner.ys -orient vertical -command "$tv yview"
2019    frame $inner.controls
2020       
2021    $tv column insert end "Name" "Description" "Date" "Creator"
2022    $tv column configure treeView -hide yes
2023    blt::table $inner \
2024        0,0 $inner.tv -fill both \
2025        0,1 $inner.ys -fill y \
2026        1,0 $inner.xs -fill x
2027    blt::table configure $inner r* c* -resize none
2028    blt::table configure $inner r0 c0 -resize both
2029
2030    button $inner.controls.cancel -text "Cancel" \
2031        -command [itcl::code $this Cancel]
2032    set title [string totitle $name]
2033    button $inner.controls.save -text $title \
2034        -command [itcl::code $this Ok]
2035    blt::table $inner.controls \
2036        0,0 $inner.controls.cancel \
2037        0,1 $inner.controls.save
2038   
2039    blt::table $inner \
2040        0,0 $inner.tv -fill both \
2041        0,1 $inner.ys -fill y \
2042        1,0 $inner.xs -fill x \
2043        3,0 $inner.controls  -fill x -cspan 2
2044    blt::table configure $inner r* c* -resize none
2045    blt::table configure $inner r0 c0 -resize both
2046    blt::table configure $inner r2 -height 0.1i
2047   
2048    $popup configure \
2049        -deactivatecommand [itcl::code $this Cancel]
2050
2051    $tv selection set [$_tree firstchild 0]
2052    set inner [$popup component inner]
2053    update
2054    # Activate the popup and call for the output.
2055    $popup activate $itk_component(help) below
2056    Cancel
2057    tkwait variable [itcl::scope _done]
2058    set result $_done
2059    $popup deactivate
2060    return $result
2061}
2062
2063itcl::body Rappture::Analyzer::SelectSimsetForLoading {} {
2064    if { [FindSimsetsForApp $_appName] == 0 } {
2065        return
2066    }
2067    if { [GetSimset "load"] } {
2068        LoadSimulations $_saved(Files)
2069    }
2070}
2071
2072itcl::body Rappture::Analyzer::reload { fileName } {
2073    if { [catch {
2074        ReadSimsetFile $fileName
2075        if { [llength $_saved(Files)] > 0 } {
2076            #StartSplashScreen
2077            LoadSimulations $_saved(Files)
2078            #HideSplashScreen
2079        }
2080    } errs] != 0 } {
2081        puts stderr "can't load \"$fileName\": errs=$errs"
2082    }
2083}
2084
2085itcl::body Rappture::Analyzer::BuildQuestionDialog { popup } {
2086    toplevel $popup -background grey92 -bd 2 -relief raised
2087    wm withdraw $popup
2088    wm overrideredirect $popup true
2089    set inner $popup
2090    # Create the print dialog widget and add it to the the balloon popup.
2091    label $popup.title -text " " \
2092        -padx 10 -pady 10 \
2093        -background grey92
2094    button $popup.yes -text "Yes" \
2095        -highlightthickness 0 \
2096        -bd 2  \
2097        -command [itcl::code $this Save]
2098    button $popup.no -text "No" \
2099        -highlightthickness 0 \
2100        -bd 2 \
2101        -command [itcl::code $this Cancel]
2102    blt::table $popup \
2103        0,0 $popup.title -cspan 2  -fill x -pady 4 \
2104        1,0 $popup.yes -width { 0 1i .6i } -pady 4 \
2105        1,1 $popup.no -width { 0 1i .6i }  -pady 4
2106    blt::table configure $popup  r2 -height 0.125i
2107}
2108
2109itcl::body Rappture::Analyzer::Save {} {
2110    set _done 1
2111}
2112
2113itcl::body Rappture::Analyzer::OverwriteSaveFile {} {
2114    set popup .question
2115    if { ![winfo exists $popup] } {
2116        BuildQuestionDialog $popup
2117    }
2118    set text "Simulation set \"$_saved(Name)\" already exists. Overwrite?"
2119    $popup.title configure -text $text
2120    $popup.yes configure -text "Save"
2121    $popup.no configure -text "Cancel"
2122    set main [winfo toplevel $itk_component(help)]
2123    set pw [winfo reqwidth $popup]
2124    set ph [winfo reqheight $popup]
2125    set sw [winfo reqwidth $main]
2126    set sh [winfo reqheight $main]
2127    set rootx [winfo rootx $main]
2128    set rooty [winfo rooty $main]
2129    set x [expr $rootx + (($sw - $pw) / 2)]
2130    set y [expr $rooty + (($sh - $ph) / 2)]
2131    wm geometry $popup +$x+$y
2132    wm deiconify $popup
2133    update
2134    grab $popup
2135    # Activate the popup and call for the output.
2136    Cancel
2137    tkwait variable [itcl::scope _done]
2138    set doSave $_done
2139    grab release $popup
2140    destroy $popup
2141    return $doSave
2142}
Note: See TracBrowser for help on using the repository browser.