2
# Copyright (C) 2001-2002 Jean-Baptiste LAMY -- jiba@tuxfamily
4
# This program is free software; you can redistribute it and/or modify
5
# it under the terms of the GNU General Public License as published by
6
# the Free Software Foundation; either version 2 of the License, or
7
# (at your option) any later version.
9
# This program is distributed in the hope that it will be useful,
10
# but WITHOUT ANY WARRANTY; without even the implied warranty of
11
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
# GNU General Public License for more details.
14
# You should have received a copy of the GNU General Public License
15
# along with this program; if not, write to the Free Software
16
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18
from editobj import MultiEdit, EVAL_ENV
20
# Internationalization -- Set here your translator func
21
# (e.g. the "_" func from the GetText module)
23
TRANSLATOR = lambda key: key
26
# Editors customization
28
_attr_editors = {"children" : {None : None}}
30
def register_attr(attr, editor, clazz = None):
31
"""register_attr(attr, editor, clazz = None)
33
Registers EDITOR as the editor for atrribute ATTR of class CLAZZ, or for any class if
34
CLAZZ is None. EDITOR can be either a Tk widget subclass of editobj.editor.Editor, or
35
None to hide the attribute.
36
MRO is used in order to allow subclasses to use the editor registered for their mother."""
38
for_attr = _attr_editors.get(attr)
39
if for_attr: for_attr[clazz] = editor
40
else: _attr_editors[attr] = { clazz : editor }
42
def _find_editor(obj, attr):
43
if isinstance(obj, MultiEdit): clazz = obj._objs[0].__class__
44
else: clazz = obj.__class__
46
for_attr = _attr_editors.get(attr)
48
if (len(for_attr) == 1) and for_attr.has_key(None): return for_attr[None]
50
for clazz in (getattr(clazz, "__mro__", None) or _mro(clazz)):
51
editor = for_attr.get(clazz, 0)
52
if not editor is 0: return editor
54
if for_attr.has_key(None): return for_attr[None]
56
if attr[0] == "_": return None # Hidden
57
import editobj.editor as editor
58
if isinstance(obj, int ): return editor.IntEditor
59
if isinstance(obj, float): return editor.IntEditor
60
if isinstance(obj, str) or isinstance(obj, unicode):
61
if "\n" in obj: return editor.TextEditor
62
return editor.StringEditor
63
return editor.EntryEditor
66
# Children customization
68
_children_attrs = {None : [("children", "insert", "__delitem__")]}
70
def register_children_attr(attr, insert = "insert", del_ = "__delitem__", clazz = None):
71
"""register_children_attr(attr, insert = "insert", del_ = "__delitem__", clazz = None)
73
Registers ATTR as an attribute that can act as the "content" or the "children"
74
of an object of class CLAZZ (or any class if None). If ATTR is None, the object is used
75
as its own list of children (automatically done for list / dict subclasses).
76
INSERT and DEL_ are the names of the methods called for inserting and deleting items.
77
INSERT can accept 2 arguments (as list.insert) or only one (as list.append), if you
78
don't care the children's order. Default values for INSERT and DEL_ are OK for lists;
79
for dicts, use INSERT = "__setitem__". EditObj will display these items in the tree view.
80
Only one such attribute can be set for a given class (several are accepted for None).
81
MRO is used in order to allow subclasses to use the children attribute registered for
83
By default, "children" is considered for any class, and instances of classes
84
that inherits from list or dict are their own children."""
86
if clazz: _children_attrs[clazz] = (attr, insert, del_)
87
else: _children_attrs[None].append((attr, insert, del_))
89
def _find_children(obj):
90
if isinstance(obj, MultiEdit): clazz = obj._objs[0].__class__
91
else: clazz = obj.__class__
93
if issubclass(clazz, list) or issubclass(clazz, dict): return obj
95
for clazz in (getattr(clazz, "__mro__", None) or _mro(clazz)):
96
children_attrs = _children_attrs.get(clazz, None)
99
children = getattr(obj, children_attrs[0])
100
if callable(children): return children()
104
for (children_attr, insert, del_) in _children_attrs[None]:
105
children = getattr(obj, children_attr, None)
107
if not children is None:
108
if callable(children): return children()
111
def _find_children_insert_remove(obj):
112
if isinstance(obj, MultiEdit): clazz = obj._objs[0].__class__
113
else: clazz = obj.__class__
115
if issubclass(clazz, list): return obj, obj.insert, obj.__delitem__
116
elif issubclass(clazz, dict): return obj, obj.__setitem__, obj.__delitem__
118
for clazz in (getattr(clazz, "__mro__", None) or _mro(clazz)):
119
children_attrs = _children_attrs.get(clazz)
121
children_attr, insert, del_ = children_attrs
123
children = getattr(obj, children_attr)
124
if callable(children): return children()
128
for (children_attr, insert, del_) in _children_attrs[None]:
129
children = getattr(obj, children_attr, None)
130
if not children is None:
131
if callable(children): return children()
133
else: return None, None, None
135
return children, getattr(obj, insert, None) or getattr(children, insert), getattr(obj, del_, None) or getattr(children, del_)
138
# Methods customization
142
def register_method(method, clazz, *args_editor):
143
"""register_method(method, clazz, *args_editor)
145
Registers METHOD as a method that must be displayed in EditObj for instance of CLAZZ.
146
METHOD can be either a method name (a string), or a function (in this case, it is not
147
a method, strictly speaking).
148
*ARGS_EDITOR are the editors used for entering the argument, e.g. use
149
editobj.editor.FloatEditor for a float argument, or editobj.editor.EntryEditor for a
150
Python eval'ed line of code.
151
MRO is used in order to allow subclasses to use the methods registered for
154
methods = _methods.get(clazz)
155
if methods: methods.append((method, args_editor))
156
else: _methods[clazz] = [(method, args_editor)]
158
def _find_methods(obj):
161
if isinstance(obj, MultiEdit): clazz = obj._objs[0].__class__
162
else: clazz = obj.__class__
164
for clazz in (getattr(clazz, "__mro__", None) or _mro(clazz)): methods.extend(_methods.get(clazz, ()))
168
# Available and default children class customization (for the "Add..." dialog box)
170
_available_children = {}
172
def register_available_children(children_codes, clazz):
173
"""register_available_children(children_codes, clazz)
175
Register the CHILDREN_CODES that are proposed for addition in an instance of CLAZZ.
176
If CHILDREN_CODES is a list of strings (Python code), EditObj will display a dialog box.
177
If CHILDREN_CODES is a single string, no dialog box will be displayed, and this code
178
will automatically be used.
179
If CHILDREN_CODES is "", nothing is done when clicking on the "Add..." button.
180
The codes are just eval'ed to create the children; they can use the "parent" variable,
181
which is set to the list/dict we are adding into."""
183
if isinstance(children_codes, list):
184
try: _available_children[clazz].extend(children_codes)
185
except: _available_children[clazz] = children_codes
187
_available_children[clazz] = children_codes
189
def _find_available_children(obj):
190
available_children = []
192
if isinstance(obj, MultiEdit): clazz = obj._objs[0].__class__
193
else: clazz = obj.__class__
195
for clazz in (getattr(clazz, "__mro__", None) or _mro(clazz)):
196
a = _available_children.get(clazz)
197
if isinstance(a, list): available_children.extend(a)
198
elif isinstance(a, str): return a
200
return available_children
203
# Proposed values customization
207
def register_values(attr, code_expressions):
208
"""register_values(attr, code_expressions)
210
Registers CODE_EXPRESSIONS as a proposed value for ATTR."""
212
code_expressions = map(unicodify, code_expressions)
213
try: _values[attr].extend(code_expressions)
214
except KeyError: _values[attr] = list(code_expressions)
216
def _find_values(attr): return _values.get(attr) or []
222
_on_children_visible = {}
224
def register_on_edit(func, clazz):
225
"""register_on_edit(func, clazz)
227
Register FUNC as an "on_edit" event for CLAZZ.
228
When an instance of CLAZZ is edited, FUNC is called with the instance and the editor
229
Tkinter window as arguments."""
231
_on_edit[clazz] = func
233
def _call_on_edit(obj, window):
234
if isinstance(obj, MultiEdit): clazz = obj._objs[0].__class__
235
else: clazz = obj.__class__
237
for clazz in (getattr(clazz, "__mro__", None) or _mro(clazz)):
238
on_edit = _on_edit.get(clazz, None)
239
if on_edit: on_edit(obj, window)
242
def register_on_children_visible(func, clazz):
243
"""register_on_children_visible(func, clazz)
245
Register FUNC as an "on_children_visible" event for CLAZZ.
246
When the children of an instance of CLAZZ are shown or hidden, FUNC is called
247
with the instance and the new visibility status (0 or 1) as arguments."""
249
_on_children_visible[clazz] = func
251
def _call_on_children_visible(obj, visible):
252
if isinstance(obj, MultiEdit): clazz = obj._objs[0].__class__
253
else: clazz = obj.__class__
255
for clazz in (getattr(clazz, "__mro__", None) or _mro(clazz)):
256
on_children_visible = _on_children_visible.get(clazz, None)
257
if on_children_visible: on_children_visible(obj, visible)
261
if type(s) is unicode: return s.encode("latin")
266
try: return unicode(s, "utf8")
267
except UnicodeError: return unicode(s, "latin")
272
for c in clazz.__bases__: mro.extend(_mro(c))