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

Last change on this file since 3177 was 3177, checked in by mmc, 12 years ago

Updated all of the copyright notices to reference the transfer to
the new HUBzero Foundation, LLC.

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-2012  HUBzero Foundation, LLC
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} {
310    $_tool xml copy $to from [$_owner xml object] $from
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.