source: trunk/gui/scripts/tool.tcl @ 13

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

Many improvements, including a new energy level viewer
for Huckel-IV. Added support for a new <boolean> type.
Fixed the cloud/field stuff so that when a cloud is 1D,
it reverts to BLT vectors so it will plot correctly.
Fixed the install script to work better on Windows.

File size: 8.4 KB
Line 
1# ----------------------------------------------------------------------
2#  COMPONENT: tool - represents an entire tool
3#
4#  This object represents an entire tool defined by Rappture.
5#  Each tool resides in an installation directory with other tool
6#  resources (libraries, examples, etc.).  Each tool is defined by
7#  its inputs and outputs, which are tied to various widgets in the
8#  GUI.  Each tool tracks the inputs, knows when they're changed,
9#  and knows how to run itself to produce new results.
10# ======================================================================
11#  AUTHOR:  Michael McLennan, Purdue University
12#  Copyright (c) 2004-2005
13#  Purdue Research Foundation, West Lafayette, IN
14# ======================================================================
15package require BLT
16
17itcl::class Rappture::Tool {
18    public variable analyzer ""
19
20    constructor {xmlobj installdir args} { # defined below }
21
22    public method installdir {} { return $_installdir }
23    public method xml {args}
24
25    public method load {xmlobj}
26    public method run {args}
27    public method abort {}
28
29    public method widgetfor {path {widget ""}}
30    public method changed {path}
31    public method sync {}
32    public method tool {}
33
34    private variable _xmlobj ""      ;# XML overall <run> object
35    private variable _installdir ""  ;# installation directory for this tool
36    private variable _path2widget    ;# maps path => widget on this page
37
38    private common job               ;# array var used for blt::bgexec jobs
39}
40                                                                               
41# ----------------------------------------------------------------------
42# CONSTRUCTOR
43# ----------------------------------------------------------------------
44itcl::body Rappture::Tool::constructor {xmlobj installdir args} {
45    if {![Rappture::library isvalid $xmlobj]} {
46        error "bad value \"$xmlobj\": should be Rappture::Library"
47    }
48    set _xmlobj $xmlobj
49
50    if {![file exists $installdir]} {
51        error "directory \"$installdir\" doesn't exist"
52    }
53    set _installdir $installdir
54
55    eval configure $args
56}
57
58# ----------------------------------------------------------------------
59# USAGE: xml <subcommand> ?<arg> <arg> ...?
60# USAGE: xml object
61#
62# Used by clients to manipulate the underlying XML data for this
63# tool.  The <subcommand> can be any operation supported by a
64# Rappture::library object.  Clients can also request the XML object
65# directly by using the "object" subcommand.
66# ----------------------------------------------------------------------
67itcl::body Rappture::Tool::xml {args} {
68    if {"object" == $args} {
69        return $_xmlobj
70    }
71    return [eval $_xmlobj $args]
72}
73
74# ----------------------------------------------------------------------
75# USAGE: run ?<path1> <value1> <path2> <value2> ...?
76#
77# This method causes the tool to run.  All widgets are synchronized
78# to the current XML representation, and a "driver.xml" file is
79# created as the input for the run.  That file is fed to the tool
80# according to the <tool><command> string, and the job is executed.
81#
82# Returns a list of the form {status result}, where status is an
83# integer status code (0=success) and result is the output from the
84# simulator.  Successful output is something like {0 run1293921.xml},
85# where 0=success and run1293921.xml is the name of the file containing
86# results.
87# ----------------------------------------------------------------------
88itcl::body Rappture::Tool::run {args} {
89    global errorInfo
90
91    # sync all widgets to the XML tree
92    sync
93
94    # if there are any args, use them to override parameters
95    foreach {path val} $args {
96        $_xmlobj put $path.current $val
97    }
98
99    foreach item {control output error} { set job($item) "" }
100
101    # write out the driver.xml file for the tool
102    set file "driver[pid].xml"
103    set status [catch {
104        set fid [open $file w]
105        puts $fid "<?xml version=\"1.0\"?>"
106        puts $fid [$_xmlobj xml]
107        close $fid
108    } result]
109
110    # execute the tool using the path from the tool description
111    if {$status == 0} {
112        set cmd [$_xmlobj get tool.command]
113        regsub -all @tool $cmd $_installdir cmd
114        regsub -all @driver $cmd $file cmd
115
116        set status [catch {eval blt::bgexec \
117            ::Rappture::Tool::job(control) \
118            -output ::Rappture::Tool::job(output) \
119            -error ::Rappture::Tool::job(error) $cmd} result]
120    } else {
121        set job(error) "$result\n$errorInfo"
122    }
123    if {$status == 0} {
124        file delete -force -- $file
125    }
126
127    # see if the job was aborted
128    if {[regexp {^KILLED} $job(control)]} {
129        return [list 0 "ABORT"]
130    }
131
132    #
133    # If successful, return the output, which should include
134    # a reference to the run.xml file containing results.
135    #
136    if {$status == 0} {
137        set file [string trim $job(output)]
138        return [list $status $file]
139    } elseif {"" != $job(output) || "" != $job(error)} {
140        return [list $status [string trim "$job(output)\n$job(error)"]]
141    }
142    return [list $status $result]
143}
144
145# ----------------------------------------------------------------------
146# USAGE: abort
147#
148# Clients use this during a "run" to abort the current job.
149# Kills the job and forces the "run" method to return.
150# ----------------------------------------------------------------------
151itcl::body Rappture::Tool::abort {} {
152    set job(control) "abort"
153}
154
155# ----------------------------------------------------------------------
156# USAGE: widgetfor <path> ?<widget>?
157#
158# Used by embedded widgets such as a Controls panel to register the
159# various controls associated with this page.  That way, this Tool
160# knows what widgets to look at when syncing itself to the underlying
161# XML data.
162# ----------------------------------------------------------------------
163itcl::body Rappture::Tool::widgetfor {path {widget ""}} {
164    # if this is a query operation, then look for the path
165    if {"" == $widget} {
166        if {[info exists _path2widget($path)]} {
167            return $_path2widget($path)
168        }
169        return ""
170    }
171
172    # otherwise, associate the path with the given widget
173    if {[info exists _path2widget($path)]} {
174        error "$path already associated with widget $_path2widget($path)"
175    }
176    set _path2widget($path) $widget
177}
178
179# ----------------------------------------------------------------------
180# USAGE: load <xmlobj>
181#
182# Loads the contents of a Rappture <xmlobj> into the controls
183# associated with this tool.
184# ----------------------------------------------------------------------
185itcl::body Rappture::Tool::load {newobj} {
186    if {![Rappture::library isvalid $newobj]} {
187        error "\"$newobj\" is not a Rappture::library"
188    }
189
190    foreach path [array names _path2widget] {
191        if {"" != [$newobj element -as type $path.current]} {
192            set val [$newobj get $path.current]
193            if {[string length $val] > 0} {
194                $_path2widget($path) value $val
195            } else {
196                set obj [$newobj element -as object $path.current]
197                $_path2widget($path) value $obj
198            }
199        }
200    }
201}
202
203# ----------------------------------------------------------------------
204# USAGE: changed <path>
205#
206# Invoked automatically by the various widgets associated with this
207# tool whenever their value changes.  If this tool has a -analyzer,
208# then it is notified that input has changed, so it can reset itself
209# for a new analysis.
210# ----------------------------------------------------------------------
211itcl::body Rappture::Tool::changed {path} {
212    if {"" != $analyzer} {
213        $analyzer reset
214    }
215}
216
217# ----------------------------------------------------------------------
218# USAGE: sync
219#
220# Used by descendents such as a Controls panel to register the
221# various controls associated with this page.  That way, this Tool
222# knows what widgets to look at when syncing itself to the underlying
223# XML data.
224# ----------------------------------------------------------------------
225itcl::body Rappture::Tool::sync {} {
226    foreach path [array names _path2widget] {
227        $_xmlobj put $path.current [$_path2widget($path) value]
228    }
229}
230
231# ----------------------------------------------------------------------
232# USAGE: tool
233#
234# Clients use this to figure out which tool is associated with
235# this object.  Since this is a tool, it returns itself.
236# ----------------------------------------------------------------------
237itcl::body Rappture::Tool::tool {} {
238    return $this
239}
Note: See TracBrowser for help on using the repository browser.