]>
Commit | Line | Data |
---|---|---|
09f3d4e6 RD |
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 + ' ') | |
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 |