]> git.saurik.com Git - wxWidgets.git/blob - wxPython/tools/XRCed/xxx.py
fixed wxString::resize() which was completely broken
[wxWidgets.git] / wxPython / tools / XRCed / xxx.py
1 # Name: xxx.py ('xxx' is easy to distinguish from 'wx' :) )
2 # Purpose: XML interface classes
3 # Author: Roman Rolinsky <rolinsky@mema.ucl.ac.be>
4 # Created: 22.08.2001
5 # RCS-ID: $Id$
6
7 from wxPython.wx import *
8 from wxPython.xrc import *
9 from xml.dom import minidom
10 import wxPython.lib.wxpTag
11
12 from params import *
13
14 # Classes to interface DOM objects
15 class xxxObject:
16 # Default behavior
17 hasChildren = false # has children elements?
18 hasStyle = true # almost everyone
19 hasName = true # has name attribute?
20 isSizer = hasChild = false
21 # Style parameters (all optional)
22 styles = ['fg', 'bg', 'font', 'enabled', 'focused', 'hidden', 'tooltip']
23 # Required paremeters: none by default
24 required = []
25 # Default parameters with default values
26 default = {}
27 # Parameter types
28 paramDict = {}
29 # Window styles and extended styles
30 winStyles = []
31 # Tree icon index
32 #image = -1
33 # Construct a new xxx object from DOM element
34 # parent is parent xxx object (or None if none), element is DOM element object
35 def __init__(self, parent, element):
36 self.parent = parent
37 self.element = element
38 self.undo = None
39 # Get attributes
40 self.className = element.getAttribute('class')
41 if self.hasName: self.name = element.getAttribute('name')
42 # Set parameters (text element children)
43 self.params = {}
44 nodes = element.childNodes[:]
45 for node in nodes:
46 if node.nodeType == minidom.Node.ELEMENT_NODE:
47 if node.tagName == 'object':
48 continue # do nothing for object children here
49 if not node.tagName in self.allParams and not node.tagName in self.styles:
50 print 'WARNING: unknown parameter for %s: %s' % \
51 (self.className, node.tagName)
52 continue
53 if node.tagName == 'content': # has items
54 # Param value is a list of text nodes
55 l = []
56 nodes = node.childNodes[:]
57 for n in nodes:
58 if n.nodeType == minidom.Node.ELEMENT_NODE:
59 assert n.tagName == 'item', 'bad content content'
60 if not n.hasChildNodes():
61 # If does not have child nodes, create empty text node
62 text = tree.dom.createTextNode('')
63 node.appendChild(text)
64 else:
65 # !!! normalize?
66 text = n.childNodes[0] # first child must be text node
67 assert text.nodeType == minidom.Node.TEXT_NODE
68 l.append(text)
69 else:
70 node.removeChild(n)
71 n.unlink()
72 self.params[node.tagName] = l
73 elif node.tagName == 'font': # has children
74 # we read and write all font parameters at once
75 self.params[node.tagName] = xxxFont(self, node)
76 else: # simple parameter
77 if not node.hasChildNodes():
78 # If does not have child nodes, create empty text node
79 text = tree.dom.createTextNode('')
80 node.appendChild(text)
81 else:
82 text = node.childNodes[0] # first child must be text node
83 assert text.nodeType == minidom.Node.TEXT_NODE
84 self.params[node.tagName] = text
85 else:
86 # Remove all other nodes
87 element.removeChild(node)
88 node.unlink()
89 # Generate HTML
90 def generateHtml(self, prefix=''):
91 SetCurrentXXX(self)
92 html = '<table cellspacing=0 cellpadding=0><tr><td width=120>\
93 <font size="+1"><b>%s</b></font></td>' % self.className
94 # Has id (name) attribute
95 if self.hasName:
96 html += """\
97 <td><wxp module="xxx" class="ParamText" width=150>
98 <param name="id" value="%d">
99 <param name="name" value="data_name">
100 <param name="value" value='("%s")'>
101 </wxp></td>""" % (-1, self.name)
102 html += '</table><p>'
103 html += '<table cellspacing=0 cellpadding=0>\n'
104 # Add required parameters
105 for param in self.allParams:
106 # Add checkbox or just text
107 if param in self.required:
108 html += '<tr><td width=20></td><td width=100>%s: </td>' % param
109 else: # optional parameter
110 html += """\
111 <tr><td width=20><wxp class="wxCheckBox">
112 <param name="id" value="%d">
113 <param name="size" value="(20,-1)">
114 <param name="name" value="%s">
115 <param name="label" value=("")>
116 </wxp></td><td width=100>%s: </td>
117 """ % (paramIDs[param], prefix + 'check_' + param, param)
118 # Add value part
119 if self.params.has_key(param):
120 if param == 'content':
121 l = []
122 for text in self.params[param]:
123 l.append(str(text.data)) # convert from unicode
124 value = str(l)
125 else:
126 value = "('" + self.params[param].data + "')"
127 else:
128 value = "('')"
129 # Get parameter type
130 try:
131 # Local or overriden type
132 typeClass = self.paramDict[param].__name__
133 except KeyError:
134 try:
135 # Standart type
136 typeClass = paramDict[param].__name__
137 except KeyError:
138 # Default
139 typeClass = 'ParamText'
140 html += """\
141 <td><wxp module="xxx" class="%s">
142 <param name="id" value="%d">
143 <param name="name" value="%s">
144 <param name="value" value="%s">
145 </wxp></td>
146 """ % (typeClass, -1, prefix + 'data_' + param, value)
147 html += '</table>\n'
148 return html
149 # Returns real tree object
150 def treeObject(self):
151 if self.hasChild: return self.child
152 return self
153 # Returns tree image index
154 def treeImage(self):
155 if self.hasChild: return self.child.treeImage()
156 return self.image
157 # Class name plus wx name
158 def treeName(self):
159 if self.hasChild: return self.child.treeName()
160 if self.hasName and self.name: return self.className + ' "' + self.name + '"'
161 return self.className
162
163 ################################################################################
164
165 class xxxFont(xxxObject):
166 allParams = ['size', 'style', 'weight', 'family', 'underlined',
167 'face', 'encoding']
168 def __init__(self, parent, element):
169 xxxObject.__init__(self, parent, element)
170 self.parentNode = element # required to behave similar to DOM node
171 self.data = self.value()
172 def updateXML(self, value):
173 # `value' is a list of strings corresponding to all parameters
174 elem = self.element
175 for node in elem.childNodes:
176 elem.removeChild(node)
177 i = 0
178 self.params.clear()
179 for param in self.allParams:
180 if value[i]:
181 fontElem = tree.dom.createElement(param)
182 textNode = tree.dom.createTextNode(value[i])
183 self.params[param] = textNode
184 fontElem.appendChild(textNode)
185 elem.appendChild(fontElem)
186 i += 1
187 # Update data
188 self.data = self.value()
189 def value(self):
190 v = []
191 for p in self.allParams:
192 try:
193 v.append(str(self.params[p].data))
194 except KeyError:
195 v.append('')
196 return v
197
198 ################################################################################
199
200 class xxxContainer(xxxObject):
201 hasChildren = true
202
203 ################################################################################
204 # Top-level windwos
205
206 class xxxPanel(xxxContainer):
207 allParams = ['pos', 'size', 'style']
208 styles = ['fg', 'bg', 'font', 'enabled', 'focused', 'hidden', 'exstyle',
209 'tooltip']
210 exStyles = ['wxWS_EX_VALIDATE_RECURSIVELY']
211
212 class xxxDialog(xxxContainer):
213 allParams = ['title', 'pos', 'size', 'style']
214 required = ['title']
215 winStyles = ['wxDIALOG_MODAL', 'wxCAPTION', 'wxDEFAULT_DIALOG_STYLE',
216 'wxRESIZE_BORDER', 'wxSYSTEM_MENU', 'wxTHICK_FRAME', 'wxSTAY_ON_TOP']
217 styles = ['fg', 'bg', 'font', 'enabled', 'focused', 'hidden', 'exstyle',
218 'tooltip']
219 exStyles = ['wxWS_EX_VALIDATE_RECURSIVELY']
220
221 class xxxFrame(xxxContainer):
222 allParams = ['title', 'centered', 'pos', 'size', 'style']
223 paramDict = {'centered': ParamBool}
224 required = ['title']
225 winStyles = ['wxDEFAULT_FRAME_STYLE', 'wxICONIZE', 'wxCAPTION', 'wxMINIMIZE',
226 'wxICONIZE', 'wxMINIMIZE_BOX', 'wxMAXIMIZE', 'wxMAXIMIZE_BOX',
227 'wxSTAY_ON_TOP', 'wxSYSTEM_MENU', 'wxRESIZE_BORDER',
228 'wxFRAME_FLOAT_ON_PARENT', 'wxFRAME_TOOL_WINDOW']
229 styles = ['fg', 'bg', 'font', 'enabled', 'focused', 'hidden', 'exstyle',
230 'tooltip']
231 exStyles = ['wxWS_EX_VALIDATE_RECURSIVELY']
232
233 ################################################################################
234 # Controls
235
236 class xxxStaticText(xxxObject):
237 allParams = ['label', 'pos', 'size', 'style']
238 required = ['label']
239 winStyles = ['wxALIGN_LEFT', 'wxALIGN_RIGHT', 'wxALIGN_CENTRE', 'wxST_NO_AUTORESIZE']
240
241 class xxxStaticLine(xxxObject):
242 allParams = ['pos', 'size', 'style']
243 winStyles = ['wxLI_HORIZONTAL', 'wxLI_VERTICAL']
244
245 class xxxTextCtrl(xxxObject):
246 allParams = ['value', 'pos', 'size', 'style']
247 winStyles = ['wxTE_PROCESS_ENTER', 'wxTE_PROCESS_TAB', 'wxTE_MULTILINE',
248 'wxTE_PASSWORD', 'wxTE_READONLY']
249
250 class xxxChoice(xxxObject):
251 allParams = ['content', 'selection', 'pos', 'size', 'style']
252 required = ['content']
253
254 class xxxSlider(xxxObject):
255 allParams = ['value', 'min', 'max', 'pos', 'size', 'style',
256 'tickfreq', 'pagesize', 'linesize', 'thumb', 'tick',
257 'selmin', 'selmax']
258 paramDict = {'value': ParamInt, 'tickfreq': ParamInt, 'pagesize': ParamInt,
259 'linesize': ParamInt, 'thumb': ParamInt, 'thumb': ParamInt,
260 'tick': ParamInt, 'selmin': ParamInt, 'selmax': ParamInt}
261 required = ['value', 'min', 'max']
262 winStyles = ['wxSL_HORIZONTAL', 'wxSL_VERTICAL', 'wxSL_AUTOTICKS', 'wxSL_LABELS',
263 'wxSL_LEFT', 'wxSL_RIGHT', 'wxSL_TOP', 'wxSL_SELRANGE']
264
265 class xxxGauge(xxxObject):
266 allParams = ['range', 'pos', 'size', 'style', 'value', 'shadow', 'bezel']
267 paramDict = {'range': ParamInt, 'value': ParamInt,
268 'shadow': ParamInt, 'bezel': ParamInt}
269 winStyles = ['wxGA_HORIZONTAL', 'wxGA_VERTICAL', 'wxGA_PROGRESSBAR', 'wxGA_SMOOTH']
270
271 class xxxScrollBar(xxxObject):
272 allParams = ['pos', 'size', 'style', 'value', 'thumbsize', 'range', 'pagesize']
273 paramDict = {'value': ParamInt, 'range': ParamInt, 'thumbsize': ParamInt,
274 'pagesize': ParamInt}
275 winStyles = ['wxSB_HORIZONTAL', 'wxSB_VERTICAL']
276
277 class xxxListCtrl(xxxObject):
278 allParams = ['pos', 'size', 'style']
279 winStyles = ['wxLC_LIST', 'wxLC_REPORT', 'wxLC_ICON', 'wxLC_SMALL_ICON',
280 'wxLC_ALIGN_TOP', 'wxLC_ALIGN_LEFT', 'wxLC_AUTOARRANGE',
281 'wxLC_USER_TEXT', 'wxLC_EDIT_LABELS', 'wxLC_NO_HEADER',
282 'wxLC_SINGLE_SEL', 'wxLC_SORT_ASCENDING', 'wxLC_SORT_DESCENDING']
283
284 # !!! temporary
285 xxxCheckList = xxxListCtrl
286
287 class xxxTreeCtrl(xxxObject):
288 allParams = ['pos', 'size', 'style']
289 winStyles = ['wxTR_HAS_BUTTONS', 'wxTR_NO_LINES', 'wxTR_LINES_AT_ROOT',
290 'wxTR_EDIT_LABELS', 'wxTR_MULTIPLE']
291
292 class xxxHtmlWindow(xxxObject):
293 allParams = ['pos', 'size', 'style', 'borders', 'url', 'htmlcode']
294 paramDict = {'borders': ParamInt}
295 winStyles = ['wxHW_SCROLLBAR_NEVER', 'wxHW_SCROLLBAR_AUTO']
296
297 class xxxCalendar(xxxObject):
298 allParams = ['pos', 'size', 'style']
299
300 class xxxNotebook(xxxContainer):
301 allParams = ['usenotebooksizer', 'pos', 'size', 'style']
302 paramDict = {'usenotebooksizer': ParamBool}
303 winStyles = ['wxNB_FIXEDWIDTH', 'wxNB_LEFT', 'wxNB_RIGHT', 'wxNB_BOTTOM']
304
305 ################################################################################
306 # Buttons
307
308 class xxxButton(xxxObject):
309 allParams = ['label', 'default', 'pos', 'size', 'style']
310 paramDict = {'default': ParamBool}
311 required = ['label']
312 winStyles = ['wxBU_LEFT', 'wxBU_TOP', 'wxBU_RIGHT', 'wxBU_BOTTOM']
313
314 class xxxBitmapButton(xxxObject):
315 allParams = ['bitmap', 'selected', 'focus', 'disabled', 'default',
316 'pos', 'size', 'style']
317 required = ['bitmap']
318 winStyles = ['wxBU_LEFT', 'wxBU_TOP', 'wxBU_RIGHT', 'wxBU_BOTTOM']
319
320 class xxxRadioButton(xxxObject):
321 allParams = ['label', 'value', 'pos', 'size', 'style']
322 paramDict = {'value': ParamBool}
323 required = ['label']
324 winStyles = ['wxRB_GROUP']
325
326 class xxxSpinButton(xxxObject):
327 allParams = ['pos', 'size', 'style']
328 winStyles = ['wxSP_HORIZONTAL', 'wxSP_VERTICAL', 'wxSP_ARROW_KEYS', 'wxSP_WRAP']
329
330 ################################################################################
331 # Boxes
332
333 class xxxStaticBox(xxxObject):
334 allParams = ['label', 'pos', 'size', 'style']
335 required = ['label']
336
337 class xxxRadioBox(xxxObject):
338 allParams = ['label', 'content', 'selection', 'dimension', 'pos', 'size', 'style']
339 paramDict = {'dimension': ParamInt}
340 required = ['label', 'content']
341 winStyles = ['wxRA_SPECIFY_ROWS', 'wxRA_SPECIFY_COLS']
342
343 class xxxCheckBox(xxxObject):
344 allParams = ['label', 'pos', 'size', 'style']
345 required = ['label']
346
347 class xxxComboBox(xxxObject):
348 allParams = ['content', 'selection', 'value', 'pos', 'size', 'style']
349 required = ['content']
350 winStyles = ['wxCB_SIMPLE', 'wxCB_DROPDOWN', 'wxCB_READONLY', 'wxCB_DROPDOWN',
351 'wxCB_SORT']
352
353 class xxxListBox(xxxObject):
354 allParams = ['content', 'selection', 'pos', 'size', 'style']
355 required = ['content']
356 winStyles = ['wxLB_SINGLE', 'wxLB_MULTIPLE', 'wxLB_EXTENDED', 'wxLB_HSCROLL',
357 'wxLB_ALWAYS_SB', 'wxLB_NEEDED_SB', 'wxLB_SORT']
358
359 ################################################################################
360 # Sizers
361
362 class xxxSizer(xxxContainer):
363 hasName = hasStyle = false
364 paramDict = {'orient': ParamOrient}
365 isSizer = true
366
367 class xxxBoxSizer(xxxSizer):
368 allParams = ['orient']
369 required = ['orient']
370 default = {'orient': 'wxVERTICAL'}
371 # Tree icon depends on orientation
372 def treeImage(self):
373 if self.params['orient'].data == 'wxHORIZONTAL': return self.imageH
374 else: return self.imageV
375
376 class xxxStaticBoxSizer(xxxBoxSizer):
377 allParams = ['label', 'orient']
378 required = ['label', 'orient']
379 default = {'orient': 'wxVERTICAL'}
380
381 class xxxGridSizer(xxxSizer):
382 allParams = ['cols', 'rows', 'vgap', 'hgap']
383 required = ['cols']
384 default = {'cols': '2', 'rows': '2'}
385
386 class xxxFlexGridSizer(xxxGridSizer):
387 pass
388
389 # Container with only one child.
390 # Not shown in tree.
391 class xxxChildContainer(xxxObject):
392 hasName = hasStyle = false
393 hasChild = true
394 def __init__(self, parent, element):
395 xxxObject.__init__(self, parent, element)
396 # Must have one child with 'object' tag, but we don't check it
397 nodes = element.childNodes[:] # create copy
398 for node in nodes:
399 if node.nodeType == minidom.Node.ELEMENT_NODE:
400 if node.tagName == 'object':
401 # Create new xxx object for child node
402 self.child = MakeXXXFromDOM(self, node)
403 self.child.parent = parent
404 # Copy hasChildren and isSizer attributes
405 self.hasChildren = self.child.hasChildren
406 self.isSizer = self.child.isSizer
407 return # success
408 else:
409 element.removeChild(node)
410 node.unlink()
411 assert 0, 'no child found'
412 def generateHtml(self):
413 return xxxObject.generateHtml(self, '_') + '<hr>\n' + \
414 self.child.generateHtml()
415
416 class xxxSizerItem(xxxChildContainer):
417 allParams = ['option', 'flag', 'border']
418 paramDict = {'option': ParamInt}
419 def __init__(self, parent, element):
420 xxxChildContainer.__init__(self, parent, element)
421 # Remove pos parameter - unnecessary for sizeritems
422 if 'pos' in self.child.allParams:
423 self.child.allParams = self.child.allParams[:]
424 self.child.allParams.remove('pos')
425
426 class xxxNotebookPage(xxxChildContainer):
427 allParams = ['label', 'selected']
428 paramDict = {'selected': ParamBool}
429 required = ['label']
430 def __init__(self, parent, element):
431 xxxChildContainer.__init__(self, parent, element)
432 # pos and size dont matter for notebookpages
433 if 'pos' in self.child.allParams:
434 self.child.allParams = self.child.allParams[:]
435 self.child.allParams.remove('pos')
436 if 'size' in self.child.allParams:
437 self.child.allParams = self.child.allParams[:]
438 self.child.allParams.remove('size')
439
440 class xxxSpacer(xxxObject):
441 hasName = hasStyle = false
442 allParams = ['size', 'option', 'flag', 'border']
443 paramDict = {'option': ParamInt}
444 default = {'size': '0,0'}
445
446 class xxxMenuBar(xxxContainer):
447 allParams = []
448
449 class xxxMenu(xxxContainer):
450 allParams = ['label']
451 default = {'label': ''}
452
453 class xxxMenuItem(xxxObject):
454 allParams = ['checkable', 'label', 'accel', 'help']
455 default = {'label': ''}
456
457 class xxxSeparator(xxxObject):
458 hasName = hasStyle = false
459 allParams = []
460
461 ################################################################################
462
463 xxxDict = {
464 'wxPanel': xxxPanel,
465 'wxDialog': xxxDialog,
466 'wxFrame': xxxFrame,
467
468 'wxButton': xxxButton,
469 'wxBitmapButton': xxxBitmapButton,
470 'wxRadioButton': xxxRadioButton,
471 'wxSpinButton': xxxSpinButton,
472
473 'wxStaticBox': xxxStaticBox,
474 'wxRadioBox': xxxRadioBox,
475 'wxComboBox': xxxComboBox,
476 'wxCheckBox': xxxCheckBox,
477 'wxListBox': xxxListBox,
478
479 'wxStaticText': xxxStaticText,
480 'wxStaticLine': xxxStaticLine,
481 'wxTextCtrl': xxxTextCtrl,
482 'wxChoice': xxxChoice,
483 'wxSlider': xxxSlider,
484 'wxGauge': xxxGauge,
485 'wxScrollBar': xxxScrollBar,
486 'wxTreeCtrl': xxxTreeCtrl,
487 'wxListCtrl': xxxListCtrl,
488 'wxCheckList': xxxCheckList,
489 'wxNotebook': xxxNotebook,
490 'notebookpage': xxxNotebookPage,
491 'wxHtmlWindow': xxxHtmlWindow,
492 'wxCalendar': xxxCalendar,
493
494 'wxBoxSizer': xxxBoxSizer,
495 'wxStaticBoxSizer': xxxStaticBoxSizer,
496 'wxGridSizer': xxxGridSizer,
497 'wxFlexGridSizer': xxxFlexGridSizer,
498 'sizeritem': xxxSizerItem,
499 'spacer': xxxSpacer,
500
501 'wxMenuBar': xxxMenuBar,
502 'wxMenu': xxxMenu,
503 'wxMenuItem': xxxMenuItem,
504 'separator': xxxSeparator,
505 }
506
507 # Create IDs for all parameters of all classes
508 paramIDs = {'fg': wxNewId(), 'bg': wxNewId(), 'exstyle': wxNewId(), 'font': wxNewId(),
509 'enabled': wxNewId(), 'focused': wxNewId(), 'hidden': wxNewId(),
510 'tooltip': wxNewId()
511 }
512 for cl in xxxDict.values():
513 for param in cl.allParams + cl.paramDict.keys():
514 if not paramIDs.has_key(param):
515 paramIDs[param] = wxNewId()
516
517 ################################################################################
518 # Helper functions
519
520 # Test for object elements
521 def IsObject(node):
522 return node.nodeType == minidom.Node.ELEMENT_NODE and node.tagName == 'object'
523
524 # Make XXX object from some DOM object, selecting correct class
525 def MakeXXXFromDOM(parent, element):
526 return xxxDict[element.getAttribute('class')](parent, element)
527
528 # Make empty DOM element
529 def MakeEmptyDOM(className):
530 elem = tree.dom.createElement('object')
531 elem.setAttribute('class', className)
532 # Set required and default parameters
533 xxxClass = xxxDict[className]
534 defaultNotRequired = filter(lambda x, l=xxxClass.required: x not in l,
535 xxxClass.default.keys())
536 for param in xxxClass.required + defaultNotRequired:
537 textElem = tree.dom.createElement(param)
538 try:
539 textNode = tree.dom.createTextNode(xxxClass.default[param])
540 except KeyError:
541 textNode = tree.dom.createTextNode('')
542 textElem.appendChild(textNode)
543 elem.appendChild(textElem)
544 return elem
545
546 # Make empty XXX object
547 def MakeEmptyXXX(parent, className):
548 # Make corresponding DOM object first
549 elem = MakeEmptyDOM(className)
550 # If parent is a sizer, we should create sizeritem object, except for spacers
551 if parent:
552 if parent.isSizer and className != 'spacer':
553 sizerItemElem = MakeEmptyDOM('sizeritem')
554 sizerItemElem.appendChild(elem)
555 elem = sizerItemElem
556 elif isinstance(parent, xxxNotebook):
557 pageElem = MakeEmptyDOM('notebookpage')
558 pageElem.appendChild(elem)
559 elem = pageElem
560 # Now just make object
561 return MakeXXXFromDOM(parent, elem)
562