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