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

Last change on this file since 738 was 115, checked in by mmc, 19 years ago

Updated all copyright notices.

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