source: trunk/gui/scripts/service.tcl @ 95

Last change on this file since 95 was 22, checked in by mmc, 19 years ago

Lots of changes to support Huckel-IV:

  • Support for embedded <tool> declarations
  • New <integer> entry
  • Support for numbers and structures as output elements
  • Atom numbers/symbols in MoleculeViewer?
File size: 11.5 KB
Line 
1# ----------------------------------------------------------------------
2#  COMPONENT: service - represents a tool embedded within another tool
3#
4#  The tool.xml description for a Rappture tool can contain one or
5#  more embedded <tool> references.  Each Rappture::Service object
6#  represents an embedded <tool> and manages its operation,
7#  contributing some service to the overall tool.
8# ======================================================================
9#  AUTHOR:  Michael McLennan, Purdue University
10#  Copyright (c) 2004-2005
11#  Purdue Research Foundation, West Lafayette, IN
12# ======================================================================
13package require BLT
14
15itcl::class Rappture::Service {
16    constructor {owner path args} { # defined below }
17    destructor { # defined below }
18
19    public method control {}
20    public method input {}
21    public method output {args}
22
23    public method run {}
24    public method abort {}
25    public method clear {}
26
27    protected method _link {from to}
28
29    private variable _owner ""    ;# thing managing this service
30    private variable _path ""     ;# path to the <tool> description in _owner
31    private variable _tool ""     ;# underlying tool for this service
32    private variable _control ""  ;# control: auto/manual
33    private variable _show        ;# <show> info for input/output methods
34    private variable _obj2path    ;# maps object in _show => service path
35    private variable _path2widget ;# maps path for object in _show => widget
36    private variable _path2path   ;# maps path for object in _show => link path
37    private variable _result ""   ;# result from last run
38}
39
40# ----------------------------------------------------------------------
41# CONSTRUCTOR
42# ----------------------------------------------------------------------
43itcl::body Rappture::Service::constructor {owner path args} {
44    if {[catch {$owner isa Rappture::ControlOwner} valid] != 0 || !$valid} {
45        error "bad object \"$owner\": should be Rappture::ControlOwner"
46    }
47    set _owner $owner
48    set _path $path
49
50    #
51    # Load up the tool description from the <interface> file.
52    #
53    set intf [$_owner xml get $path.interface]
54    if {"" == $intf} {
55        puts "can't find <interface> description for tool at $path"
56    } else {
57        set installdir [[$_owner tool] installdir]
58        regsub -all @tool $intf $installdir intf
59
60        set xmlobj [Rappture::library $intf]
61        set installdir [file dirname $intf]
62        set _tool [Rappture::Tool ::#auto $xmlobj $installdir]
63        set _control [$_tool xml get tool.control]
64
65        #
66        # Scan through the <tool> and establish all of the
67        # relationships:
68        #
69        #   <show> ... Add to list of "input" for this service.
70        #              Caller will add controls to the interface.
71        #
72        #   <link> ... Link this value to another input/output
73        #              that exists in the containing tool.
74        #
75        #   <set> .... Hard-code the value for this input/output.
76        #
77        foreach dir {input output} {
78            set _show($dir) ""
79            foreach cname [$_owner xml children $path.$dir] {
80                set ppath $path.$dir.$cname
81
82                set spath [$_owner xml get $ppath.path]
83                if {"" == $spath} {
84                    error "missing <path> at $ppath"
85                }
86
87                set type [$_owner xml element -as type $ppath]
88                switch -- $type {
89                  show {
90puts "show: $spath"
91                    set tpath [$_owner xml get $ppath.to]
92                    if {"" == $tpath && $dir == "input"} {
93                        error "missing <to> at $ppath"
94                    }
95                    set obj [$_tool xml element -as object $spath]
96puts " => $obj"
97                    lappend _show($dir) $obj
98                    set _obj2path($obj) $spath
99
100                    if {$dir == "input"} {
101puts "link: $tpath => $spath"
102                        $_owner notify add $this $tpath \
103                            [itcl::code $this _link $tpath $spath]
104                    }
105                  }
106                  link {
107                    set tpath [$_owner xml get $ppath.to]
108                    if {"" == $tpath} {
109                        error "missing <to> at $ppath"
110                    }
111                    if {"" == [$_owner xml element $tpath]} {
112                        error "bad <to> path \"$tpath\" at $ppath"
113                    }
114                    if {$dir == "input"} {
115puts "link: $tpath => $spath"
116                        $_owner notify add $this $tpath \
117                            [itcl::code $this _link $tpath $spath]
118                    } else {
119puts "path2path: $spath => $tpath"
120                        set _path2path($spath) $tpath
121                    }
122                  }
123                  set {
124                    if {"" == [$_owner xml element $ppath.value]} {
125                        error "missing <value> at $ppath"
126                    }
127puts "set: $spath from $ppath.value"
128                    $_tool xml copy $spath from \
129                        [$_owner xml object] $ppath.value
130                  }
131                }
132            }
133        }
134
135        if {$_control != "auto"} {
136            set _show(control) [$_tool xml element -as object tool.control]
137        } else {
138            set _show(control) ""
139        }
140    }
141
142    eval configure $args
143}
144
145# ----------------------------------------------------------------------
146# DESTRUCTOR
147# ----------------------------------------------------------------------
148itcl::body Rappture::Service::destructor {} {
149    foreach dir [array names _show] {
150        foreach obj $_show($dir) {
151            itcl::delete object $obj
152        }
153    }
154}
155
156# ----------------------------------------------------------------------
157# USAGE: control
158#
159# Used by the container that displays this service to determine what
160# the control for this service should look like.  Returns "" if
161# there is no control--the service is invoked automatically whenever
162# the inputs change.  Otherwise, it returns a list of the form
163# {key value key value ...} with attributes that configure the button
164# controlling this service.
165# ----------------------------------------------------------------------
166itcl::body Rappture::Service::control {} {
167    return $_show(control)
168}
169
170# ----------------------------------------------------------------------
171# USAGE: input
172#
173# Used by the container that displays this service to describe any
174# inputs for this service that should be added to the main service.
175# Returns a list of XML objects representing various input controls.
176# ----------------------------------------------------------------------
177itcl::body Rappture::Service::input {} {
178    return $_show(input)
179}
180
181# ----------------------------------------------------------------------
182# USAGE: output
183# USAGE: output for <object> <widget>
184#
185# Used by the container that displays this service to describe any
186# outputs for this service that should be added to the main service.
187#
188# With no args, it returns a list of XML objects representing various
189# outputs.  The caller uses this information to create various output
190# widgets.
191# ----------------------------------------------------------------------
192itcl::body Rappture::Service::output {args} {
193    if {[llength $args] == 0} {
194        return $_show(output)
195    }
196    set option [lindex $args 0]
197    switch -- $option {
198        for {
199            if {[llength $args] != 3} {
200                error "wrong # args: should be \"output for object widget\""
201            }
202            set obj [lindex $args 1]
203            set win [lindex $args 2]
204            if {[info exists _obj2path($obj)]} {
205                set path $_obj2path($obj)
206puts "OUTPUT $path => $win"
207                set _path2widget($path) $win
208            } else {
209                puts "error: don't recognize output object $obj"
210            }
211        }
212        default {
213            error "bad option \"$option\": should be for"
214        }
215    }
216}
217
218# ----------------------------------------------------------------------
219# USAGE: run
220#
221# This method causes the service to run.  All widgets are synchronized
222# to the current XML representation, and a "driver.xml" file is
223# created as the input for the run.  That file is fed to the tool
224# according to the <tool><command> string, and the job is executed.
225#
226# All outputs are pushed out to the tool containing this service
227# according to the <outputs> directive for the service.
228# ----------------------------------------------------------------------
229itcl::body Rappture::Service::run {} {
230puts "running..."
231    clear
232    foreach {status result} [$_tool run] break
233
234    if {$status == 0 && $result != "ABORT"} {
235        if {[regexp {=RAPPTURE-RUN=>([^\n]+)} $result match file]} {
236            set xmlobj [Rappture::library $file]
237            #
238            # Scan through all outputs and copy them to the final output
239            # for the tool.  If they have widgets associated with them,
240            # set the value for the widget.
241            #
242puts "showing output..."
243            foreach cname [$xmlobj children output] {
244                set path output.$cname
245puts " for $path"
246                $_owner xml copy $path from $xmlobj $path
247
248                if {[info exists _path2widget($path)]} {
249                    set obj [$xmlobj element -as object $path]
250puts " sending $obj to $_path2widget($path)"
251                    $_path2widget($path) value $obj
252                }
253                if {[info exists _path2path($path)]} {
254puts " sending $path to $_path2path($path)"
255                    $_owner xml copy $_path2path($path) from $xmlobj $path
256                    set w [$_owner widgetfor $_path2path($path)]
257                    if {$w != ""} {
258                        set obj [$_owner xml element -as object $_path2path($path)]
259                        $w value $obj
260                    }
261                }
262            }
263            set _result $xmlobj
264        } else {
265            set status 1
266            set result "Can't find result file in output:\n\n$result"
267        }
268    }
269}
270
271# ----------------------------------------------------------------------
272# USAGE: abort
273#
274# Clients use this during a "run" to abort the current job.
275# Kills the job and forces the "run" method to return.
276# ----------------------------------------------------------------------
277itcl::body Rappture::Service::abort {} {
278    $_tool abort
279}
280
281# ----------------------------------------------------------------------
282# USAGE: clear
283#
284# Clears any result hanging around from the last run.
285# ----------------------------------------------------------------------
286itcl::body Rappture::Service::clear {} {
287    if {"" != $_result} {
288        foreach cname [$_result children output] {
289            set path output.$cname
290
291            if {[info exists _path2widget($path)]} {
292                $_path2widget($path) value ""
293            }
294        }
295        itcl::delete object $_result
296        set _result ""
297    }
298}
299
300# ----------------------------------------------------------------------
301# USAGE: _link <fromPath> <toPath>
302#
303# Used internally to link the value at <fromPath> in the outer tool
304# to the value at <toPath> for this service.  If this service is
305# automatic and <toPath> is an input, this also invokes the service.
306# ----------------------------------------------------------------------
307itcl::body Rappture::Service::_link {from to} {
308puts "link update: $from => $to"
309    $_tool xml copy $to from [$_owner xml object] $from
310
311    if {$_control == "auto" && [regexp -nocase {^input\.} $to]} {
312        after cancel [itcl::code $this run]
313        after idle [itcl::code $this run]
314    }
315}
Note: See TracBrowser for help on using the repository browser.