~ubuntu-dev/ubuntu/lucid/editobj/lucid-201002101911

« back to all changes in this revision

Viewing changes to custom.py

  • Committer: Bazaar Package Importer
  • Author(s): Marc Dequènes (Duck)
  • Date: 2004-04-29 16:35:29 UTC
  • Revision ID: james.westby@ubuntu.com-20040429163529-nf7jugpi5b075se5
Tags: upstream-0.5.3b
Import upstream version 0.5.3b

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
# EditObj
 
2
# Copyright (C) 2001-2002 Jean-Baptiste LAMY -- jiba@tuxfamily
 
3
#
 
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.
 
8
#
 
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.
 
13
#
 
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
 
17
 
 
18
from editobj import MultiEdit, EVAL_ENV
 
19
 
 
20
# Internationalization -- Set here your translator func
 
21
# (e.g. the "_" func from the GetText module)
 
22
 
 
23
TRANSLATOR = lambda key: key
 
24
 
 
25
 
 
26
# Editors customization
 
27
 
 
28
_attr_editors = {"children" : {None : None}}
 
29
 
 
30
def register_attr(attr, editor, clazz = None):
 
31
  """register_attr(attr, editor, clazz = None)
 
32
 
 
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."""
 
37
  
 
38
  for_attr = _attr_editors.get(attr)
 
39
  if for_attr: for_attr[clazz] = editor
 
40
  else:        _attr_editors[attr] = { clazz : editor }
 
41
  
 
42
def _find_editor(obj, attr):
 
43
  if isinstance(obj, MultiEdit): clazz = obj._objs[0].__class__
 
44
  else:                          clazz = obj.__class__
 
45
  
 
46
  for_attr = _attr_editors.get(attr)
 
47
  if for_attr:
 
48
    if (len(for_attr) == 1) and for_attr.has_key(None): return for_attr[None]
 
49
    
 
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
 
53
      
 
54
    if for_attr.has_key(None): return for_attr[None]
 
55
 
 
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
 
64
 
 
65
 
 
66
# Children customization
 
67
 
 
68
_children_attrs = {None : [("children", "insert", "__delitem__")]}
 
69
 
 
70
def register_children_attr(attr, insert = "insert", del_ = "__delitem__", clazz = None):
 
71
  """register_children_attr(attr, insert = "insert", del_ = "__delitem__", clazz = None)
 
72
 
 
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
 
82
their mother.
 
83
By default, "children" is considered for any class, and instances of classes
 
84
that inherits from list or dict are their own children."""
 
85
  
 
86
  if clazz: _children_attrs[clazz] = (attr, insert, del_)
 
87
  else:     _children_attrs[None].append((attr, insert, del_))
 
88
  
 
89
def _find_children(obj):
 
90
  if isinstance(obj, MultiEdit): clazz = obj._objs[0].__class__
 
91
  else:                          clazz = obj.__class__
 
92
  
 
93
  if issubclass(clazz, list) or issubclass(clazz, dict): return obj
 
94
  
 
95
  for clazz in (getattr(clazz, "__mro__", None) or _mro(clazz)):
 
96
    children_attrs = _children_attrs.get(clazz, None)
 
97
    if children_attrs:
 
98
      if children_attrs[0]:
 
99
        children = getattr(obj, children_attrs[0])
 
100
        if callable(children): return children()
 
101
        return children
 
102
      else: return obj
 
103
    
 
104
  for (children_attr, insert, del_) in _children_attrs[None]:
 
105
    children = getattr(obj, children_attr, None)
 
106
    
 
107
    if not children is None:
 
108
      if callable(children): return children()
 
109
      return children
 
110
 
 
111
def _find_children_insert_remove(obj):
 
112
  if isinstance(obj, MultiEdit): clazz = obj._objs[0].__class__
 
113
  else:                          clazz = obj.__class__
 
114
  
 
115
  if   issubclass(clazz, list): return obj, obj.insert,      obj.__delitem__
 
116
  elif issubclass(clazz, dict): return obj, obj.__setitem__, obj.__delitem__
 
117
  
 
118
  for clazz in (getattr(clazz, "__mro__", None) or _mro(clazz)):
 
119
    children_attrs = _children_attrs.get(clazz)
 
120
    if children_attrs:
 
121
      children_attr, insert, del_ = children_attrs
 
122
      if children_attr:
 
123
        children = getattr(obj, children_attr)
 
124
        if callable(children): return children()
 
125
      else: children = obj
 
126
      break
 
127
  else: 
 
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()
 
132
        break
 
133
    else: return None, None, None
 
134
  
 
135
  return children, getattr(obj, insert, None) or getattr(children, insert), getattr(obj, del_, None) or getattr(children, del_)
 
136
 
 
137
 
 
138
# Methods customization
 
139
 
 
140
_methods = {}
 
141
 
 
142
def register_method(method, clazz, *args_editor):
 
143
  """register_method(method, clazz, *args_editor)
 
144
 
 
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
 
152
their mother."""
 
153
  
 
154
  methods = _methods.get(clazz)
 
155
  if methods: methods.append((method, args_editor))
 
156
  else:       _methods[clazz] = [(method, args_editor)]
 
157
 
 
158
def _find_methods(obj):
 
159
  methods = []
 
160
  
 
161
  if isinstance(obj, MultiEdit): clazz = obj._objs[0].__class__
 
162
  else:                          clazz = obj.__class__
 
163
  
 
164
  for clazz in (getattr(clazz, "__mro__", None) or _mro(clazz)): methods.extend(_methods.get(clazz, ()))
 
165
  return methods
 
166
 
 
167
 
 
168
# Available and default children class customization (for the "Add..." dialog box)
 
169
 
 
170
_available_children = {}
 
171
 
 
172
def register_available_children(children_codes, clazz):
 
173
  """register_available_children(children_codes, clazz)
 
174
 
 
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."""
 
182
  
 
183
  if isinstance(children_codes, list):
 
184
    try:    _available_children[clazz].extend(children_codes)
 
185
    except: _available_children[clazz] = children_codes
 
186
  else:
 
187
    _available_children[clazz] = children_codes
 
188
 
 
189
def _find_available_children(obj):
 
190
  available_children = []
 
191
  
 
192
  if isinstance(obj, MultiEdit): clazz = obj._objs[0].__class__
 
193
  else:                          clazz = obj.__class__
 
194
  
 
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
 
199
    
 
200
  return available_children
 
201
 
 
202
  
 
203
# Proposed values customization
 
204
 
 
205
_values = {}
 
206
 
 
207
def register_values(attr, code_expressions):
 
208
  """register_values(attr, code_expressions)
 
209
 
 
210
Registers CODE_EXPRESSIONS as a proposed value for ATTR."""
 
211
  
 
212
  code_expressions = map(unicodify, code_expressions)
 
213
  try:             _values[attr].extend(code_expressions)
 
214
  except KeyError: _values[attr] = list(code_expressions)
 
215
  
 
216
def _find_values(attr): return _values.get(attr) or []
 
217
 
 
218
 
 
219
# Editing events
 
220
 
 
221
_on_edit = {}
 
222
_on_children_visible = {}
 
223
 
 
224
def register_on_edit(func, clazz):
 
225
  """register_on_edit(func, clazz)
 
226
 
 
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."""
 
230
  
 
231
  _on_edit[clazz] = func
 
232
 
 
233
def _call_on_edit(obj, window):
 
234
  if isinstance(obj, MultiEdit): clazz = obj._objs[0].__class__
 
235
  else:                          clazz = obj.__class__
 
236
  
 
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)
 
240
 
 
241
 
 
242
def register_on_children_visible(func, clazz):
 
243
  """register_on_children_visible(func, clazz)
 
244
 
 
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."""
 
248
  
 
249
  _on_children_visible[clazz] = func
 
250
 
 
251
def _call_on_children_visible(obj, visible):
 
252
  if isinstance(obj, MultiEdit): clazz = obj._objs[0].__class__
 
253
  else:                          clazz = obj.__class__
 
254
  
 
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)
 
258
    
 
259
    
 
260
def encode(s):
 
261
  if type(s) is unicode: return s.encode("latin")
 
262
  return s
 
263
 
 
264
def unicodify(s):
 
265
  if type(s) is str:
 
266
    try:                 return unicode(s, "utf8")
 
267
    except UnicodeError: return unicode(s, "latin")
 
268
  return s
 
269
 
 
270
def _mro(clazz):
 
271
  mro = [clazz]
 
272
  for c in clazz.__bases__: mro.extend(_mro(c))
 
273
  return mro