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

Last change on this file since 3513 was 3513, checked in by gah, 11 years ago

Add string trim to select 'xml get' calls

File size: 53.1 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    constructor {tool args} { # defined below }
53    destructor { # defined below }
54
55    public method simulate {args}
56    public method reset {{when -eventually}}
57    public method load {xmlobj}
58    public method clear {{xmlobj "all"}}
59    public method download {option args}
60
61    protected method _plot {args}
62    protected method _reorder {comps}
63    protected method _autoLabel {xmlobj path title cntVar}
64    protected method _fixResult {}
65    protected method _fixResultSet {args}
66    protected method _fixSize {}
67    protected method _fixSimControl {}
68    protected method _fixNotebook {}
69    protected method _simState {state args}
70    protected method _simOutput {message}
71    protected method _resultTooltip {}
72    protected method _isPdbTrajectory {data}
73    protected method _isLammpsTrajectory {data}
74    protected method _pdbToSequence {xmlobj path id child data}
75    protected method _lammpsToSequence {xmlobj path id child data}
76    protected method _trajToSequence {xmlobj {path ""}}
77
78    private variable _tool ""          ;# belongs to this tool
79    private variable _appName ""       ;# Name of application
80    private variable _control "manual" ;# start mode
81    private variable _resultset ""     ;# ResultSet object with all results
82    private variable _pages 0          ;# number of pages for result sets
83    private variable _label2page       ;# maps output label => result set
84    private variable _label2desc       ;# maps output label => description
85    private variable _label2item       ;# maps output label => output.xxx item
86    private variable _lastlabel ""     ;# label of last example loaded
87    private variable _plotlist ""      ;# items currently being plotted
88
89    private common job                 ;# array var used for blt::bgexec jobs
90}
91
92itk::usual Analyzer {
93    keep -background -cursor foreground -font
94}
95
96# ----------------------------------------------------------------------
97# CONSTRUCTOR
98# ----------------------------------------------------------------------
99itcl::body Rappture::Analyzer::constructor {tool args} {
100    set _tool $tool
101
102    # use this to store all simulation results
103    set _resultset [Rappture::ResultSet ::#auto]
104    $_resultset notify add $this [itcl::code $this _fixResultSet]
105
106    # widget settings...
107    itk_option add hull.width hull.height
108    pack propagate $itk_component(hull) no
109
110    frame $itk_interior.simol -borderwidth 1 -relief flat
111    pack $itk_interior.simol -fill x
112
113    itk_component add simbg {
114        frame $itk_interior.simol.simbg -borderwidth 0
115    } {
116        usual
117        rename -background -simcontrolcolor simControlColor Color
118    }
119    pack $itk_component(simbg) -expand yes -fill both
120
121    set simtxt [$tool xml get tool.action.label]
122    if {"" == $simtxt} {
123        set simtxt "Simulate"
124    }
125    itk_component add simulate {
126        button $itk_component(simbg).simulate -text $simtxt \
127            -command [itcl::code $this simulate]
128    } {
129        usual
130        rename -highlightbackground -simcontrolcolor simControlColor Color
131    }
132    pack $itk_component(simulate) -side left -padx 4 -pady 4
133
134    # BE CAREFUL: Shift focus when we click on "Simulate".
135    #   This shifts focus away from input widgets and causes them to
136    #   finalize and log any pending changes.  A better way would be
137    #   to have the "sync" operation finalize/sync, but this works
138    #   for now.
139    bind $itk_component(simulate) <ButtonPress> {focus %W}
140
141    # if there's a hub url, then add "About" and "Questions" links
142    set _appName [$_tool xml get tool.id]
143    set url [Rappture::Tool::resources -huburl]
144    if {"" != $url && "" != $_appName} {
145        itk_component add hubcntls {
146            frame $itk_component(simbg).hubcntls
147        } {
148            usual
149            rename -background -simcontrolcolor simControlColor Color
150        }
151        pack $itk_component(hubcntls) -side right -padx 4
152
153        itk_component add icon {
154            label $itk_component(hubcntls).icon -image [Rappture::icon ask] \
155                -highlightthickness 0
156        } {
157            usual
158            ignore -highlightthickness
159            rename -background -simcontrolcolor simControlColor Color
160        }
161        pack $itk_component(icon) -side left
162
163        itk_component add about {
164            button $itk_component(hubcntls).about -text "About this tool" \
165                -command [list Rappture::filexfer::webpage \
166                              "$url/tools/$_appName"]
167        } {
168            usual
169            ignore -font
170            rename -background -simcontrolcolor simControlColor Color
171            rename -highlightbackground -simcontrolcolor simControlColor Color
172        }
173        pack $itk_component(about) -side top -anchor w
174
175        itk_component add questions {
176            button $itk_component(hubcntls).questions -text Questions? \
177                -command [list Rappture::filexfer::webpage \
178                              "$url/resources/$_appName/questions"]
179        } {
180            usual
181            ignore -font
182            rename -background -simcontrolcolor simControlColor Color
183            rename -highlightbackground -simcontrolcolor simControlColor Color
184        }
185        pack $itk_component(questions) -side top -anchor w
186    }
187
188    itk_component add simstatus {
189        text $itk_component(simbg).simstatus -borderwidth 0 \
190            -highlightthickness 0 -height 1 -width 1 -wrap none \
191            -state disabled
192    } {
193        usual
194        ignore -highlightthickness
195        rename -background -simcontrolcolor simControlColor Color
196        rename -font -textfont textFont Font
197    }
198    pack $itk_component(simstatus) -side left -expand yes -fill x
199
200    $itk_component(simstatus) tag configure popup \
201        -underline 1 -foreground blue
202
203    $itk_component(simstatus) tag bind popup \
204        <Enter> {%W configure -cursor center_ptr}
205    $itk_component(simstatus) tag bind popup \
206        <Leave> {%W configure -cursor ""}
207    $itk_component(simstatus) tag bind popup \
208        <ButtonPress> {after idle {Rappture::Tooltip::tooltip show %W}}
209
210
211    itk_component add notebook {
212        Rappture::Notebook $itk_interior.nb
213    }
214    pack $itk_interior.nb -expand yes -fill both
215
216    # ------------------------------------------------------------------
217    # ABOUT PAGE
218    # ------------------------------------------------------------------
219    set w [$itk_component(notebook) insert end about]
220
221    Rappture::Scroller $w.info -xscrollmode off -yscrollmode auto
222    pack $w.info -expand yes -fill both -padx 4 -pady 20
223    itk_component add toolinfo {
224        text $w.info.text -width 1 -height 1 -wrap word \
225            -borderwidth 0 -highlightthickness 0
226    } {
227        usual
228        ignore -borderwidth -relief
229        rename -font -textfont textFont Font
230    }
231    $w.info contents $w.info.text
232
233    # ------------------------------------------------------------------
234    # SIMULATION PAGE
235    # ------------------------------------------------------------------
236    set w [$itk_component(notebook) insert end simulate]
237    frame $w.cntls
238    pack $w.cntls -side bottom -fill x -pady 12
239    frame $w.cntls.sep -background black -height 1
240    pack $w.cntls.sep -side top -fill x
241
242    itk_component add abort {
243        button $w.cntls.abort -text "Abort" \
244            -command [itcl::code $_tool abort]
245    }
246    pack $itk_component(abort) -side left -expand yes -padx 4 -pady 4
247
248    Rappture::Scroller $w.info -xscrollmode auto -yscrollmode auto
249    pack $w.info -expand yes -fill both -padx 4 -pady 4
250    itk_component add runinfo {
251        text $w.info.text -width 1 -height 1 -wrap none \
252            -borderwidth 0 -highlightthickness 0 \
253            -state disabled
254    } {
255        usual
256        ignore -borderwidth -relief
257        rename -font -codefont codeFont Font
258    }
259    $w.info contents $w.info.text
260
261    itk_component add progress {
262        Rappture::Progress $w.progress
263    }
264
265    # ------------------------------------------------------------------
266    # ANALYZE PAGE
267    # ------------------------------------------------------------------
268    set w [$itk_component(notebook) insert end analyze]
269
270    frame $w.top
271    pack $w.top -side top -fill x -pady 8
272    label $w.top.l -text "Result:" -font $itk_option(-font)
273    pack $w.top.l -side left
274
275    itk_component add viewselector {
276        Rappture::Combobox $w.top.sel -width 10 -editable no
277    } {
278        usual
279        rename -font -textfont textFont Font
280    }
281    pack $itk_component(viewselector) -side left -expand yes -fill x
282    bind $itk_component(viewselector) <<Value>> [itcl::code $this _fixResult]
283    bind $itk_component(viewselector) <Enter> \
284        [itcl::code $this download coming]
285
286    Rappture::Tooltip::for $itk_component(viewselector) \
287        "@[itcl::code $this _resultTooltip]"
288
289    $itk_component(viewselector) choices insert end \
290        --- "---"
291
292    itk_component add download {
293        button $w.top.dl -image [Rappture::icon download] -anchor e \
294            -borderwidth 1 -relief flat -overrelief raised \
295            -command [itcl::code $this download start $w.top.dl]
296    }
297    pack $itk_component(download) -side right -padx {4 0}
298    bind $itk_component(download) <Enter> \
299        [itcl::code $this download coming]
300
301    $itk_component(viewselector) choices insert end \
302        @download [Rappture::filexfer::label download]
303
304    if {[Rappture::filexfer::enabled]} {
305        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.
306
307NOTE:  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."
308    } else {
309        Rappture::Tooltip::for $itk_component(download) "Saves the current result to a file on your desktop."
310    }
311
312    itk_component add results {
313        Rappture::Panes $w.pane -sashwidth 1 -sashrelief solid -sashpadding {4 0}
314    }
315    pack $itk_component(results) -expand yes -fill both
316    set f [$itk_component(results) pane 0]
317
318    itk_component add resultpages {
319        Rappture::Notebook $f.nb
320    }
321    pack $itk_component(resultpages) -expand yes -fill both
322
323    set f [$itk_component(results) insert end -fraction 0.1]
324    itk_component add resultselector {
325        Rappture::ResultSelector $f.rsel -resultset $_resultset \
326            -settingscommand [itcl::code $this _plot]
327    }
328    pack $itk_component(resultselector) -expand yes -fill both
329    bind $itk_component(resultselector) <<Layout>> [itcl::code $this _fixSize]
330    bind $itk_component(results) <Configure> [itcl::code $this _fixSize]
331
332    eval itk_initialize $args
333
334    $itk_component(runinfo) tag configure ERROR -foreground red
335    $itk_component(runinfo) tag configure text -font $itk_option(-textfont)
336
337    #
338    # Load up tool info on the first page.
339    #
340    $itk_component(toolinfo) tag configure title \
341        -font $itk_option(-boldtextfont)
342
343    set mesg [$tool xml get tool.title]
344    if {"" != $mesg} {
345        $itk_component(toolinfo) insert end $mesg title
346        $itk_component(toolinfo) insert end "\n\n"
347    }
348
349    set mesg [$tool xml get tool.about]
350    if {"" != $mesg} {
351        $itk_component(toolinfo) insert end $mesg
352    }
353    $itk_component(toolinfo) configure -state disabled
354    $itk_component(notebook) current about
355
356    # tool can run on "manual" (default) or "auto"
357    set cntl [string trim [$tool xml get tool.control]]
358    if {"" == $cntl} {
359        set cntl [string trim [$tool xml get tool.control.type]]
360    }
361    if {"" != $cntl} {
362        set _control $cntl
363    }
364
365    # reset everything to a clean state
366    reset
367}
368
369# ----------------------------------------------------------------------
370# DESTRUCTOR
371# ----------------------------------------------------------------------
372itcl::body Rappture::Analyzer::destructor {} {
373    after cancel [itcl::code $this simulate]
374    $_resultset notify remove $this
375    itcl::delete object $_resultset
376}
377
378# ----------------------------------------------------------------------
379# USAGE: simulate ?-ifneeded?
380# USAGE: simulate ?<path1> <value1> <path2> <value2> ...?
381#
382# Kicks off the simulator by executing the tool.command associated
383# with the tool.  If any arguments are specified, they are used to
384# set parameters for the simulation.  While the simulation is running,
385# it shows status.  When the simulation is finished, it switches
386# automatically to "analyze" mode and shows the results.
387# ----------------------------------------------------------------------
388itcl::body Rappture::Analyzer::simulate {args} {
389    if {$args == "-ifneeded"} {
390        # check to see if simulation is really needed
391        $_tool sync
392        if {[$_resultset contains [$_tool xml object]]
393              && ![string equal $_control "manual-resim"]} {
394            # not needed -- show results and return
395            $itk_component(notebook) current analyze
396            return
397        }
398        set args ""
399    }
400
401    # simulation is needed -- go to simulation page
402    $itk_component(notebook) current simulate
403
404    # no progress messages yet
405    pack forget $itk_component(progress)
406    lappend args -output [itcl::code $this _simOutput]
407
408    _simState off
409    $itk_component(runinfo) configure -state normal
410    $itk_component(runinfo) delete 1.0 end
411    $itk_component(runinfo) insert end "Running simulation...\n\n" text
412    $itk_component(runinfo) configure -state disabled
413
414    # if the hold window is set, then put up a busy cursor
415    if {$itk_option(-holdwindow) != ""} {
416        blt::busy hold $itk_option(-holdwindow)
417        raise $itk_component(hull)
418    }
419
420    # execute the job
421    foreach {status result} [eval $_tool run $args] break
422
423    # if job was aborted, then allow simulation again
424    if {$result == "ABORT"} {
425        _simState on "Aborted"
426    }
427
428    # load results from run.xml into analyzer
429    if {$status == 0 && $result != "ABORT"} {
430        set status [catch {load $result} result]
431    }
432
433    # back to normal
434    if {$itk_option(-holdwindow) != ""} {
435        blt::busy release $itk_option(-holdwindow)
436    }
437    $itk_component(abort) configure -state disabled
438
439    if {$status != 0} {
440        $itk_component(runinfo) configure -state normal
441        $itk_component(runinfo) delete 1.0 end
442        $itk_component(runinfo) insert end "Problem launching job:\n\n" text
443        _simOutput $result
444        $itk_component(runinfo) configure -state disabled
445        $itk_component(runinfo) see 1.0
446
447        # Try to create a support ticket for this error.
448        # It may be a real problem.
449        if {[Rappture::bugreport::shouldReport for jobs]} {
450            set ::errorInfo "\n\n== RAPPTURE INPUT ==\n[$_tool xml xml]"
451            Rappture::bugreport::register "Problem launching job:\n$result"
452            Rappture::bugreport::attachment [$_tool xml xml]
453            Rappture::bugreport::send
454        }
455    } else {
456        $itk_component(notebook) current analyze
457    }
458
459    # do this last -- after _simOutput above
460    pack forget $itk_component(progress)
461}
462
463# ----------------------------------------------------------------------
464# USAGE: reset ?-eventually|-now?
465#
466# Used to reset the analyzer whenever the input to a simulation has
467# changed.  Sets the mode back to "simulate", so the user has to
468# simulate again to see the output.  If the <start> option is set
469# to "auto", the simulation is invoked immediately.
470# ----------------------------------------------------------------------
471itcl::body Rappture::Analyzer::reset {{when -eventually}} {
472    if {$when == "-eventually"} {
473        after cancel [list catch [itcl::code $this reset -now]]
474        after idle [list catch [itcl::code $this reset -now]]
475        return
476    }
477
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        # if control mode is "auto", then simulate right away
483        if {[string match auto* $_control]} {
484            # auto control -- don't need button
485            pack forget $itk_interior.simol
486
487            after cancel [itcl::code $this simulate]
488            after idle [itcl::code $this simulate]
489        } else {
490            _simState on "new input parameters"
491        }
492    } else {
493        _simState off
494    }
495}
496
497# ----------------------------------------------------------------------
498# USAGE: load <xmlobj>
499#
500# Loads the data from the given <xmlobj> into the appropriate results
501# sets.  If necessary, new results sets are created to store the data.
502# ----------------------------------------------------------------------
503itcl::body Rappture::Analyzer::load {xmlobj} {
504    # only show the last result? then clear first
505    if {[string trim [$_tool xml get tool.analyzer]] == "last"} {
506        clear
507    }
508
509    $_resultset add $xmlobj
510
511    # NOTE: Adding will trigger a !change event on the ResultSet
512    # object, which will trigger calls to _fixResultSet to add
513    # the results to display.
514}
515
516# ----------------------------------------------------------------------
517# USAGE: clear ?<xmlobj>?
518#
519# Discards one or more results previously loaded into the analyzer.
520# If an <xmlobj> is specified, then that one result is cleared.
521# Otherwise, all results are cleared.
522# ----------------------------------------------------------------------
523itcl::body Rappture::Analyzer::clear {{xmlobj "all"}} {
524    if {$xmlobj eq "" || $xmlobj eq "all"} {
525        $_resultset clear
526    } else {
527        $_resultset clear $xmlobj
528    }
529
530    # NOTE: Clearing will trigger a !change event on the ResultSet
531    # object, which will trigger calls to _fixResultSet to clean up
532    # the results being displayed.
533}
534
535# ----------------------------------------------------------------------
536# USAGE: download coming
537# USAGE: download controls <downloadCommand>
538# USAGE: download start ?widget?
539# USAGE: download now ?widget?
540#
541# Spools the current result so the user can download it.
542# ----------------------------------------------------------------------
543itcl::body Rappture::Analyzer::download {option args} {
544    set title [$itk_component(viewselector) value]
545    set page [$itk_component(viewselector) translate $title]
546
547    switch -- $option {
548        coming {
549            #
550            # Warn result that a download is coming, in case
551            # it needs to take a screen snap.
552            #
553            if {![regexp {^(|@download|---)$} $page]} {
554                set f [$itk_component(resultpages) page $page]
555                $f.rviewer download coming
556            }
557        }
558        controls {
559            # no controls for this download yet
560            return ""
561        }
562        start {
563            set widget $itk_component(download)
564            if {[llength $args] > 0} {
565                set widget [lindex $args 0]
566                if {[catch {winfo class $widget}]} {
567                    set widget $itk_component(download)
568                }
569            }
570            #
571            # See if this download has any controls.  If so, then
572            # post them now and let the user continue the download
573            # after selecting a file format.
574            #
575            if {$page != ""} {
576                set ext ""
577                set f [$itk_component(resultpages) page $page]
578                set arg [itcl::code $this download now $widget]
579                set popup [$f.rviewer download controls $arg]
580                if {"" != $popup} {
581                    $popup activate $widget below
582                } else {
583                    download now $widget
584                }
585            } else {
586                # this shouldn't happen
587                set file error.html
588                set data "<h1>Not Found</h1>There is no result selected."
589            }
590        }
591        now {
592            set widget $itk_component(download)
593            if {[llength $args] > 0} {
594                set widget [lindex $args 0]
595                if {[catch {winfo class $widget}]} {
596                    set widget $itk_component(download)
597                }
598            }
599            #
600            # Perform the actual download.
601            #
602            if {$page != ""} {
603                set ext ""
604                set f [$itk_component(resultpages) page $page]
605                set item [$itk_component(viewselector) value]
606                set result [$f.rviewer download now $widget $_appName $item]
607                if { $result == "" } {
608                    return;                # User cancelled the download.
609                }
610                foreach {ext data} $result break
611                if {"" == $ext} {
612                    if {"" != $widget} {
613                        Rappture::Tooltip::cue $widget \
614                            "Can't download this result."
615                    }
616                    return
617                }
618                regsub -all {[\ -\/\:-\@\{-\~]} $title {} title
619                set file "$title$ext"
620            } else {
621                # this shouldn't happen
622                set file error.html
623                set data "<h1>Not Found</h1>There is no result selected."
624            }
625
626            Rappture::Logger::log download [$itk_component(viewselector) value]
627            set mesg [Rappture::filexfer::download $data $file]
628            if {[string length $mesg] > 0} {
629                Rappture::Tooltip::cue $widget $mesg
630            }
631        }
632        default {
633            error "bad option \"$option\": should be coming, controls, now, start"
634        }
635    }
636}
637
638# ----------------------------------------------------------------------
639# USAGE: _plot ?<index> <options> <index> <options>...?
640#
641# Used internally to update the plot shown in the current result
642# viewer whenever the resultselector settings have changed.  Causes the
643# desired results to show up on screen.
644# ----------------------------------------------------------------------
645itcl::body Rappture::Analyzer::_plot {args} {
646    set _plotlist $args
647
648    set page [$itk_component(viewselector) value]
649    set page [$itk_component(viewselector) translate $page]
650    if {"" != $page} {
651        set f [$itk_component(resultpages) page $page]
652        $f.rviewer plot clear
653        foreach {index opts} $_plotlist {
654            $f.rviewer plot add $index $opts
655        }
656    }
657}
658
659# ----------------------------------------------------------------------
660# USAGE: _reorder <compList>
661#
662# Used internally to change the order of a series of output components
663# found in the <output> section.  Moves the <log> elements to the end
664# and returns the updated list.
665# ----------------------------------------------------------------------
666itcl::body Rappture::Analyzer::_reorder {comps} {
667    set i 0
668    set max [llength $comps]
669    while {$i < $max} {
670        set c [lindex $comps $i]
671        if {[string match log* $c]} {
672            set comps [lreplace $comps $i $i]
673            lappend comps $c
674            incr max -1
675        } else {
676            incr i
677        }
678    }
679    return $comps
680}
681
682# ----------------------------------------------------------------------
683# USAGE: _autoLabel <xmlobj> <path> <title> <cntVar>
684#
685# Used internally to check for an about.label property at the <path>
686# in <xmlobj>.  If this object doesn't have a label, then one is
687# supplied using the given <title>.  The <cntVar> is an array of
688# counters in the calling scopes for titles that have been used
689# in the past.  This is used to create titles like "Plot #2" the
690# second time it is encountered.
691#
692# The <xmlobj> is updated so that the label is inserted directly in
693# the tree.
694# ----------------------------------------------------------------------
695itcl::body Rappture::Analyzer::_autoLabel {xmlobj path title cntVar} {
696    upvar $cntVar counters
697
698    set group [$xmlobj get $path.about.group]
699    set label [$xmlobj get $path.about.label]
700    if {"" == $label} {
701        # no label -- make one up using the title specified
702        if {![info exists counters($group-$title)]} {
703            set counters($group-$title) 1
704            set label $title
705        } else {
706            set label "$title (#[incr counters($group-$title)])"
707        }
708        $xmlobj put $path.about.label $label
709    } else {
710        # handle the case of two identical labels in <output>
711        if {![info exists counters($group-$label)]} {
712            set counters($group-$label) 1
713        } else {
714            set label "$label (#[incr counters($group-$label)])"
715            $xmlobj put $path.about.label $label
716        }
717    }
718    return $label
719}
720
721# ----------------------------------------------------------------------
722# USAGE: _fixResult
723#
724# Used internally to change the result page being displayed whenever
725# the user selects a page from the results combobox.
726# ----------------------------------------------------------------------
727itcl::body Rappture::Analyzer::_fixResult {} {
728    set name [$itk_component(viewselector) value]
729    set page ""
730    if {"" != $name} {
731        set page [$itk_component(viewselector) translate $name]
732    }
733    if {$page == "@download"} {
734        # put the combobox back to its last value
735        $itk_component(viewselector) component entry configure -state normal
736        $itk_component(viewselector) component entry delete 0 end
737        $itk_component(viewselector) component entry insert end $_lastlabel
738        $itk_component(viewselector) component entry configure -state disabled
739        # perform the actual download
740        download start $itk_component(download)
741    } elseif {$page == "---"} {
742        # put the combobox back to its last value
743        $itk_component(viewselector) component entry configure -state normal
744        $itk_component(viewselector) component entry delete 0 end
745        $itk_component(viewselector) component entry insert end $_lastlabel
746        $itk_component(viewselector) component entry configure -state disabled
747    } elseif {$page != ""} {
748        set _lastlabel $name
749        set win [winfo toplevel $itk_component(hull)]
750        blt::busy hold $win
751        $itk_component(resultpages) current $page
752
753        set f [$itk_component(resultpages) page $page]
754        $f.rviewer plot clear
755        eval $f.rviewer plot add $_plotlist
756        blt::busy release [winfo toplevel $itk_component(hull)]
757        Rappture::Logger::log output $_label2item($name)
758        Rappture::Tooltip::for $itk_component(viewselector) \
759            "@[itcl::code $this _resultTooltip]" -log $_label2item($name)
760    }
761}
762
763# ----------------------------------------------------------------------
764# USAGE: _fixResultSet ?<eventData>...?
765#
766# Used internally to react to changes within the ResultSet.  When a
767# result is added, a new result viewer is created for the object.
768# When all results are cleared, the viewers are deleted.
769# ----------------------------------------------------------------------
770itcl::body Rappture::Analyzer::_fixResultSet {args} {
771    array set eventData $args
772    switch -- $eventData(op) {
773        add {
774            set xmlobj $eventData(what)
775
776            # Detect molecule elements that contain trajectory data
777            # and convert to sequences.
778            _trajToSequence $xmlobj output
779
780            # Go through the analysis and find all result sets.
781            set haveresults 0
782            foreach item [_reorder [$xmlobj children output]] {
783                switch -glob -- $item {
784                    log* {
785                        _autoLabel $xmlobj output.$item "Output Log" counters
786                    }
787                    number* {
788                        _autoLabel $xmlobj output.$item "Number" counters
789                    }
790                    integer* {
791                        _autoLabel $xmlobj output.$item "Integer" counters
792                    }
793                    string* {
794                        _autoLabel $xmlobj output.$item "String" counters
795                    }
796                    histogram* - curve* - field* {
797                        _autoLabel $xmlobj output.$item "Plot" counters
798                    }
799                    drawing* {
800                        _autoLabel $xmlobj output.$item "Drawing" counters
801                    }
802                    structure* {
803                        _autoLabel $xmlobj output.$item "Structure" counters
804                    }
805                    table* {
806                        _autoLabel $xmlobj output.$item "Energy Levels" counters
807                    }
808                    sequence* {
809                        _autoLabel $xmlobj output.$item "Sequence" counters
810                    }
811                }
812                set label [$xmlobj get output.$item.about.group]
813                if {"" == $label} {
814                    set label [$xmlobj get output.$item.about.label]
815                }
816
817                set hidden [$xmlobj get output.$item.hide]
818                set hidden [expr {"" != $hidden && $hidden}]
819
820                if {"" != $label && !$hidden} {
821                    set haveresults 1
822                }
823            }
824
825            # if there are any valid results, add them to the resultset
826            if {$haveresults} {
827                set index [$_resultset get simnum $xmlobj]
828
829                # add each result to a result viewer
830                foreach item [_reorder [$xmlobj children output]] {
831                    set label [$xmlobj get output.$item.about.group]
832                    if {"" == $label} {
833                        set label [$xmlobj get output.$item.about.label]
834                    }
835                    set hidden [$xmlobj get output.$item.hide]
836                    if { $hidden == "" } {
837                        set hidden 0
838                    }
839                    if {"" != $label && !$hidden} {
840                        if {![info exists _label2page($label)]} {
841                            set name "page[incr _pages]"
842                            set page [$itk_component(resultpages) \
843                                insert end $name]
844                            set _label2page($label) $page
845                            set _label2item($label) output.$item
846                            set _label2desc($label) \
847                                [$xmlobj get output.$item.about.description]
848                            Rappture::ResultViewer $page.rviewer
849                            pack $page.rviewer -expand yes -fill both -pady 4
850
851                            set end [$itk_component(viewselector) \
852                                choices index -value ---]
853                            if {$end < 0} {
854                                set end "end"
855                            }
856                            $itk_component(viewselector) choices insert $end \
857                                $name $label
858                        }
859
860                        # add/replace the latest result into this viewer
861                        set page $_label2page($label)
862
863                        if {![info exists reset($page)]} {
864                            $page.rviewer clear $index
865                            set reset($page) 1
866                        }
867                        $page.rviewer add $index $xmlobj output.$item
868                    }
869                }
870            }
871
872            # show the first page by default
873            set max [$itk_component(viewselector) choices size]
874            for {set i 0} {$i < $max} {incr i} {
875                set first [$itk_component(viewselector) choices get -label $i]
876                if {$first != ""} {
877                    set page [$itk_component(viewselector) choices get -value $i]
878                    set char [string index $page 0]
879                    if {$char != "@" && $char != "-"} {
880                        $itk_component(resultpages) current $page
881                        $itk_component(viewselector) value $first
882                        set _lastlabel $first
883                        break
884                    }
885                }
886            }
887        }
888        clear {
889            if {$eventData(what) ne "all"} {
890                # delete this result from all viewers
891                array set params $eventData(what)
892                foreach label [array names _label2page] {
893                    set page $_label2page($label)
894                    $page.rviewer clear $params(simnum)
895                }
896            }
897
898            if {[$_resultset size] == 0} {
899                # reset the size of the controls area
900                set ht [winfo height $itk_component(results)]
901                set cntlht [$itk_component(resultselector) size -controlarea]
902                set frac [expr {double($cntlht)/$ht}]
903                $itk_component(results) fraction end $frac
904
905                foreach label [array names _label2page] {
906                    set page $_label2page($label)
907                    destroy $page.rviewer
908                }
909                $itk_component(resultpages) delete -all
910                set _pages 0
911
912                $itk_component(viewselector) value ""
913                $itk_component(viewselector) choices delete 0 end
914                catch {unset _label2page}
915                catch {unset _label2item}
916                catch {unset _label2desc}
917                set _plotlist ""
918
919                $itk_component(viewselector) choices insert end --- "---"
920                $itk_component(viewselector) choices insert end \
921                    @download [Rappture::filexfer::label download]
922                set _lastlabel ""
923            }
924
925            # fix Simulate button state
926            reset
927        }
928        default {
929            error "don't know how to handle op \"$eventData(op)\""
930        }
931    }
932}
933
934# ----------------------------------------------------------------------
935# USAGE: _fixSize
936#
937# Used internally to change the size of the result set area whenever
938# a new control appears.  Adjusts the size available for the result
939# set up to some maximum.
940# ----------------------------------------------------------------------
941itcl::body Rappture::Analyzer::_fixSize {} {
942    set ht [winfo height $itk_component(results)]
943    if {$ht <= 1} { set ht [winfo reqheight $itk_component(results)] }
944    set cntlht [$itk_component(resultselector) size -controlarea]
945    set frac [expr {double($cntlht)/$ht}]
946
947    if {$frac < 0.4} {
948        $itk_component(results) fraction end $frac
949    }
950    _fixSimControl
951}
952
953# ----------------------------------------------------------------------
954# USAGE: _simState <boolean> ?<message>? ?<settings>?
955#
956# Used internally to change the "Simulation" button on or off.
957# If the <boolean> is on, then any <message> and <settings> are
958# displayed as well.  If the <boolean> is off, then only display
959# the message. The <message> is a note to the user about
960# what will be simulated, and the <settings> are a list of
961# tool parameter settings of the form {path1 val1 path2 val2 ...}.
962# When these are in place, the next Simulate operation will use
963# these settings.  This helps fill in missing data values.
964# ----------------------------------------------------------------------
965itcl::body Rappture::Analyzer::_simState {state args} {
966    if {$state} {
967        $itk_interior.simol configure \
968            -background $itk_option(-simcontrolactiveoutline)
969        configure -simcontrolcolor $itk_option(-simcontrolactivebackground)
970
971        $itk_component(abort) configure -state disabled
972        $itk_component(simulate) configure -state normal \
973            -command [itcl::code $this simulate]
974
975        #
976        # If there's a special message, then put it up next to the button.
977        #
978        set mesg [lindex $args 0]
979        if {"" != $mesg} {
980            $itk_component(simstatus) configure -state normal
981            $itk_component(simstatus) delete 1.0 end
982            $itk_component(simstatus) insert end $mesg
983
984            #
985            # If there are any settings, then install them in the
986            # "Simulate" button.  Also, pop them up as a tooltip
987            # for the message.
988            #
989            set settings [lindex $args 1]
990            if {[llength $settings] > 0} {
991                $itk_component(simulate) configure \
992                    -command [eval itcl::code $this simulate $settings]
993
994                set details ""
995                foreach {path val} $settings {
996                    set str [$_tool xml get $path.about.label]
997                    if {"" == $str} {
998                        set str [$_tool xml element -as id $path]
999                    }
1000                    append details "$str = $val\n"
1001                }
1002                set details [string trim $details]
1003
1004                Rappture::Tooltip::for $itk_component(simstatus) $details
1005                $itk_component(simstatus) insert end " "
1006                $itk_component(simstatus) insert end "(details...)" popup
1007            }
1008            $itk_component(simstatus) configure -state disabled
1009        }
1010    } else {
1011        if {"" != $itk_option(-simcontrolbackground)} {
1012            set simcbg $itk_option(-simcontrolbackground)
1013        } else {
1014            set simcbg $itk_option(-background)
1015        }
1016        $itk_interior.simol configure \
1017            -background $itk_option(-simcontroloutline)
1018        configure -simcontrolcolor $simcbg
1019
1020        $itk_component(simulate) configure -state disabled
1021        $itk_component(abort) configure -state normal
1022
1023        $itk_component(simstatus) configure -state normal
1024        $itk_component(simstatus) delete 1.0 end
1025        set mesg [lindex $args 0]
1026        if {"" != $mesg} {
1027            $itk_component(simstatus) insert end $mesg
1028        }
1029        $itk_component(simstatus) configure -state disabled
1030    }
1031}
1032
1033# ----------------------------------------------------------------------
1034# USAGE: _simOutput <message>
1035#
1036# Invoked automatically whenever output comes in while running the
1037# tool.  Extracts any =RAPPTURE-???=> messages from the output and
1038# sends the output to the display.  For example, any
1039# =RAPPTURE-PROGRESS=> message pops up the progress meter and updates
1040# it to show the latest progress message.  This is useful for
1041# long-running tools, to let the user know how much longer the
1042# simulation will take.
1043# ----------------------------------------------------------------------
1044itcl::body Rappture::Analyzer::_simOutput {message} {
1045    #
1046    # Scan through and pick out any =RAPPTURE-PROGRESS=> messages first.
1047    #
1048    while {[regexp -indices \
1049               {=RAPPTURE-PROGRESS=> *([-+]?[0-9]+) +([^\n]*)(\n|$)} $message \
1050                match percent mesg]} {
1051
1052        foreach {i0 i1} $percent break
1053        set percent [string range $message $i0 $i1]
1054
1055        foreach {i0 i1} $mesg break
1056        set mesg [string range $message $i0 $i1]
1057
1058        pack $itk_component(progress) -fill x -padx 10 -pady 10
1059        $itk_component(progress) settings -percent $percent -message $mesg
1060
1061        foreach {i0 i1} $match break
1062        set message [string replace $message $i0 $i1]
1063    }
1064
1065    #
1066    # Break up the remaining lines according to =RAPPTURE-ERROR=> messages.
1067    # Show errors in a special color.
1068    #
1069    $itk_component(runinfo) configure -state normal
1070
1071    while {[regexp -indices \
1072               {=RAPPTURE-([a-zA-Z]+)=>([^\n]*)(\n|$)} $message \
1073                match type mesg]} {
1074
1075        foreach {i0 i1} $match break
1076        set first [string range $message 0 [expr {$i0-1}]]
1077        if {[string length $first] > 0} {
1078            $itk_component(runinfo) insert end $first
1079            $itk_component(runinfo) insert end \n
1080        }
1081
1082        foreach {t0 t1} $type break
1083        set type [string range $message $t0 $t1]
1084        foreach {m0 m1} $mesg break
1085        set mesg [string range $message $m0 $m1]
1086        if {[string length $mesg] > 0 && $type != "RUN"} {
1087            $itk_component(runinfo) insert end $mesg $type
1088            $itk_component(runinfo) insert end \n $type
1089        }
1090
1091        set message [string range $message [expr {$i1+1}] end]
1092    }
1093
1094    if {[string length $message] > 0} {
1095        $itk_component(runinfo) insert end $message
1096        if {[$itk_component(runinfo) get end-2char] != "\n"} {
1097            $itk_component(runinfo) insert end "\n"
1098        }
1099        $itk_component(runinfo) see end
1100    }
1101    $itk_component(runinfo) configure -state disabled
1102}
1103
1104# ----------------------------------------------------------------------
1105# USAGE: _resultTooltip
1106#
1107# Used internally to build the tooltip string displayed for the
1108# result selector.  If the current page has an associated description,
1109# then it is displayed beneath the result.
1110#
1111# Returns the string for the tooltip.
1112# ----------------------------------------------------------------------
1113itcl::body Rappture::Analyzer::_resultTooltip {} {
1114    set tip ""
1115    set name [$itk_component(viewselector) value]
1116    if {[info exists _label2desc($name)] &&
1117         [string length $_label2desc($name)] > 0} {
1118        append tip "$_label2desc($name)\n\n"
1119    }
1120    if {[array size _label2page] > 1} {
1121        append tip "Use this control to display other output results."
1122    }
1123    return $tip
1124}
1125
1126# ----------------------------------------------------------------------
1127# USAGE: _fixSimControl
1128#
1129# Used internally to add or remove the simulation control at the
1130# top of the analysis area.  This is controlled by the -simcontrol
1131# option.
1132# ----------------------------------------------------------------------
1133itcl::body Rappture::Analyzer::_fixSimControl {} {
1134    switch -- $itk_option(-simcontrol) {
1135        on {
1136            pack $itk_interior.simol -fill x -before $itk_interior.nb
1137        }
1138        off {
1139            pack forget $itk_interior.simol
1140        }
1141        auto {
1142            #
1143            # If we have two or more radiodials, then there is a
1144            # chance of encountering a combination of parameters
1145            # with no data, requiring simulation.
1146            #
1147            if {[$itk_component(resultselector) size -controls] >= 2} {
1148                pack $itk_interior.simol -fill x -before $itk_interior.nb
1149            } else {
1150                pack forget $itk_interior.simol
1151            }
1152        }
1153        default {
1154            error "bad value \"$itk_option(-simcontrol)\": should be on, off, auto"
1155        }
1156    }
1157}
1158
1159# ----------------------------------------------------------------------
1160# USAGE: _fixNotebook
1161#
1162# Used internally to switch the active notebook page
1163# ----------------------------------------------------------------------
1164itcl::body Rappture::Analyzer::_fixNotebook {} {
1165    switch -- $itk_option(-notebookpage) {
1166        about {
1167            $itk_component(notebook) current about
1168        }
1169        simulate {
1170            $itk_component(notebook) current simulate
1171        }
1172        analyze {
1173            $itk_component(notebook) current analyze
1174        }
1175        default {
1176            error "bad value \"$itk_option(-notebookpage)\": should be about, simulate, analyze"
1177        }
1178    }
1179}
1180
1181# ----------------------------------------------------------------------
1182# USAGE: _isPdbTrajectory <data>
1183#
1184# Used internally to determine whether pdb or lammps data represents a
1185# trajectory rather than a single frame
1186# ----------------------------------------------------------------------
1187itcl::body Rappture::Analyzer::_isPdbTrajectory {data} {
1188    if { [llength $data] == 0 } {
1189        return 0
1190    }
1191    set nModels 0
1192    foreach line $data {
1193        if { [string match "MODEL*" $line] }  {
1194            incr nModels
1195            if { $nModels > 1 } {
1196                # Stop if more than one model found.  No need to count them
1197                # all.
1198                return 1
1199            }
1200        }
1201    }
1202    return 0
1203}
1204
1205# ----------------------------------------------------------------------
1206# USAGE: _isLammpsTrajectory <data>
1207#
1208# Used internally to determine whether pdb or lammps data represents a
1209# trajectory rather than a single frame
1210# ----------------------------------------------------------------------
1211itcl::body Rappture::Analyzer::_isLammpsTrajectory { data } {
1212    if { [llength $data] == 0 } {
1213        return 0
1214    }
1215    set nModels 0
1216    foreach line $data {
1217        if { [regexp {^[\t ]*ITEM:[ \t]+TIMESTEP} $line] } {
1218            incr nModels
1219            if { $nModels > 1 } {
1220                # Stop if more than one model found.  No need to count them
1221                # all.
1222                return 1
1223            }
1224        }
1225    }
1226    return 0
1227}
1228
1229# ----------------------------------------------------------------------
1230# USAGE: _pdbToSequence <xmlobj> ?<path>?
1231#
1232# If the molecule element is a trajectory, delete the original
1233# and create a sequence of individual molecules.
1234# Used internally to detect any molecule output elements that contain
1235# trajectory data.  Trajectories will be converted into sequences of
1236# individual molecules.  All other elements will be unaffected. Scans
1237# the entire xml tree if a starting path is not specified.
1238# ----------------------------------------------------------------------
1239itcl::body Rappture::Analyzer::_pdbToSequence {xmlobj path id child data} {
1240
1241    set seqLabel [$xmlobj get ${child}.about.label]
1242    set descr    [$xmlobj get ${child}.about.description]
1243    set formula  [$xmlobj get ${child}.components.molecule.formula]
1244    $xmlobj remove $child
1245
1246    set sequence  $path.sequence($id)
1247    $xmlobj put ${sequence}.about.label $seqLabel
1248    $xmlobj put ${sequence}.about.description $descr
1249    $xmlobj put ${sequence}.index.label "Frame"
1250
1251    set frameNum 0
1252    set numLines [llength $data]
1253    for { set i 0 } { $i < $numLines } { incr i } {
1254        set line [lindex $data $i]
1255        set line [string trim $line]
1256        set contents {}
1257        if { [string match "MODEL*" $line] } {
1258            # Save the contents until we get an ENDMDL record.
1259            for {} { $i < $numLines } { incr i } {
1260                set line [lindex $data $i]
1261                set line [string trim $line]
1262                if { $line == "" } {
1263                    continue;           # Skip blank lines.
1264                }
1265                if { [string match "ENDMDL*" $line] } {
1266                    break;
1267                }
1268                append contents $line\n
1269            }
1270            set frame ${sequence}.element($frameNum)
1271            $xmlobj put ${frame}.index $frameNum
1272           
1273            set molecule ${frame}.structure.components.molecule
1274            $xmlobj put ${molecule}.pdb $contents
1275            $xmlobj put ${molecule}.formula $formula
1276            incr frameNum
1277        }
1278    }
1279}
1280
1281# ----------------------------------------------------------------------
1282# USAGE: _lammpsToSequence <xmlobj> ?<path>?
1283#
1284# If the molecule element is a trajectory, delete the original
1285# and create a sequence of individual molecules.
1286# Used internally to detect any molecule output elements that contain
1287# trajectory data.  Trajectories will be converted into sequences of
1288# individual molecules.  All other elements will be unaffected. Scans
1289# the entire xml tree if a starting path is not specified.
1290# ----------------------------------------------------------------------
1291itcl::body Rappture::Analyzer::_lammpsToSequence {xmlobj path id child data} {
1292
1293    set seqLabel [$xmlobj get ${child}.about.label]
1294    set descr    [$xmlobj get ${child}.about.description]
1295    set typemap  [$xmlobj get ${child}.components.molecule.lammpstypemap]
1296    $xmlobj remove $child
1297
1298    set sequence ${path}.sequence($id)
1299    $xmlobj put ${sequence}.about.label $seqLabel
1300    $xmlobj put ${sequence}.about.description $descr
1301    $xmlobj put ${sequence}.index.label "Frame"
1302
1303    set frameNum 0
1304    set frameContents ""
1305    set inModel 0
1306    foreach line $data {
1307        set line [string trim $line]
1308        if { $line == "" } {
1309            continue;                   # Skip blank lines
1310        }
1311        if {[regexp {^[\t ]*ITEM:[ \t]+ATOMS} $line] } {
1312            if { $inModel && $frameContents != "" } {
1313                set frame ${sequence}.element($frameNum)
1314                $xmlobj put ${frame}.index $frameNum
1315               
1316                set molecule ${frame}.structure.components.molecule
1317                $xmlobj put ${molecule}.lammps $frameContents
1318                $xmlobj put ${molecule}.lammpstypemap $typemap
1319               
1320                incr frameNum
1321                set frameContents ""
1322            }
1323            set inModel 1
1324        } elseif { [scan $line "%d %d %f %f %f" a b c d e] == 5 } {
1325            if { !$inModel } {
1326                puts stderr "found \"$line\" without previous \"ITEM: ATOMS\""
1327                set inModel 1
1328            }
1329            append frameContents $line\n
1330        }
1331    }
1332    if { $frameContents != "" } {
1333        set frame ${sequence}.element($frameNum)
1334        $xmlobj put ${frame}.index $frameNum
1335       
1336        set molecule ${frame}.structure.components.molecule
1337        $xmlobj put ${molecule}.lammps $frameContents
1338        $xmlobj put ${molecule}.lammpstypemap $typemap
1339    }
1340}
1341
1342# ----------------------------------------------------------------------
1343# USAGE: _trajToSequence <xmlobj> ?<path>?
1344#
1345#       Check for PDB and LAMMPS trajectories in molecule data and rewrite
1346#       the individual models as a sequence of molecules.  Used internally
1347#       to detect any molecule output elements that contain trajectory data.
1348#       Trajectories will be converted into sequences of individual molecules.
1349#       All other elements will be unaffected. Scans the entire xml tree if a
1350#       starting path is not specified. 
1351#
1352# ----------------------------------------------------------------------
1353itcl::body Rappture::Analyzer::_trajToSequence {xmlobj {path ""}} {
1354    # Remove leading dot from path, if present.
1355    if { [string index $path 0] == "." } {
1356        set path [string range $path 1 end]
1357    }
1358    # Otherwise check each child.
1359    foreach child [$xmlobj children $path] {
1360        set current ${path}.${child}
1361        if { [string match "structure*" $child] } {
1362            set isTraj [$xmlobj get ${current}.components.molecule.trajectory]
1363            if { $isTraj == "" || !$isTraj } {
1364                continue;               # Not a trajectory.
1365            }
1366            # Look for trajectory if molecule element found.  Check both pdb
1367            # data and lammps data.
1368            set type [$xmlobj element -as type $current]
1369            set id   [$xmlobj element -as id $current]
1370            set pdbdata    [$xmlobj get ${current}.components.molecule.pdb]
1371            set lammpsdata [$xmlobj get ${current}.components.molecule.lammps]
1372            if { $pdbdata != "" && $lammpsdata != "" } {
1373                puts stderr \
1374                    "found both <pdb> and <lammps> elements: picking pdb"
1375            }
1376            set pdbdata [split $pdbdata \n]
1377            set lammpsdata [split $lammpsdata \n]
1378            if { [_isPdbTrajectory $pdbdata] } {
1379                _pdbToSequence $xmlobj $path $id $current $pdbdata
1380            } elseif { [_isLammpsTrajectory $lammpsdata] } {
1381                _lammpsToSequence $xmlobj $path $id $current $lammpsdata
1382            }
1383            continue
1384        }
1385        if 0 {
1386        # Recurse over all child nodes.
1387        _trajToSequence $xmlobj $current
1388        }
1389    }
1390}
1391
1392# ----------------------------------------------------------------------
1393# CONFIGURATION OPTION: -simcontrol
1394#
1395# Controls whether or not the Simulate button is showing.  In some
1396# cases, it is not needed.
1397# ----------------------------------------------------------------------
1398itcl::configbody Rappture::Analyzer::simcontrol {
1399    _fixSimControl
1400}
1401
1402# ----------------------------------------------------------------------
1403# CONFIGURATION OPTION: -notebookpage
1404#
1405# Controls which page of the analyzer notebook is shown. It is
1406# particularly needed when using rerun, when you don't want to
1407# "simulate -ifneeded" because an actual simulation might be
1408# kicked off due to differences between tool.xml and run.xml
1409# ----------------------------------------------------------------------
1410itcl::configbody Rappture::Analyzer::notebookpage {
1411    _fixNotebook
1412}
Note: See TracBrowser for help on using the repository browser.