source: trunk/gui/scripts/controlOwner.tcl @ 23

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

Fixed the output processing to recognize messages
tagged with the prefix =RAPPTURE-???=> as Rappture
directives. The following directives are now recognized:

=RAPPTURE-PROGRESS=>percent message
=RAPPTURE-ERROR=>message
=RAPPTURE-RUN=>runfile

Also, added the Rappture::exec command to make it easy
to exec a tool within a wrapper script and handle stdout
and stderr messages properly.

File size: 9.4 KB
Line 
1# ----------------------------------------------------------------------
2#  COMPONENT: owner - manages Rappture controls
3#
4#  This object represents an entity managing Rappture controls.
5#  It is typically a Tool, a DeviceEditor, or some other large entity
6#  that manages a Rappture XML tree.  All controlling widgets are
7#  registered with an owner, and the owner propagates notifications
8#  out to clients who have an interest in a particular control.
9# ======================================================================
10#  AUTHOR:  Michael McLennan, Purdue University
11#  Copyright (c) 2004-2005
12#  Purdue Research Foundation, West Lafayette, IN
13# ======================================================================
14package require Itcl
15
16itcl::class Rappture::ControlOwner {
17    constructor {owner} { # defined below }
18
19    public method xml {args}
20
21    public method load {newobj}
22    public method widgetfor {path args}
23    public method changed {path}
24    public method notify {option owner args}
25    public method sync {}
26    public method tool {}
27
28    protected variable _owner ""     ;# ControlOwner containing this one
29    protected variable _xmlobj ""    ;# Rappture XML description
30    private variable _path2widget    ;# maps path => widget on this page
31    private variable _owner2paths    ;# for notify: maps owner => interests
32    private variable _callbacks      ;# for notify: maps owner/path => callback
33}
34                                                                               
35# ----------------------------------------------------------------------
36# CONSTRUCTOR
37# ----------------------------------------------------------------------
38itcl::body Rappture::ControlOwner::constructor {owner} {
39    set _owner $owner
40}
41
42# ----------------------------------------------------------------------
43# USAGE: xml <subcommand> ?<arg> <arg> ...?
44# USAGE: xml object
45#
46# Used by clients to manipulate the underlying XML data for this
47# tool.  The <subcommand> can be any operation supported by a
48# Rappture::library object.  Clients can also request the XML object
49# directly by using the "object" subcommand.
50# ----------------------------------------------------------------------
51itcl::body Rappture::ControlOwner::xml {args} {
52    if {"object" == $args} {
53        return $_xmlobj
54    }
55    return [eval $_xmlobj $args]
56}
57
58# ----------------------------------------------------------------------
59# USAGE: widgetfor <path> ?<widget>?
60#
61# Used by embedded widgets such as a Controls panel to register the
62# various controls associated with this page.  That way, this
63# ControlOwner knows what widgets to look at when syncing itself
64# to the underlying XML data.
65# ----------------------------------------------------------------------
66itcl::body Rappture::ControlOwner::widgetfor {path args} {
67    # if this is a query operation, then look for the path
68    if {[llength $args] == 0} {
69        if {[info exists _path2widget($path)]} {
70            return $_path2widget($path)
71        }
72        return ""
73    }
74
75    # otherwise, associate the path with the given widget
76    set widget [lindex $args 0]
77    if {"" != $widget} {
78        if {[info exists _path2widget($path)]} {
79            error "$path already associated with widget $_path2widget($path)"
80        }
81        set _path2widget($path) $widget
82    } else {
83        unset _path2widget($path)
84    }
85}
86
87# ----------------------------------------------------------------------
88# USAGE: load <xmlobj>
89#
90# Loads the contents of a Rappture <xmlobj> into the controls
91# associated with this tool.
92# ----------------------------------------------------------------------
93itcl::body Rappture::ControlOwner::load {newobj} {
94    if {![Rappture::library isvalid $newobj]} {
95        error "\"$newobj\" is not a Rappture::library"
96    }
97
98    foreach path [array names _path2widget] {
99        # copy new value to the XML tree
100        [tool] xml copy $path.current from $newobj $path.current
101
102        # also copy to the widget associated with the tree
103        if {"" != [$newobj element -as type $path.current]} {
104            set val [$newobj get $path.current]
105            if {[string length $val] > 0
106                  || [llength [$newobj children $path.current]] == 0} {
107                $_path2widget($path) value $val
108            } else {
109                set obj [$newobj element -as object $path.current]
110                $_path2widget($path) value $obj
111            }
112        }
113    }
114}
115
116# ----------------------------------------------------------------------
117# USAGE: changed <path>
118#
119# Invoked automatically by the various widgets associated with this
120# tool whenever their value changes.  Sends notifications to any
121# client that has registered an interest via "notify add".
122# ----------------------------------------------------------------------
123itcl::body Rappture::ControlOwner::changed {path} {
124    if {"" != $_owner} {
125        $_owner changed $path
126    } else {
127        foreach owner [array names _owner2paths] {
128            foreach pattern $_owner2paths($owner) {
129                if {[string match $pattern $path]} {
130                    uplevel #0 $_callbacks($owner/$pattern)
131                    break
132                }
133            }
134        }
135    }
136}
137
138# ----------------------------------------------------------------------
139# USAGE: notify add <owner> <path> <callback>
140# USAGE: notify info ?<owner>? ?<path>?
141# USAGE: notify remove <owner> ?<path> ...?
142#
143# Clients use this to request notifications about changes to a
144# particular <path> for a control under this tool.  Whenever the
145# value associated with <path> changes, the client identified by
146# <owner> is sent a message by invoking its <callback> routine.
147#
148# Notifications can be silenced by calling the "notify remove"
149# function.
150# ----------------------------------------------------------------------
151itcl::body Rappture::ControlOwner::notify {option args} {
152    switch -- $option {
153        add {
154            if {[llength $args] != 3} {
155                error "wrong # args: should be \"notify add owner path callback\""
156            }
157            set owner [lindex $args 0]
158            set path [lindex $args 1]
159            set cb [lindex $args 2]
160
161            if {[info exists _owner2paths($owner)]} {
162                set plist $_owner2paths($owner)
163            } else {
164                set plist ""
165            }
166
167            set i [lsearch -exact $plist $path]
168            if {$i < 0} { lappend _owner2paths($owner) $path }
169            set _callbacks($owner/$path) $cb
170        }
171        info {
172            if {[llength $args] == 0} {
173                # no args? then return all owners
174                return [array names _owner2paths]
175            } else {
176                set owner [lindex $args 0]
177                if {[info exists _owner2paths($owner)]} {
178                    set plist $_owner2paths($owner)
179                } else {
180                    set plist ""
181                }
182                if {[llength $args] == 1} {
183                    # 1 arg? then return paths for this owner
184                    return $plist
185                } elseif {[llength $args] == 2} {
186                    # 2 args? then return callback for this path
187                    set path [lindex $args 1]
188                    if {[info exists _callbacks($owner/$path)]} {
189                        return $_callbacks($owner/$path)
190                    }
191                    return ""
192                } else {
193                    error "wrong # args: should be \"notify info ?owner? ?path?\""
194                }
195            }
196        }
197        remove {
198            if {[llength $args] < 1} {
199                error "wrong # args: should be \"notify remove owner ?path ...?\""
200            }
201            set owner [lindex $args 0]
202
203            if {[llength $args] == 1} {
204                # no args? then delete all paths for this owner
205                if {[info exists _owner2paths($owner)]} {
206                    set plist $_owner2paths($owner)
207                } else {
208                    set plist ""
209                }
210            } else {
211                set plist [lrange $args 1 end]
212            }
213
214            # forget about the callback for each path
215            foreach path $plist {
216                catch {unset _callbacks($owner/$path)}
217
218                if {[info exists _owner2paths($owner)]} {
219                    set i [lsearch -exact $_owner2paths($owner) $path]
220                    if {$i >= 0} {
221                        set _owner2paths($owner) \
222                            [lreplace $_owner2paths($owner) $i $i]
223                    }
224                }
225            }
226        }
227    }
228}
229
230# ----------------------------------------------------------------------
231# USAGE: sync
232#
233# Used by descendents such as a Controls panel to register the
234# various controls associated with this page.  That way, this
235# ControlOwner knows what widgets to look at when syncing itself
236# to the underlying XML data.
237# ----------------------------------------------------------------------
238itcl::body Rappture::ControlOwner::sync {} {
239    foreach path [array names _path2widget] {
240        $_xmlobj put $path.current [$_path2widget($path) value]
241    }
242}
243
244# ----------------------------------------------------------------------
245# USAGE: tool
246#
247# Clients use this to figure out which tool is associated with
248# this object.  If there is no parent ControlOwner, then this
249# must be the top-level tool.
250# ----------------------------------------------------------------------
251itcl::body Rappture::ControlOwner::tool {} {
252    if {"" != $_owner} {
253        return [$_owner tool]
254    }
255    return $this
256}
Note: See TracBrowser for help on using the repository browser.