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

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

Updated all copyright notices.

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