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

Last change on this file since 5044 was 5044, checked in by mmc, 9 years ago

Fixed the Panes widget to handle fractional sizes better. Instead of
adjusting the fractions internally after each change, it keeps the
requested fractions, but normalizes them before the layout. This keeps
the behavior of the widget consistent, and keeps sizes closer to what
was requested for each pane. Also, fixed the -orientation option so
that the widget can switch back and forth between orientations.

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