1 # -*- mode: tcl; fill-column: 75; tab-width: 8; coding: iso-latin-1-unix -*-
3 # $Id: Object.tcl,v 1.3 2006-10-01 23:59:47 villate Exp $
5 # Original Id: object.tcl,v 1.7 1995/02/10 08:32:50 sls Exp sls
7 # This software is copyright (C) 1994 by the Lawrence Berkeley Laboratory.
9 # Redistribution and use in source and binary forms, with or without
10 # modification, are permitted provided that: (1) source code distributions
11 # retain the above copyright notice and this paragraph in its entirety, (2)
12 # distributions including binary code include the above copyright notice and
13 # this paragraph in its entirety in the documentation or other materials
14 # provided with the distribution, and (3) all advertising materials mentioning
15 # features or use of this software display the following acknowledgement:
16 # ``This product includes software developed by the University of California,
17 # Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
18 # the University nor the names of its contributors may be used to endorse
19 # or promote products derived from this software without specific prior
22 # THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
23 # WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
24 # MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
26 # Prepare for message catalogues
28 if {$args == ""} {return $str}
29 return [eval [list format $str] $args]
32 proc object_info
{name
} {
33 # need an object info function like itcl
36 set object_priv
(currentClass
) {}
37 set object_priv
(objectCounter
) 0
39 proc object_class
{name spec
} {
41 set object_priv
(currentClass
) $name
42 lappend object_priv
(objects
) $name
43 upvar #0 ${name}_priv class
47 proc doc arg
"upvar #0 ${name}_priv class; set class(__doc__) \"\$arg\""
50 proc $name:config
{self args
} "uplevel \[concat object_config \$self \$args]"
51 proc $name:configure args
"uplevel \[concat object_config \$args]"
52 proc $name:cget
{self
option} "uplevel \[list object_cget \$self \$option]"
53 proc $name {inst args
} "object_new $name \$inst; uplevel \[concat object_config \$inst \$args]"
57 # could do doc as a simple proc that finds if its in a method or a class
58 # use uplevel and/or look for self as first of info args
60 proc method
{name args body
} {
62 set className
$object_priv(currentClass
)
63 upvar #0 ${className}_priv class
64 lappend class
(methods
) $name
66 append methodArgs
" " $args
67 set procbody
"upvar #0 \$self slot"
68 append procbody
"\nproc doc arg \"upvar #0 \$self slot; set slot(${name}.__doc__) \\\$arg\""
69 append procbody
"\n$body"
70 proc $className:$name $methodArgs $procbody
73 # Pythonic method without the implicit self
74 proc def
{name args body
} {
76 set className
$object_priv(currentClass
)
77 upvar #0 ${className}_priv class
78 lappend class
(methods
) $name
80 set procbody
"set self \$[lindex $methodArgs 0]; upvar #0 \$self slot"
81 append procbody
"\nproc doc arg \"upvar #0 \$self slot; set slot(${name}.__doc__) \\\$arg\""
82 append procbody
"\n$body"
83 proc $className:$name $methodArgs $procbody
86 proc member
{name
{defaultValue
{}}} {
88 set className
$object_priv(currentClass
)
89 upvar #0 ${className}_priv class
90 if {![info exists class
(member_info
/$name)]} {
91 lappend class
(members
) [list $name $defaultValue]
93 set class
(member_info
/$name) {}
96 proc param
{name
{defaultValue
{}} {resourceClass
{}} {configCode
{}}} {
98 set className
$object_priv(currentClass
)
99 upvar #0 ${className}_priv class
100 if {$resourceClass == ""} {
102 [string toupper
[string index
$name 0]][string range
$name 1 end
]
104 if ![info exists class
(param_info
/$name)] {
105 lappend class
(params
) $name
107 set class
(param_info
/$name) [list $defaultValue $resourceClass]
108 if {$configCode != {}} {
109 proc $className:config
:$name self
$configCode
113 proc object_include
{args
} {
115 set className
$object_priv(currentClass
)
116 foreach super_class_name
$args {
117 if {[info procs
$super_class_name] == ""} {auto_load $super_class_name}
118 upvar #0 ${className}_priv class
119 upvar #0 ${super_class_name}_priv super_class
120 foreach p
$super_class(params
) {
121 lappend class
(params
) $p
122 set class
(param_info
/$p) $super_class(param_info
/$p)
124 set class
(members
) [concat $super_class(members
) $class(members
)]
125 foreach m
$super_class(methods
) {
127 set proc $super_class_name:$m
128 foreach arg
[info args
$proc] {
129 if {[info default $proc $arg def
]} {
130 lappend formals
[list $arg $def]
135 proc $className:$m $formals [info body
$proc]
140 proc object_new
{className
{name
{}}} {
143 set name O_
[incr object_priv
(objectCounter
)]
145 upvar #0 $name object
146 upvar #0 ${className}_priv class
147 set object
(__class__
) $className
148 set object
(__file__
) [info script
]
149 foreach var
$class(params
) {
150 set info $class(param_info
/$var)
151 set resourceClass
[lindex $info 1]
152 if {$resourceClass != "" && \
153 ![catch {set val
[option get
$name $var $resourceClass]}]} {
155 set val
[lindex $info 0]
158 set val
[lindex $info 0]
160 set object
($var) $val
162 foreach var
$class(members
) {
163 set object
([lindex $var 0]) [lindex $var 1]
165 proc $name {method args
} [format {
167 uplevel [concat $object(__class__
):$method %s
$args]
169 if {[info procs
${className
}:__init__
] != ""} {
171 } elseif
{[info procs
${className
}:create
] != ""} {
177 proc object_define_creator
{windowType name spec
} {
178 object_class
$name $spec
179 if {[info procs
$name:create
] == {} && [info procs
$name:__init__
] == {}} {
180 error "widget \"$name\" must define a create method"
182 if {[info procs
$name:reconfig
] == {}} {
183 error "widget \"$name\" must define a reconfig method"
185 proc $name {window args
} [format {
186 if {[winfo exists
$window]} {destroy $window}
187 # need to transfer option database from Toplevel/Frame if we use -class
189 rename $window object_window_of
$window
190 upvar #0 $window object
191 set object
(__window__
) $window
192 object_new
%s
$window
193 proc %s
:frame {self args
} \
194 "uplevel \[concat object_window_of$window \$args]"
195 uplevel [concat $window config
$args]
196 # __init__ is a required method
197 if {![catch {$window __init__
} err
]} {
198 # create is the oldname
199 } elseif
{[catch {$window create
} err
]} {
200 tk_messageBox -icon error -type ok
\
201 -message "Error creating widget \"$window\":\n$err"
202 error "Error creating $window:\n$err"
204 set object
(__created
) 1
205 bind $window <Destroy
> \
206 "if !\[string compare %%W $window\] { object_delete $window }"
207 # reconfig is a required method
211 [string toupper
[string index
$name 0]][string range
$name 1 end
] \
215 # Class creators and their synonyms
216 proc object_frame
{name spec
} {
217 # need to transfer option database from Frame to widget?
218 object_define_creator
frame $name $spec
221 eval object_frame
$args
224 proc object_toplevel
{name spec
} {
225 # need to transfer option database from Toplevel to widget?
226 object_define_creator
toplevel $name $spec
229 eval object_toplevel
$args
233 set arglist
{name args
}
237 # Do some fancy reformatting on the "source" call to handle platform
238 # differences with respect to pathnames. Use format just so that the
239 # command is a little easier to read (otherwise it'd be full of
240 # backslashed dollar signs, etc.
241 append index
[list set auto_index
([fullname
$name])] \
242 [format { [list source [file join $dir %s
]]} \
243 [file split $scriptFile]] "\n"
245 foreach elt
{widget dialog object_toplevel object_frame
} {
246 auto_mkindex_parser
::command $elt $arglist $body
249 auto_mkindex_parser
::command object_class
{name args
} {
252 # Do some fancy reformatting on the "source" call to handle platform
253 # differences with respect to pathnames. Use format just so that the
254 # command is a little easier to read (otherwise it'd be full of
255 # backslashed dollar signs, etc.
256 append index
[list set auto_index
([fullname
$name])] \
257 [format { [list source [file join $dir %s
]]} \
258 [file split $scriptFile]] "\n"
262 proc object_config
{self args
} {
263 upvar #0 $self object
264 set len
[llength $args]
266 upvar #0 $object(__class__)_priv class
268 if {![info exists class
(params
)]} {
271 foreach param
$class(params
) {
272 set info $class(param_info
/$param)
274 [list -$param $param [lindex $info 1] [lindex $info 0] \
277 if {[info exists object
(__window__
)]} {
278 set result
[concat $result [object_window_of
$object(__window__
) config
]]
283 upvar #0 $object(__class__)_priv class
284 if {[string index
$args 0] != "-"} {
285 error "param '$args' didn't start with dash"
287 set param
[string range
$args 1 end
]
288 if {![info exists class
(params
)]} {
289 error "Attempt to query an undeclared param: $param"
291 if {[set ndx
[lsearch -exact $class(params
) $param]] == -1} {
292 if {[info exists object
(__window__
)]} {
293 return [object_window_of
$object(__window__
) config
-$param]
295 error "no param '$args'"
297 set info $class(param_info
/$param)
298 return [list -$param $param [lindex $info 1] [lindex $info 0] \
301 # accumulate commands and eval them later so that no changes will take
302 # place if we find an error
304 while {$args != ""} {
305 set fieldId
[lindex $args 0]
306 if {[string index
$fieldId 0] != "-"} {
307 error "param '$fieldId' didn't start with dash"
309 set fieldId
[string range
$fieldId 1 end
]
310 if ![info exists object
($fieldId)] {
311 if {[info exists object
(__window__
)]} {
312 if {[catch [list object_window_of
$object(__window__
) config
-$fieldId]]} {
313 error "tried to set param '$fieldId' which did not exist."
316 [list object_window_of
$object(__window__
) config
-$fieldId [lindex $args 1]]
317 set args
[lrange $args 2 end
]
323 if {[llength $args] == 1} {
324 return $object($fieldId)
326 lappend cmds
[list set object
($fieldId) [lindex $args 1]]
327 if {[info procs
$object(__class__
):config
:$fieldId] != {}} {
328 lappend cmds
[list $self config
:$fieldId]
330 set args
[lrange $args 2 end
]
336 if {[info exists object
(__created
)] && [info procs
$object(__class__
):reconfig
] != {}} {
341 proc object_cget
{self var
} {
342 upvar #0 $self object
343 return [lindex [object_config
$self $var] 4]
346 proc object_delete self
{
347 upvar #0 $self object
348 if {[info exists object
(__class__
)] && [info commands
$object(__class__
):destroy] != ""} {
349 catch {$object(__class__
):destroy $self}
351 if {[info exists object
(__window__
)]} {
352 if {[string length
[info commands object_window_of
$self]]} {
353 catch {rename $self {}}
354 rename object_window_of
$self $self
361 proc object_slotname slot
{
363 return [set self
]($slot)