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>
6 from wxPython
.wx
import *
7 from wxPython
.xrc
import *
8 from xml
.dom
import minidom
9 import wxPython
.lib
.wxpTag
13 # Classes to interface DOM objects
15 # Param ids for controls
16 ID_CHECK_PARAMS
= wxNewId()
17 ID_TEXT_PARAMS
= wxNewId()
19 hasChildren
= false
# has children elements?
20 hasName
= true
# has name attribute?
21 isSizer
= hasChild
= false
22 # Required paremeters: none by default
24 # Default parameters with default values
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
):
36 self
.element
= element
39 self
.className
= element
.getAttribute('class')
40 if self
.hasName
: self
.name
= element
.getAttribute('name')
41 # Set parameters (text element children)
43 nodes
= element
.childNodes
[:]
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
54 nodes
= node
.childNodes
[:]
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
)
64 text
= n
.childNodes
[0] # first child must be text node
65 assert text
.nodeType
== minidom
.Node
.TEXT_NODE
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
)
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
81 # Remove all other nodes
82 element
.removeChild(node
)
86 def generateHtml(self
, prefix
=''):
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
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
)
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
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
+ ' ')
116 if self
.params
.has_key(param
):
117 if param
== 'content':
119 for text
in self
.params
[param
]:
120 l
.append(str(text
.data
)) # convert from unicode
123 value
= "('" + self
.params
[param
].data
+ "')"
128 # Local or overriden type
129 typeClass
= self
.paramDict
[param
].__name
__
133 typeClass
= paramDict
[param
].__name
__
136 typeClass
= 'ParamText'
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">
144 """ % (typeClass
, self
.ID_TEXT_PARAMS
,
145 prefix
+ param
, value
, prefix
+ param
)
148 # Returns real tree object
149 def treeObject(self
):
150 if self
.hasChild
: return self
.child
152 # Returns tree image index
154 if self
.hasChild
: return self
.child
.treeImage()
156 # Class name plus wx name
158 if self
.hasChild
: return self
.child
.treeName()
159 if self
.hasName
and self
.name
: return self
.className
+ ' "' + self
.name
+ '"'
160 return self
.className
162 ################################################################################
164 class xxxContainer(xxxObject
):
167 ################################################################################
170 class xxxPanel(xxxContainer
):
171 allParams
= ['pos', 'size', 'style']
173 class xxxDialog(xxxContainer
):
174 allParams
= ['title', 'pos', 'size', 'style']
176 styles
= ['wxDIALOG_MODAL', 'wxCAPTION', 'wxDEFAULT_DIALOG_STYLE',
177 'wxRESIZE_BORDER', 'wxSYSTEM_MENU', 'wxTHICK_FRAME', 'wxSTAY_ON_TOP']
179 class xxxFrame(xxxContainer
):
180 allParams
= ['title', 'centered', 'pos', 'size', 'style']
181 paramDict
= {'centered': ParamBool}
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']
188 ################################################################################
191 class xxxStaticText(xxxObject
):
192 allParams
= ['label', 'pos', 'size', 'style']
194 styles
= ['wxALIGN_LEFT', 'wxALIGN_RIGHT', 'wxALIGN_CENTRE', 'wxST_NO_AUTORESIZE']
196 class xxxStaticLine(xxxObject
):
197 allParams
= ['pos', 'size', 'style']
198 styles
= ['wxLI_HORIZONTAL', 'wxLI_VERTICAL']
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']
205 class xxxChoice(xxxObject
):
206 allParams
= ['content', 'selection', 'pos', 'size', 'style']
207 required
= ['content']
209 class xxxSlider(xxxObject
):
210 allParams
= ['value', 'min', 'max', 'pos', 'size', 'style',
211 'tickfreq', 'pagesize', 'linesize', 'thumb', 'tick',
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']
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']
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']
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']
240 xxxCheckList
= xxxListCtrl
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']
247 class xxxHtmlWindow(xxxObject
):
248 allParams
= ['pos', 'size', 'style', 'borders', 'url', 'htmlcode']
249 paramDict
= {'borders': ParamInt}
250 styles
= ['wxHW_SCROLLBAR_NEVER', 'wxHW_SCROLLBAR_AUTO']
252 class xxxCalendar(xxxObject
):
253 allParams
= ['pos', 'size', 'style']
255 class xxxNotebook(xxxContainer
):
256 allParams
= ['usenotebooksizer', 'pos', 'size', 'style']
257 paramDict
= {'usenotebooksizer': ParamBool}
258 styles
= ['wxNB_FIXEDWIDTH', 'wxNB_LEFT', 'wxNB_RIGHT', 'wxNB_BOTTOM']
260 ################################################################################
263 class xxxButton(xxxObject
):
264 allParams
= ['label', 'default', 'pos', 'size', 'style']
265 paramDict
= {'default': ParamBool}
267 styles
= ['wxBU_LEFT', 'wxBU_TOP', 'wxBU_RIGHT', 'wxBU_BOTTOM']
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']
275 class xxxRadioButton(xxxObject
):
276 allParams
= ['label', 'value', 'pos', 'size', 'style']
277 paramDict
= {'value': ParamBool}
279 styles
= ['wxRB_GROUP']
281 class xxxSpinButton(xxxObject
):
282 allParams
= ['pos', 'size', 'style']
283 styles
= ['wxSP_HORIZONTAL', 'wxSP_VERTICAL', 'wxSP_ARROW_KEYS', 'wxSP_WRAP']
285 ################################################################################
288 class xxxStaticBox(xxxObject
):
289 allParams
= ['label', 'pos', 'size', 'style']
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']
298 class xxxCheckBox(xxxObject
):
299 allParams
= ['label', 'pos', 'size', 'style']
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',
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']
314 ################################################################################
317 class xxxSizer(xxxContainer
):
319 paramDict
= {'orient': ParamOrient}
322 class xxxBoxSizer(xxxSizer
):
323 allParams
= ['orient']
324 required
= ['orient']
325 default
= {'orient': 'wxVERTICAL'}
326 # Tree icon depends on orientation
328 if self
.params
['orient'].data
== 'wxHORIZONTAL': return self
.imageH
329 else: return self
.imageV
331 class xxxStaticBoxSizer(xxxBoxSizer
):
332 allParams
= ['label', 'orient']
333 required
= ['label', 'orient']
334 default
= {'orient': 'wxVERTICAL'}
336 class xxxGridSizer(xxxSizer
):
337 allParams
= ['cols', 'rows', 'vgap', 'hgap']
339 default
= {'cols': '2', 'rows': '2'}
341 class xxxFlexGridSizer(xxxGridSizer
):
344 # Container with only one child.
346 class xxxChildContainer(xxxObject
):
348 ID_CHECK_PARAMS
= wxNewId()
349 ID_TEXT_PARAMS
= wxNewId()
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
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
367 element
.removeChild(node
)
369 assert 0, 'no child found'
370 def generateHtml(self
):
371 return xxxObject
.generateHtml(self
, '_') + '<hr>\n' + \
372 self
.child
.generateHtml()
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')
384 class xxxNotebookPage(xxxChildContainer
):
385 allParams
= ['label', 'selected']
386 paramDict
= {'selected': ParamBool}
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')
398 class xxxSpacer(xxxObject
):
400 allParams
= ['size', 'option', 'flag', 'border']
401 paramDict
= {'option': ParamInt}
402 default
= {'size': '0,0'}
404 class xxxMenuBar(xxxContainer
):
407 class xxxMenu(xxxContainer
):
408 allParams
= ['label']
409 default
= {'label': ''}
411 class xxxMenuItem(xxxObject
):
412 allParams
= ['checkable', 'label', 'accel', 'help']
413 default
= {'label': ''}
415 class xxxSeparator(xxxObject
):
421 'wxDialog': xxxDialog
,
424 'wxButton': xxxButton
,
425 'wxBitmapButton': xxxBitmapButton
,
426 'wxRadioButton': xxxRadioButton
,
427 'wxSpinButton': xxxSpinButton
,
429 'wxStaticBox': xxxStaticBox
,
430 'wxRadioBox': xxxRadioBox
,
431 'wxComboBox': xxxComboBox
,
432 'wxCheckBox': xxxCheckBox
,
433 'wxListBox': xxxListBox
,
435 'wxStaticText': xxxStaticText
,
436 'wxStaticLine': xxxStaticLine
,
437 'wxTextCtrl': xxxTextCtrl
,
438 'wxChoice': xxxChoice
,
439 'wxSlider': xxxSlider
,
441 'wxScrollBar': xxxScrollBar
,
442 'wxTreeCtrl': xxxTreeCtrl
,
443 'wxListCtrl': xxxListCtrl
,
444 'wxCheckList': xxxCheckList
,
445 'wxNotebook': xxxNotebook
,
446 'notebookpage': xxxNotebookPage
,
447 'wxHtmlWindow': xxxHtmlWindow
,
448 'wxCalendar': xxxCalendar
,
450 'wxBoxSizer': xxxBoxSizer
,
451 'wxStaticBoxSizer': xxxStaticBoxSizer
,
452 'wxGridSizer': xxxGridSizer
,
453 'wxFlexGridSizer': xxxFlexGridSizer
,
454 'sizeritem': xxxSizerItem
,
457 'wxMenuBar': xxxMenuBar
,
459 'wxMenuItem': xxxMenuItem
,
460 'separator': xxxSeparator
,
465 # Test for object elements
467 return node
.nodeType
== minidom
.Node
.ELEMENT_NODE
and node
.tagName
== 'object'
469 # Make XXX object from some DOM object, selecting correct class
470 def MakeXXXFromDOM(parent
, element
):
471 return xxxDict
[element
.getAttribute('class')](parent
, element
)
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
)
484 textNode
= tree
.dom
.createTextNode(xxxClass
.default
[param
])
486 textNode
= tree
.dom
.createTextNode('')
487 textElem
.appendChild(textNode
)
488 elem
.appendChild(textElem
)
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
497 if parent
.isSizer
and className
!= 'spacer':
498 sizerItemElem
= MakeEmptyDOM('sizeritem')
499 sizerItemElem
.appendChild(elem
)
501 elif isinstance(parent
, xxxNotebook
):
502 pageElem
= MakeEmptyDOM('notebookpage')
503 pageElem
.appendChild(elem
)
505 # Now just make object
506 return MakeXXXFromDOM(parent
, elem
)