X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/0d9b8891484035ec88f975c8b8bad33adc8db418..52cd0643658c92b11c85e977b8cefd059df509b0:/wxPython/wx/tools/XRCed/xxx.py diff --git a/wxPython/wx/tools/XRCed/xxx.py b/wxPython/wx/tools/XRCed/xxx.py index 03bb4f70bc..c0ef04012f 100644 --- a/wxPython/wx/tools/XRCed/xxx.py +++ b/wxPython/wx/tools/XRCed/xxx.py @@ -7,6 +7,7 @@ from xml.dom import minidom from globals import * from params import * +import traceback, types # Base class for interface parameter classes class xxxNode: @@ -40,19 +41,23 @@ class xxxParam(xxxNode): # Use convertion from unicode to current encoding self.textNode = text # Value returns string - if wxUSE_UNICODE: # no conversion is needed + if wx.USE_UNICODE: # no conversion is needed def value(self): return self.textNode.data def update(self, value): self.textNode.data = value else: def value(self): - return self.textNode.data.encode(g.currentEncoding) + try: + return self.textNode.data.encode(g.currentEncoding) + except LookupError: + return self.textNode.data.encode() def update(self, value): try: # handle exception if encoding is wrong self.textNode.data = unicode(value, g.currentEncoding) except UnicodeDecodeError: - wxLogMessage("Unicode error: set encoding in file\nglobals.py to something appropriate") + self.textNode.data = unicode(value) + #wx.LogMessage("Unicode error: set encoding in file\nglobals.py to something appropriate") # Integer parameter class xxxParamInt(xxxParam): @@ -86,7 +91,7 @@ class xxxParamContent(xxxNode): text = n.childNodes[0] # first child must be text node assert text.nodeType == minidom.Node.TEXT_NODE l.append(text) - data.append(str(text.data)) + data.append(text.data) else: # remove other node.removeChild(n) n.unlink() @@ -185,6 +190,7 @@ class xxxObject: hasStyle = True # almost everyone hasName = True # has name attribute? isSizer = hasChild = False + isElement = True allParams = None # Some nodes have no parameters # Style parameters (all optional) styles = ['fg', 'bg', 'font', 'enabled', 'focused', 'hidden', 'tooltip'] @@ -204,44 +210,54 @@ class xxxObject: #image = -1 # Construct a new xxx object from DOM element # parent is parent xxx object (or None if none), element is DOM element object - def __init__(self, parent, element): + def __init__(self, parent, element, refElem=None): self.parent = parent - self.element = element + self.node = element + self.refElem = refElem self.undo = None - # Get attributes - self.className = element.getAttribute('class') + # Reference are dereferenced + if element.tagName == 'object_ref': + # Find original object + self.ref = element.getAttribute('ref') + if refElem: + self.className = self.refElem.getAttribute('class') + else: + self.className = 'xxxUnknown' + self.required = [] + else: + # Get attributes + self.ref = None + self.className = element.getAttribute('class') self.subclass = element.getAttribute('subclass') if self.hasName: self.name = element.getAttribute('name') # Set parameters (text element children) self.params = {} - nodes = element.childNodes[:] - for node in nodes: - if node.nodeType == minidom.Node.ELEMENT_NODE: - tag = node.tagName - if tag == 'object': + for n in element.childNodes[:]: + if n.nodeType == minidom.Node.ELEMENT_NODE: + tag = n.tagName + if tag in ['object', 'object_ref']: continue # do nothing for object children here - if tag not in self.allParams and tag not in self.styles: + elif tag not in self.allParams and tag not in self.styles: print 'WARNING: unknown parameter for %s: %s' % \ (self.className, tag) elif tag in self.specials: - self.special(tag, node) + self.special(tag, n) elif tag == 'content': if self.className == 'wxCheckListBox': - self.params[tag] = xxxParamContentCheckList(node) + self.params[tag] = xxxParamContentCheckList(n) else: - self.params[tag] = xxxParamContent(node) + self.params[tag] = xxxParamContent(n) elif tag == 'font': # has children - self.params[tag] = xxxParamFont(element, node) + self.params[tag] = xxxParamFont(element, n) elif tag in self.bitmapTags: # Can have attributes - self.params[tag] = xxxParamBitmap(node) + self.params[tag] = xxxParamBitmap(n) else: # simple parameter - self.params[tag] = xxxParam(node) - else: - pass - # Remove all other nodes -# element.removeChild(node) -# node.unlink() + self.params[tag] = xxxParam(n) + elif n.nodeType == minidom.Node.TEXT_NODE and n.data.isspace(): + # Remove empty text nodes + element.removeChild(n) + n.unlink() # Check that all required params are set for param in self.required: @@ -266,11 +282,11 @@ class xxxObject: break if found: nextTextElem = self.params[p].node - self.element.insertBefore(elem, nextTextElem) + self.node.insertBefore(elem, nextTextElem) else: - self.element.appendChild(elem) + self.node.appendChild(elem) else: - wxLogWarning('Required parameter %s of %s missing' % + wx.LogWarning('Required parameter %s of %s missing' % (param, self.className)) # Returns real tree object def treeObject(self): @@ -289,8 +305,69 @@ class xxxObject: return className # Class name or subclass def panelName(self): - if self.subclass: return self.subclass + '(' + self.className + ')' - else: return self.className + if self.subclass: name = self.subclass + '(' + self.className + ')' + name = self.className + if self.ref: name = 'ref: ' + self.ref + ', ' + name + return name + # Sets name of tree object + def setTreeName(self, name): + if self.hasChild: obj = self.child + else: obj = self + obj.name = name + obj.node.setAttribute('name', name) + # Set normal (text) params + def set(self, param, value): + try: + self.params[param].update(value) + except KeyError: + elem = g.tree.dom.createElement(param) + p = xxxParam(elem) + p.update(value) + self.params[param] = p + self.node.appendChild(elem) + # Special processing for growablecols-like parameters + # represented by several nodes + def special(self, tag, node): + if not self.params.has_key(tag): + # Create new multi-group + self.params[tag] = xxxParamMulti(node) + self.params[tag].append(xxxParamInt(node)) + def setSpecial(self, param, value): + # Straightforward implementation: remove, add again + self.params[param].remove() + del self.params[param] + for i in value: + node = g.tree.dom.createElement(param) + text = g.tree.dom.createTextNode(str(i)) + node.appendChild(text) + self.node.appendChild(node) + self.special(param, node) + +# Imitation of FindResource/DoFindResource from xmlres.cpp +def DoFindResource(parent, name, classname, recursive): + for n in parent.childNodes: + if n.nodeType == minidom.Node.ELEMENT_NODE and \ + n.tagName in ['object', 'object_ref'] and \ + n.getAttribute('name') == name: + cls = n.getAttribute('class') + if not classname or cls == classname: return n + if not cls or n.tagName == 'object_ref': + refName = n.getAttribute('ref') + if not refName: continue + refNode = FindResource(refName) + if refName and refNode.getAttribute('class') == classname: + return n + if recursive: + for n in parent.childNodes: + if n.nodeType == minidom.Node.ELEMENT_NODE and \ + n.tagName in ['object', 'object_ref']: + found = DoFindResource(n, name, classname, True) + if found: return found +def FindResource(name, classname='', recursive=True): + found = DoFindResource(g.tree.mainNode, name, classname, recursive) + if found: return found + wx.LogError('XRC resource "%s" not found!' % name) + ################################################################################ @@ -311,7 +388,7 @@ class xxxParamFont(xxxObject, xxxNode): self.data = v def update(self, value): # `value' is a list of strings corresponding to all parameters - elem = self.element + elem = self.node # Remove old elements first childNodes = elem.childNodes[:] for node in childNodes: elem.removeChild(node) @@ -361,6 +438,7 @@ class xxxMainNode(xxxContainer): class xxxPanel(xxxContainer): allParams = ['pos', 'size', 'style'] + winStyles = ['wxNO_3D', 'wxTAB_TRAVERSAL'] styles = ['fg', 'bg', 'font', 'enabled', 'focused', 'hidden', 'exstyle', 'tooltip'] @@ -369,11 +447,13 @@ class xxxDialog(xxxContainer): paramDict = {'centered': ParamBool} required = ['title'] default = {'title': ''} - winStyles = ['wxDEFAULT_DIALOG_STYLE', - 'wxCAPTION', 'wxMINIMIZE_BOX', 'wxMAXIMIZE_BOX', 'wxCLOSE_BOX', - 'wxSTAY_ON_TOP', - 'wxTHICK_FRAME', - 'wxNO_3D', 'wxDIALOG_NO_PARENT'] + winStyles = ['wxDEFAULT_DIALOG_STYLE', 'wxCAPTION', + 'wxSTAY_ON_TOP', 'wxSYSTEM_MENU', 'wxTHICK_FRAME', + 'wxRESIZE_BORDER', 'wxRESIZE_BOX', 'wxCLOSE_BOX', + 'wxMAXIMIZE_BOX', 'wxMINIMIZE_BOX', + 'wxDIALOG_MODAL', 'wxDIALOG_MODELESS', 'wxDIALOG_NO_PARENT' + 'wxNO_3D', 'wxTAB_TRAVERSAL'] + exStyles = ['wxWS_EX_VALIDATE_RECURSIVELY', 'wxDIALOG_EX_METAL'] styles = ['fg', 'bg', 'font', 'enabled', 'focused', 'hidden', 'exstyle', 'tooltip'] @@ -382,30 +462,40 @@ class xxxFrame(xxxContainer): paramDict = {'centered': ParamBool} required = ['title'] default = {'title': ''} - winStyles = ['wxDEFAULT_FRAME_STYLE', - 'wxCAPTION', 'wxMINIMIZE_BOX', 'wxMAXIMIZE_BOX', 'wxCLOSE_BOX', - 'wxSTAY_ON_TOP', - 'wxSYSTEM_MENU', 'wxRESIZE_BORDER', - 'wxFRAME_TOOL_WINDOW', 'wxFRAME_NO_TASKBAR', - 'wxFRAME_FLOAT_ON_PARENT', 'wxFRAME_SHAPED' - ] + winStyles = ['wxDEFAULT_FRAME_STYLE', 'wxDEFAULT_DIALOG_STYLE', 'wxCAPTION', + 'wxSTAY_ON_TOP', 'wxSYSTEM_MENU', 'wxTHICK_FRAME', + 'wxRESIZE_BORDER', 'wxRESIZE_BOX', 'wxCLOSE_BOX', + 'wxMAXIMIZE_BOX', 'wxMINIMIZE_BOX', + 'wxFRAME_NO_TASKBAR', 'wxFRAME_SHAPED', 'wxFRAME_TOOL_WINDOW', + 'wxFRAME_FLOAT_ON_PARENT', + 'wxNO_3D', 'wxTAB_TRAVERSAL'] + exStyles = ['wxWS_EX_VALIDATE_RECURSIVELY', 'wxFRAME_EX_METAL'] styles = ['fg', 'bg', 'font', 'enabled', 'focused', 'hidden', 'exstyle', 'tooltip'] class xxxTool(xxxObject): - allParams = ['bitmap', 'bitmap2', 'toggle', 'tooltip', 'longhelp', 'label'] + allParams = ['bitmap', 'bitmap2', 'radio', 'toggle', 'tooltip', 'longhelp', 'label'] required = ['bitmap'] - paramDict = {'bitmap2': ParamBitmap, 'toggle': ParamBool} + paramDict = {'bitmap2': ParamBitmap, 'radio': ParamBool, 'toggle': ParamBool} hasStyle = False class xxxToolBar(xxxContainer): - allParams = ['bitmapsize', 'margins', 'packing', 'separation', + allParams = ['bitmapsize', 'margins', 'packing', 'separation', 'dontattachtoframe', 'pos', 'size', 'style'] hasStyle = False paramDict = {'bitmapsize': ParamPosSize, 'margins': ParamPosSize, - 'packing': ParamInt, 'separation': ParamInt, + 'packing': ParamUnit, 'separation': ParamUnit, + 'dontattachtoframe': ParamBool, 'style': ParamNonGenericStyle} + winStyles = ['wxTB_FLAT', 'wxTB_DOCKABLE', 'wxTB_VERTICAL', 'wxTB_HORIZONTAL', + 'wxTB_3DBUTTONS','wxTB_TEXT', 'wxTB_NOICONS', 'wxTB_NODIVIDER', + 'wxTB_NOALIGN', 'wxTB_HORZ_LAYOUT', 'wxTB_HORZ_TEXT'] + +class xxxStatusBar(xxxObject): + hasStyle = False + allParams = ['fields', 'widths', 'styles', 'style'] + paramDict = {'fields': ParamIntNN, 'widths': ParamText, 'styles': ParamText, 'style': ParamNonGenericStyle} - winStyles = ['wxTB_FLAT', 'wxTB_DOCKABLE', 'wxTB_VERTICAL', 'wxTB_HORIZONTAL', 'wxTB_TEXT'] + winStyles = ['wxST_SIZEGRIP'] class xxxWizard(xxxContainer): allParams = ['title', 'bitmap', 'pos'] @@ -413,6 +503,7 @@ class xxxWizard(xxxContainer): default = {'title': ''} winStyles = [] exStyles = ['wxWIZARD_EX_HELPBUTTON'] + styles = ['fg', 'bg', 'font', 'exstyle'] class xxxWizardPage(xxxContainer): allParams = ['bitmap'] @@ -454,8 +545,24 @@ class xxxStaticBitmap(xxxObject): class xxxTextCtrl(xxxObject): allParams = ['value', 'pos', 'size', 'style'] - winStyles = ['wxTE_PROCESS_ENTER', 'wxTE_PROCESS_TAB', 'wxTE_MULTILINE', - 'wxTE_PASSWORD', 'wxTE_READONLY', 'wxHSCROLL'] + winStyles = ['wxTE_NO_VSCROLL', + 'wxTE_AUTO_SCROLL', + 'wxTE_PROCESS_ENTER', + 'wxTE_PROCESS_TAB', + 'wxTE_MULTILINE', + 'wxTE_PASSWORD', + 'wxTE_READONLY', + 'wxHSCROLL', + 'wxTE_RICH', + 'wxTE_RICH2', + 'wxTE_AUTO_URL', + 'wxTE_NOHIDESEL', + 'wxTE_LEFT', + 'wxTE_CENTRE', + 'wxTE_RIGHT', + 'wxTE_DONTWRAP', + 'wxTE_LINEWRAP', + 'wxTE_WORDWRAP'] paramDict = {'value': ParamMultilineText} class xxxChoice(xxxObject): @@ -468,67 +575,106 @@ class xxxSlider(xxxObject): allParams = ['value', 'min', 'max', 'pos', 'size', 'style', 'tickfreq', 'pagesize', 'linesize', 'thumb', 'tick', 'selmin', 'selmax'] - paramDict = {'value': ParamInt, 'tickfreq': ParamInt, 'pagesize': ParamInt, - 'linesize': ParamInt, 'thumb': ParamInt, 'thumb': ParamInt, + paramDict = {'value': ParamInt, 'tickfreq': ParamIntNN, 'pagesize': ParamIntNN, + 'linesize': ParamIntNN, 'thumb': ParamUnit, 'tick': ParamInt, 'selmin': ParamInt, 'selmax': ParamInt} required = ['value', 'min', 'max'] winStyles = ['wxSL_HORIZONTAL', 'wxSL_VERTICAL', 'wxSL_AUTOTICKS', 'wxSL_LABELS', 'wxSL_LEFT', 'wxSL_RIGHT', 'wxSL_TOP', 'wxSL_BOTTOM', - 'wxSL_BOTH', 'wxSL_SELRANGE'] + 'wxSL_BOTH', 'wxSL_SELRANGE', 'wxSL_INVERSE'] class xxxGauge(xxxObject): allParams = ['range', 'pos', 'size', 'style', 'value', 'shadow', 'bezel'] - paramDict = {'range': ParamInt, 'value': ParamInt, - 'shadow': ParamInt, 'bezel': ParamInt} + paramDict = {'range': ParamIntNN, 'value': ParamIntNN, + 'shadow': ParamIntNN, 'bezel': ParamIntNN} winStyles = ['wxGA_HORIZONTAL', 'wxGA_VERTICAL', 'wxGA_PROGRESSBAR', 'wxGA_SMOOTH'] class xxxScrollBar(xxxObject): allParams = ['pos', 'size', 'style', 'value', 'thumbsize', 'range', 'pagesize'] - paramDict = {'value': ParamInt, 'range': ParamInt, 'thumbsize': ParamInt, - 'pagesize': ParamInt} + paramDict = {'value': ParamIntNN, 'range': ParamIntNN, 'thumbsize': ParamIntNN, + 'pagesize': ParamIntNN} winStyles = ['wxSB_HORIZONTAL', 'wxSB_VERTICAL'] class xxxListCtrl(xxxObject): allParams = ['pos', 'size', 'style'] winStyles = ['wxLC_LIST', 'wxLC_REPORT', 'wxLC_ICON', 'wxLC_SMALL_ICON', - 'wxLC_ALIGN_TOP', 'wxLC_ALIGN_LEFT', 'wxLC_AUTOARRANGE', - 'wxLC_USER_TEXT', 'wxLC_EDIT_LABELS', 'wxLC_NO_HEADER', - 'wxLC_SINGLE_SEL', 'wxLC_SORT_ASCENDING', 'wxLC_SORT_DESCENDING'] + 'wxLC_ALIGN_TOP', 'wxLC_ALIGN_LEFT', 'wxLC_AUTOARRANGE', + 'wxLC_USER_TEXT', 'wxLC_EDIT_LABELS', 'wxLC_NO_HEADER', + 'wxLC_SINGLE_SEL', 'wxLC_SORT_ASCENDING', 'wxLC_SORT_DESCENDING', + 'wxLC_VIRTUAL', 'wxLC_HRULES', 'wxLC_VRULES', 'wxLC_NO_SORT_HEADER'] class xxxTreeCtrl(xxxObject): allParams = ['pos', 'size', 'style'] - winStyles = ['wxTR_HAS_BUTTONS', 'wxTR_NO_LINES', 'wxTR_LINES_AT_ROOT', - 'wxTR_EDIT_LABELS', 'wxTR_MULTIPLE'] + winStyles = ['wxTR_EDIT_LABELS', + 'wxTR_NO_BUTTONS', + 'wxTR_HAS_BUTTONS', + 'wxTR_TWIST_BUTTONS', + 'wxTR_NO_LINES', + 'wxTR_FULL_ROW_HIGHLIGHT', + 'wxTR_LINES_AT_ROOT', + 'wxTR_HIDE_ROOT', + 'wxTR_ROW_LINES', + 'wxTR_HAS_VARIABLE_ROW_HEIGHT', + 'wxTR_SINGLE', + 'wxTR_MULTIPLE', + 'wxTR_EXTENDED', + 'wxTR_DEFAULT_STYLE'] class xxxHtmlWindow(xxxObject): allParams = ['pos', 'size', 'style', 'borders', 'url', 'htmlcode'] - paramDict = {'borders': ParamInt, 'htmlcode':ParamMultilineText} - winStyles = ['wxHW_SCROLLBAR_NEVER', 'wxHW_SCROLLBAR_AUTO'] + paramDict = {'htmlcode':ParamMultilineText} + winStyles = ['wxHW_SCROLLBAR_NEVER', 'wxHW_SCROLLBAR_AUTO', 'wxHW_NO_SELECTION'] class xxxCalendarCtrl(xxxObject): allParams = ['pos', 'size', 'style'] + winStyles = ['wxCAL_SUNDAY_FIRST', 'wxCAL_MONDAY_FIRST', 'wxCAL_SHOW_HOLIDAYS', + 'wxCAL_NO_YEAR_CHANGE', 'wxCAL_NO_MONTH_CHANGE', + 'wxCAL_SEQUENTIAL_MONTH_SELECTION', 'wxCAL_SHOW_SURROUNDING_WEEKS'] class xxxNotebook(xxxContainer): - allParams = ['usenotebooksizer', 'pos', 'size', 'style'] - paramDict = {'usenotebooksizer': ParamBool} - winStyles = ['wxNB_FIXEDWIDTH', 'wxNB_LEFT', 'wxNB_RIGHT', 'wxNB_BOTTOM'] + allParams = ['pos', 'size', 'style'] + winStyles = ['wxNB_TOP', 'wxNB_LEFT', 'wxNB_RIGHT', 'wxNB_BOTTOM', + 'wxNB_FIXEDWIDTH', 'wxNB_MULTILINE', 'wxNB_NOPAGETHEME', 'wxNB_FLAT'] +class xxxChoicebook(xxxContainer): + allParams = ['pos', 'size', 'style'] + winStyles = ['wxCHB_DEFAULT', 'wxCHB_LEFT', 'wxCHB_RIGHT', 'wxCHB_TOP', 'wxCHB_BOTTOM'] + +class xxxListbook(xxxContainer): + allParams = ['pos', 'size', 'style'] + winStyles = ['wxLB_DEFAULT', 'wxLB_LEFT', 'wxLB_RIGHT', 'wxLB_TOP', 'wxLB_BOTTOM'] + class xxxSplitterWindow(xxxContainer): allParams = ['orientation', 'sashpos', 'minsize', 'pos', 'size', 'style'] paramDict = {'orientation': ParamOrientation, 'sashpos': ParamUnit, 'minsize': ParamUnit } - winStyles = ['wxSP_3D', 'wxSP_3DSASH', 'wxSP_3DBORDER', 'wxSP_BORDER', - 'wxSP_NOBORDER', 'wxSP_PERMIT_UNSPLIT', 'wxSP_LIVE_UPDATE', - 'wxSP_NO_XP_THEME' ] + winStyles = ['wxSP_3D', 'wxSP_3DSASH', 'wxSP_3DBORDER', + 'wxSP_FULLSASH', 'wxSP_NOBORDER', 'wxSP_PERMIT_UNSPLIT', 'wxSP_LIVE_UPDATE', + 'wxSP_NO_XP_THEME' ] class xxxGenericDirCtrl(xxxObject): allParams = ['defaultfolder', 'filter', 'defaultfilter', 'pos', 'size', 'style'] - paramDict = {'defaultfilter': ParamInt} + paramDict = {'defaultfilter': ParamIntNN} winStyles = ['wxDIRCTRL_DIR_ONLY', 'wxDIRCTRL_3D_INTERNAL', 'wxDIRCTRL_SELECT_FIRST', - 'wxDIRCTRL_SHOW_FILTERS', 'wxDIRCTRL_EDIT_LABELS'] + 'wxDIRCTRL_SHOW_FILTERS'] class xxxScrolledWindow(xxxContainer): allParams = ['pos', 'size', 'style'] - winStyles = ['wxHSCROLL', 'wxVSCROLL'] + winStyles = ['wxHSCROLL', 'wxVSCROLL', 'wxNO_3D', 'wxTAB_TRAVERSAL'] + +class xxxDateCtrl(xxxObject): + allParams = ['pos', 'size', 'style', 'borders'] + winStyles = ['wxDP_DEFAULT', 'wxDP_SPIN', 'wxDP_DROPDOWN', + 'wxDP_ALLOWNONE', 'wxDP_SHOWCENTURY'] + +class xxxGrid(xxxObject): + allParams = ['pos', 'size', 'style'] + +class xxxFilePickerCtrl(xxxObject): + allParams = ['value', 'message', 'wildcard', 'pos', 'size', 'style'] + winStyles = ['wxFLP_OPEN', 'wxFLP_SAVE', 'wxFLP_OVERWRITE_PROMPT', + 'wxFLP_FILE_MUST_EXIST', 'wxFLP_CHANGE_DIR', + 'wxFLP_DEFAULT_STYLE'] + ################################################################################ # Buttons @@ -537,20 +683,23 @@ class xxxButton(xxxObject): allParams = ['label', 'default', 'pos', 'size', 'style'] paramDict = {'default': ParamBool} required = ['label'] - winStyles = ['wxBU_LEFT', 'wxBU_TOP', 'wxBU_RIGHT', 'wxBU_BOTTOM'] + winStyles = ['wxBU_LEFT', 'wxBU_TOP', 'wxBU_RIGHT', 'wxBU_BOTTOM', 'wxBU_EXACTFIT', + 'wxNO_BORDER'] class xxxBitmapButton(xxxObject): allParams = ['bitmap', 'selected', 'focus', 'disabled', 'default', 'pos', 'size', 'style'] + paramDict = {'selected': ParamBitmap, 'focus': ParamBitmap, 'disabled': ParamBitmap, + 'default': ParamBool} required = ['bitmap'] - winStyles = ['wxBU_AUTODRAW', 'wxBU_LEFT', 'wxBU_TOP', - 'wxBU_RIGHT', 'wxBU_BOTTOM'] + winStyles = ['wxBU_AUTODRAW', 'wxBU_LEFT', 'wxBU_RIGHT', + 'wxBU_TOP', 'wxBU_BOTTOM'] class xxxRadioButton(xxxObject): allParams = ['label', 'value', 'pos', 'size', 'style'] paramDict = {'value': ParamBool} required = ['label'] - winStyles = ['wxRB_GROUP'] + winStyles = ['wxRB_GROUP', 'wxRB_SINGLE'] class xxxSpinButton(xxxObject): allParams = ['value', 'min', 'max', 'pos', 'size', 'style'] @@ -576,10 +725,11 @@ class xxxStaticBox(xxxObject): class xxxRadioBox(xxxObject): allParams = ['label', 'content', 'selection', 'dimension', 'pos', 'size', 'style'] - paramDict = {'dimension': ParamInt} + paramDict = {'dimension': ParamIntNN} required = ['label', 'content'] default = {'content': '[]'} - winStyles = ['wxRA_SPECIFY_ROWS', 'wxRA_SPECIFY_COLS'] + winStyles = ['wxRA_SPECIFY_ROWS', 'wxRA_SPECIFY_COLS', 'wxRA_HORIZONTAL', + 'wxRA_VERTICAL'] class xxxCheckBox(xxxObject): allParams = ['label', 'checked', 'pos', 'size', 'style'] @@ -599,16 +749,14 @@ class xxxListBox(xxxObject): required = ['content'] default = {'content': '[]'} winStyles = ['wxLB_SINGLE', 'wxLB_MULTIPLE', 'wxLB_EXTENDED', 'wxLB_HSCROLL', - 'wxLB_ALWAYS_SB', 'wxLB_NEEDED_SB', 'wxLB_SORT'] + 'wxLB_ALWAYS_SB', 'wxLB_NEEDED_SB', 'wxLB_SORT'] class xxxCheckList(xxxObject): allParams = ['content', 'pos', 'size', 'style'] required = ['content'] default = {'content': '[]'} - winStyles = ['wxLC_LIST', 'wxLC_REPORT', 'wxLC_ICON', 'wxLC_SMALL_ICON', - 'wxLC_ALIGN_TOP', 'wxLC_ALIGN_LEFT', 'wxLC_AUTOARRANGE', - 'wxLC_USER_TEXT', 'wxLC_EDIT_LABELS', 'wxLC_NO_HEADER', - 'wxLC_SINGLE_SEL', 'wxLC_SORT_ASCENDING', 'wxLC_SORT_DESCENDING'] + winStyles = ['wxLB_SINGLE', 'wxLB_MULTIPLE', 'wxLB_EXTENDED', 'wxLB_HSCROLL', + 'wxLB_ALWAYS_SB', 'wxLB_NEEDED_SB', 'wxLB_SORT'] paramDict = {'content': ParamContentCheckList} ################################################################################ @@ -618,6 +766,7 @@ class xxxSizer(xxxContainer): hasName = hasStyle = False paramDict = {'orient': ParamOrient} isSizer = True + itemTag = 'sizeritem' # different for some sizers class xxxBoxSizer(xxxSizer): allParams = ['orient'] @@ -639,6 +788,7 @@ class xxxGridSizer(xxxSizer): class xxxStdDialogButtonSizer(xxxSizer): allParams = [] + itemTag = 'button' # For repeated parameters class xxxParamMulti: @@ -658,59 +808,25 @@ class xxxParamMulti: class xxxFlexGridSizer(xxxGridSizer): specials = ['growablecols', 'growablerows'] allParams = ['cols', 'rows', 'vgap', 'hgap'] + specials - paramDict = {'growablecols':ParamIntList, 'growablerows':ParamIntList} - # Special processing for growable* parameters - # (they are represented by several nodes) - def special(self, tag, node): - if not self.params.has_key(tag): - # Create new multi-group - self.params[tag] = xxxParamMulti(node) - self.params[tag].append(xxxParamInt(node)) - def setSpecial(self, param, value): - # Straightforward implementation: remove, add again - self.params[param].remove() - del self.params[param] - for i in value: - node = g.tree.dom.createElement(param) - text = g.tree.dom.createTextNode(str(i)) - node.appendChild(text) - self.element.appendChild(node) - self.special(param, node) + paramDict = {'growablecols': ParamIntList, 'growablerows': ParamIntList} class xxxGridBagSizer(xxxSizer): specials = ['growablecols', 'growablerows'] allParams = ['vgap', 'hgap'] + specials - paramDict = {'growablecols':ParamIntList, 'growablerows':ParamIntList} - # Special processing for growable* parameters - # (they are represented by several nodes) - def special(self, tag, node): - if not self.params.has_key(tag): - # Create new multi-group - self.params[tag] = xxxParamMulti(node) - self.params[tag].append(xxxParamInt(node)) - def setSpecial(self, param, value): - # Straightforward implementation: remove, add again - self.params[param].remove() - del self.params[param] - for i in value: - node = g.tree.dom.createElement(param) - text = g.tree.dom.createTextNode(str(i)) - node.appendChild(text) - self.element.appendChild(node) - self.special(param, node) + paramDict = {'growablecols': ParamIntList, 'growablerows': ParamIntList} # Container with only one child. # Not shown in tree. class xxxChildContainer(xxxObject): hasName = hasStyle = False hasChild = True - def __init__(self, parent, element): - xxxObject.__init__(self, parent, element) + def __init__(self, parent, element, refElem=None): + xxxObject.__init__(self, parent, element, refElem) # Must have one child with 'object' tag, but we don't check it nodes = element.childNodes[:] # create copy for node in nodes: if node.nodeType == minidom.Node.ELEMENT_NODE: - if node.tagName == 'object': + if node.tagName in ['object', 'object_ref']: # Create new xxx object for child node self.child = MakeXXXFromDOM(self, node) self.child.parent = parent @@ -722,27 +838,49 @@ class xxxChildContainer(xxxObject): element.removeChild(node) node.unlink() assert 0, 'no child found' + def resetChild(self, xxx): + '''Reset child info (for replacing with another class).''' + self.child = xxx + self.hasChildren = xxx.hasChildren + self.isSizer = xxx.isSizer class xxxSizerItem(xxxChildContainer): allParams = ['option', 'flag', 'border', 'minsize', 'ratio'] paramDict = {'option': ParamInt, 'minsize': ParamPosSize, 'ratio': ParamPosSize} - #default = {'cellspan': '1,1'} - def __init__(self, parent, element): + defaults_panel = {} + defaults_control = {} + def __init__(self, parent, element, refElem=None): # For GridBag sizer items, extra parameters added if isinstance(parent, xxxGridBagSizer): self.allParams = self.allParams + ['cellpos', 'cellspan'] - xxxChildContainer.__init__(self, parent, element) + xxxChildContainer.__init__(self, parent, element, refElem) # Remove pos parameter - not needed for sizeritems if 'pos' in self.child.allParams: self.child.allParams = self.child.allParams[:] self.child.allParams.remove('pos') + def resetChild(self, xxx): + xxxChildContainer.resetChild(self, xxx) + # Remove pos parameter - not needed for sizeritems + if 'pos' in self.child.allParams: + self.child.allParams = self.child.allParams[:] + self.child.allParams.remove('pos') -class xxxNotebookPage(xxxChildContainer): +class xxxSizerItemButton(xxxSizerItem): + allParams = [] + paramDict = {} + def __init__(self, parent, element, refElem=None): + xxxChildContainer.__init__(self, parent, element, refElem=None) + # Remove pos parameter - not needed for sizeritems + if 'pos' in self.child.allParams: + self.child.allParams = self.child.allParams[:] + self.child.allParams.remove('pos') + +class xxxPage(xxxChildContainer): allParams = ['label', 'selected'] paramDict = {'selected': ParamBool} required = ['label'] - def __init__(self, parent, element): - xxxChildContainer.__init__(self, parent, element) + def __init__(self, parent, element, refElem=None): + xxxChildContainer.__init__(self, parent, element, refElem) # pos and size dont matter for notebookpages if 'pos' in self.child.allParams: self.child.allParams = self.child.allParams[:] @@ -756,6 +894,11 @@ class xxxSpacer(xxxObject): allParams = ['size', 'option', 'flag', 'border'] paramDict = {'option': ParamInt} default = {'size': '0,0'} + def __init__(self, parent, element, refElem=None): + # For GridBag sizer items, extra parameters added + if isinstance(parent, xxxGridBagSizer): + self.allParams = self.allParams + ['cellpos', 'cellspan'] + xxxObject.__init__(self, parent, element, refElem) class xxxMenuBar(xxxContainer): allParams = ['style'] @@ -782,16 +925,153 @@ class xxxSeparator(xxxObject): class xxxUnknown(xxxObject): allParams = ['pos', 'size', 'style'] - paramDict = {'style': ParamNonGenericStyle} # no generic styles + winStyles = ['wxNO_FULL_REPAINT_ON_RESIZE'] ################################################################################ +# Comment + +_handlers = [] # custom handler classes/funcs +def getHandlers(): + return _handlers +def setHandlers(handlers): + global _handlers + _handlers = handlers +_CFuncPtr = None # ctypes function type + +def register(hndlr): + """Register hndlr function or XmlResourceHandler class.""" + if _CFuncPtr and isinstance(hndlr, _CFuncPtr): + _handlers.append(hndlr) + return + if not isinstance(hndlr, type): + wx.LogError('handler is not a type: %s' % hndlr) + elif not issubclass(hndlr, wx.xrc.XmlResourceHandler): + wx.LogError('handler is not a XmlResourceHandler: %s' % hndlr) + else: + _handlers.append(hndlr) + +def load_dl(path, localname=''): + """Load shared/dynamic library into xxx namespace. + + If path is not absolute or relative, try to find in the module's directory. + """ + if not localname: + localname = os.path.basename(os.path.splitext(path)[0]) + try: + import ctypes + global _CFuncPtr + _CFuncPtr = ctypes._CFuncPtr # use as a flag of loaded ctypes + #if not os.path.dirname(path) and os.path.isfile(path): + + except ImportError: + wx.LogError('ctypes module not found') + globals()[localname] = None + return + try: + dl = ctypes.CDLL(path) + globals()[localname] = dl + # Register AddXmlHandlers() if exists + try: + register(dl.AddXmlHandlers) + except: + pass + except: + wx.LogError('error loading dynamic library: %s' % path) + print traceback.print_exc() + +# Called when creating test window +def addHandlers(): + for h in _handlers: + if _CFuncPtr and isinstance(h, _CFuncPtr): + try: + apply(h, ()) + except: + wx.LogError('error calling DL func: "%s"' % h) + print traceback.print_exc() + else: + try: + xrc.XmlResource.Get().AddHandler(apply(h, ())) + except: + wx.LogError('error adding XmlHandler: "%s"' % h) + print traceback.print_exc() + +def custom(klassName, klass='unknown'): + """Define custom control based on xrcClass. + + klass: new object name + xrcClass: name of an existing XRC object class or + a class object defining class parameters. + """ + if type(klass) is str: + # Copy correct xxx class under new name + kl = xxxDict[klass] + xxxClass = types.ClassType('xxx' + klassName, kl.__bases__, kl.__dict__) + else: + xxxClass = klass + # Register param IDs + for param in klass.allParams + klass.paramDict.keys(): + if not paramIDs.has_key(param): + paramIDs[param] = wx.NewId() + # Insert in dictionaty + xxxDict[klassName] = xxxClass + # Add to menu + g.pullDownMenu.addCustom(klassName) + +class xxxParamComment(xxxParam): + locals = {} # namespace for comment directives + allow = None # undefined initial state for current file + def __init__(self, node): + xxxNode.__init__(self, node) + self.textNode = node + # Parse "pragma" comments if enabled + if node.data and node.data[0] == '%' and g.conf.allowExec != 'no' and \ + xxxParamComment.allow is not False: + # Show warning + if g.conf.allowExec == 'ask' and xxxParamComment.allow is None: + flags = wx.ICON_EXCLAMATION | wx.YES_NO | wx.CENTRE + dlg = wx.MessageDialog(g.frame, ''' +This file contains executable %comment directives. Allow to execute?''', + 'Warning', flags) + say = dlg.ShowModal() + dlg.Destroy() + if say == wx.ID_YES: + xxxParamComment.allow = True + else: + xxxParamComment.allow = False + try: + code = node.data[1:] + exec code in globals(), self.locals + except: + wx.LogError('exec error: "%s"' % code) + print traceback.print_exc() +class xxxComment(xxxObject): + hasStyle = hasName = False + allParams = required = ['comment'] + + def __init__(self, parent, node): + self.parent = parent + self.node = node + self.isElement = False + self.undo = None + self.className = 'comment' + self.ref = self.subclass = None + self.params = {'comment': xxxParamComment(node)} + + def treeName(self): + # Replace newlines by \n to avoid tree item resizing + return self.params['comment'].value().replace('\n', r'\n') + +################################################################################ + +# Mapping of XRC names to xxx classes xxxDict = { 'wxPanel': xxxPanel, 'wxDialog': xxxDialog, 'wxFrame': xxxFrame, 'tool': xxxTool, 'wxToolBar': xxxToolBar, + 'wxStatusBar': xxxStatusBar, 'wxWizard': xxxWizard, 'wxWizardPage': xxxWizardPage, 'wxWizardPageSimple': xxxWizardPageSimple, @@ -822,14 +1102,21 @@ xxxDict = { 'wxTreeCtrl': xxxTreeCtrl, 'wxListCtrl': xxxListCtrl, 'wxCheckListBox': xxxCheckList, + 'notebookpage': xxxPage, + 'choicebookpage': xxxPage, + 'listbookpage': xxxPage, 'wxNotebook': xxxNotebook, + 'wxChoicebook': xxxChoicebook, + 'wxListbook': xxxListbook, 'wxSplitterWindow': xxxSplitterWindow, - 'notebookpage': xxxNotebookPage, 'wxHtmlWindow': xxxHtmlWindow, 'wxCalendarCtrl': xxxCalendarCtrl, 'wxGenericDirCtrl': xxxGenericDirCtrl, 'wxSpinCtrl': xxxSpinCtrl, 'wxScrolledWindow': xxxScrolledWindow, + 'wxGrid': xxxGrid, + 'wxFilePickerCtrl': xxxFilePickerCtrl, + 'wxDatePickerCtrl': xxxDateCtrl, 'wxBoxSizer': xxxBoxSizer, 'wxStaticBoxSizer': xxxStaticBoxSizer, @@ -837,7 +1124,7 @@ xxxDict = { 'wxFlexGridSizer': xxxFlexGridSizer, 'wxGridBagSizer': xxxGridBagSizer, 'wxStdDialogButtonSizer': xxxStdDialogButtonSizer, - 'sizeritem': xxxSizerItem, + 'sizeritem': xxxSizerItem, 'button': xxxSizerItemButton, 'spacer': xxxSpacer, 'wxMenuBar': xxxMenuBar, @@ -846,36 +1133,50 @@ xxxDict = { 'separator': xxxSeparator, 'unknown': xxxUnknown, + 'comment': xxxComment, } # Create IDs for all parameters of all classes -paramIDs = {'fg': wxNewId(), 'bg': wxNewId(), 'exstyle': wxNewId(), 'font': wxNewId(), - 'enabled': wxNewId(), 'focused': wxNewId(), 'hidden': wxNewId(), - 'tooltip': wxNewId(), 'encoding': wxNewId(), - 'cellpos': wxNewId(), 'cellspan': wxNewId() +paramIDs = {'fg': wx.NewId(), 'bg': wx.NewId(), 'exstyle': wx.NewId(), 'font': wx.NewId(), + 'enabled': wx.NewId(), 'focused': wx.NewId(), 'hidden': wx.NewId(), + 'tooltip': wx.NewId(), 'encoding': wx.NewId(), + 'cellpos': wx.NewId(), 'cellspan': wx.NewId(), + 'text': wx.NewId() } for cl in xxxDict.values(): if cl.allParams: for param in cl.allParams + cl.paramDict.keys(): if not paramIDs.has_key(param): - paramIDs[param] = wxNewId() + paramIDs[param] = wx.NewId() ################################################################################ # Helper functions # Test for object elements def IsObject(node): - return node.nodeType == minidom.Node.ELEMENT_NODE and node.tagName == 'object' + return node.nodeType == minidom.Node.ELEMENT_NODE and \ + node.tagName in ['object', 'object_ref'] or \ + node.nodeType == minidom.Node.COMMENT_NODE # Make XXX object from some DOM object, selecting correct class -def MakeXXXFromDOM(parent, element): +def MakeXXXFromDOM(parent, node): + if node.nodeType == minidom.Node.COMMENT_NODE: + return xxxComment(parent, node) + if node.tagName == 'object_ref': + ref = node.getAttribute('ref') + refElem = FindResource(ref) + if refElem: cls = refElem.getAttribute('class') + else: return xxxUnknown(parent, node) + else: + refElem = None + cls = node.getAttribute('class') try: - klass = xxxDict[element.getAttribute('class')] + klass = xxxDict[cls] except KeyError: # If we encounter a weird class, use unknown template - print 'WARNING: unsupported class:', element.getAttribute('class') + print 'WARNING: unsupported class:', node.getAttribute('class') klass = xxxUnknown - return klass(parent, element) + return klass(parent, node, refElem) # Make empty DOM element def MakeEmptyDOM(className): @@ -899,16 +1200,81 @@ def MakeEmptyDOM(className): def MakeEmptyXXX(parent, className): # Make corresponding DOM object first elem = MakeEmptyDOM(className) - # If parent is a sizer, we should create sizeritem object, except for spacers + # Special handling, e.g. if parent is a sizer, we should create + # sizeritem object, except for spacers, etc. if parent: if parent.isSizer and className != 'spacer': - sizerItemElem = MakeEmptyDOM('sizeritem') + sizerItemElem = MakeEmptyDOM(parent.itemTag) + sizerItemElem.appendChild(elem) + elem = sizerItemElem + elif isinstance(parent, xxxNotebook): + pageElem = MakeEmptyDOM('notebookpage') + pageElem.appendChild(elem) + elem = pageElem + elif isinstance(parent, xxxChoicebook): + pageElem = MakeEmptyDOM('choicebookpage') + pageElem.appendChild(elem) + elem = pageElem + elif isinstance(parent, xxxListbook): + pageElem = MakeEmptyDOM('listbookpage') + pageElem.appendChild(elem) + elem = pageElem + # Now just make object + xxx = MakeXXXFromDOM(parent, elem) + # Special defaults for new panels and controls + if isinstance(xxx, xxxSizerItem): + if isinstance(xxx.child, xxxContainer) and not xxx.child.isSizer: + for param,v in xxxSizerItem.defaults_panel.items(): + xxx.set(param, v) + elif isinstance(xxx.child, xxxObject): + for param,v in xxxSizerItem.defaults_control.items(): + xxx.set(param, v) + return xxx + +# Make empty DOM element for reference +def MakeEmptyRefDOM(ref): + elem = g.tree.dom.createElement('object_ref') + elem.setAttribute('ref', ref) + return elem + +# Make empty XXX object +def MakeEmptyRefXXX(parent, ref): + # Make corresponding DOM object first + elem = MakeEmptyRefDOM(ref) + # If parent is a sizer, we should create sizeritem object, except for spacers + if parent: + if parent.isSizer: + sizerItemElem = MakeEmptyDOM(parent.itemTag) sizerItemElem.appendChild(elem) elem = sizerItemElem elif isinstance(parent, xxxNotebook): pageElem = MakeEmptyDOM('notebookpage') pageElem.appendChild(elem) elem = pageElem + elif isinstance(parent, xxxChoicebook): + pageElem = MakeEmptyDOM('choicebookpage') + pageElem.appendChild(elem) + elem = pageElem + elif isinstance(parent, xxxListbook): + pageElem = MakeEmptyDOM('listbookpage') + pageElem.appendChild(elem) + elem = pageElem + # Now just make object + xxx = MakeXXXFromDOM(parent, elem) + # Label is not used for references + xxx.allParams = xxx.allParams[:] + #xxx.allParams.remove('label') + return xxx + +# Make empty comment node +def MakeEmptyCommentDOM(): + node = g.tree.dom.createComment('') + return node + +# Make empty xxxComment +def MakeEmptyCommentXXX(parent): + node = MakeEmptyCommentDOM() # Now just make object - return MakeXXXFromDOM(parent, elem) + xxx = MakeXXXFromDOM(parent, node) + return xxx