diff --git a/wxPython/wx/tools/XRCed/CHANGES.txt b/wxPython/wx/tools/XRCed/CHANGES.txt index a9db3b30e5..cb43de5ba8 100644 --- a/wxPython/wx/tools/XRCed/CHANGES.txt +++ b/wxPython/wx/tools/XRCed/CHANGES.txt @@ -1,3 +1,12 @@ +0.1.6-1 +------- + +New (experimental ;) ) feature: support for "object_ref" tag, for +creating references to named objects (see tn0014.txt). "reference..." +menu command creates new object_ref node. Properties of the top-level +object can be overriden, but overriding child controls is not working +as expected (maybe a bug in wx). + 0.1.5-3 ------- diff --git a/wxPython/wx/tools/XRCed/globals.py b/wxPython/wx/tools/XRCed/globals.py index 9d274483f3..cfcbc68dc3 100644 --- a/wxPython/wx/tools/XRCed/globals.py +++ b/wxPython/wx/tools/XRCed/globals.py @@ -15,7 +15,7 @@ import sys # Global constants progname = 'XRCed' -version = '0.1.5-3' +version = '0.1.6-1' # Can be changed to set other default encoding different #defaultEncoding = '' # you comment above and can uncomment this: diff --git a/wxPython/wx/tools/XRCed/tree.py b/wxPython/wx/tools/XRCed/tree.py index 0a4d4d0638..4c6817b535 100644 --- a/wxPython/wx/tools/XRCed/tree.py +++ b/wxPython/wx/tools/XRCed/tree.py @@ -117,6 +117,8 @@ class ID_NEW: HELP_BUTTON = wxNewId() CONTEXT_HELP_BUTTON = wxNewId() + REF = wxNewId() + LAST = wxNewId() @@ -403,7 +405,7 @@ class HighLightBox: class XML_Tree(wxTreeCtrl): def __init__(self, parent, id): - wxTreeCtrl.__init__(self, parent, id, style = wxTR_HAS_BUTTONS) + wxTreeCtrl.__init__(self, parent, id, style = wxTR_HAS_BUTTONS | wxTR_MULTIPLE) self.SetBackgroundColour(wxColour(224, 248, 224)) # Register events EVT_TREE_SEL_CHANGED(self, self.GetId(), self.OnSelChanged) @@ -449,11 +451,6 @@ class XML_Tree(wxTreeCtrl): EVT_ENTER_WINDOW(self, g.tools.OnMouse) EVT_LEAVE_WINDOW(self, g.tools.OnMouse) - def Unselect(self): - self.selection = None - wxTreeCtrl.Unselect(self) - g.tools.UpdateUI() - def ExpandAll(self, item): if self.ItemHasChildren(item): self.Expand(item) @@ -516,7 +513,7 @@ class XML_Tree(wxTreeCtrl): self.Unselect() # Add tree item for given parent item if node is DOM element node with - # 'object' tag. xxxParent is parent xxx object + # object/object_ref tag. xxxParent is parent xxx object def AddNode(self, itemParent, xxxParent, node): # Set item data to current node try: @@ -529,6 +526,9 @@ class XML_Tree(wxTreeCtrl): item = self.AppendItem(itemParent, treeObj.treeName(), image=treeObj.treeImage(), data=wxTreeItemData(xxx)) + # Different color for references + if treeObj.ref: + self.SetItemTextColour(item, 'DarkGreen') # Try to find children objects if treeObj.hasChildren: nodes = treeObj.element.childNodes[:] @@ -556,6 +556,8 @@ class XML_Tree(wxTreeCtrl): parent.element.appendChild(elem) newItem = self.AppendItem(itemParent, xxx.treeName(), image=xxx.treeImage(), data=wxTreeItemData(xxx)) + # Different color for references + if xxx.treeObject().ref: self.SetItemTextColour(newItem, 'DarkGreen') # Add children items if xxx.hasChildren: treeObj = xxx.treeObject() @@ -619,7 +621,7 @@ class XML_Tree(wxTreeCtrl): return parentWin.GetSizer() elif isinstance(xxx.parent, xxxToolBar): # How to get tool from toolbar? - return parentWin.GetChildren()[0] + return parentWin elif isinstance(xxx.parent, xxxStdDialogButtonSizer): # This sizer returns non-existing children for ch in parentWin.GetChildren(): @@ -784,13 +786,7 @@ class XML_Tree(wxTreeCtrl): pos = g.testWinPos # Save in memory FS memFile = MemoryFile('xxx.xrc') - # Create partial XML file - faster for big files - - dom = MyDocument() - mainNode = dom.createElement('resource') - dom.appendChild(mainNode) - - # Remove temporarily from old parent + # Create memory XML file elem = xxx.element # Change window id to _XRCED_T_W. This gives some name for # unnamed windows, and for named gives the possibility to @@ -806,14 +802,11 @@ class XML_Tree(wxTreeCtrl): elem.setAttribute('class', 'wxPanel') parent = elem.parentNode next = elem.nextSibling - parent.replaceChild(self.dummyNode, elem) - # Append to new DOM, write it - mainNode.appendChild(elem) - dom.writexml(memFile, encoding=self.rootObj.params['encoding'].value()) + encd = self.rootObj.params['encoding'].value() + if not encd: encd = None + self.dom.writexml(open('ttt.xrc','w'), encoding=encd) + self.dom.writexml(memFile, encoding=encd) # Put back in place - mainNode.removeChild(elem) - dom.unlink() - parent.replaceChild(elem, self.dummyNode) # Remove temporary name or restore changed if not xxx.name: elem.removeAttribute('name') @@ -998,6 +991,8 @@ class XML_Tree(wxTreeCtrl): needInsert = self.NeedInsert(item) if item == self.root or needInsert and self.GetItemParent(item) == self.root: SetMenu(m, pullDownMenu.topLevel) + m.AppendSeparator() + m.Append(ID_NEW.REF, 'reference...', 'Create object_ref node') else: xxx = self.GetPyData(item).treeObject() # Check parent for possible child nodes if inserting sibling @@ -1017,6 +1012,8 @@ class XML_Tree(wxTreeCtrl): m.Enable(m.FindItem('sizer'), False) elif not (xxx.isSizer or xxx.parent and xxx.parent.isSizer): m.Enable(ID_NEW.SPACER, False) + m.AppendSeparator() + m.Append(ID_NEW.REF, 'reference...', 'Create object_ref node') # Select correct label for create menu if not needInsert: if self.shift: @@ -1056,7 +1053,7 @@ class XML_Tree(wxTreeCtrl): menu.AppendMenu(id, 'Replace With', m) if not m.GetMenuItemCount(): menu.Enable(id, False) menu.Append(pullDownMenu.ID_SUBCLASS, 'Subclass...', - 'Set subclass property') + 'Set "subclass" property') menu.AppendSeparator() # Not using standart IDs because we don't want to show shortcuts menu.Append(wxID_CUT, 'Cut', 'Cut to the clipboard') @@ -1089,5 +1086,5 @@ class XML_Tree(wxTreeCtrl): if isinstance(xxx, xxxBoxSizer): self.SetItemImage(item, xxx.treeImage()) # Set global modified state - g.frame.modified = True + g.frame.SetModified() diff --git a/wxPython/wx/tools/XRCed/undo.py b/wxPython/wx/tools/XRCed/undo.py index ef9083cdc7..1f01d8d403 100644 --- a/wxPython/wx/tools/XRCed/undo.py +++ b/wxPython/wx/tools/XRCed/undo.py @@ -20,13 +20,13 @@ class UndoManager: undoObj = self.undo.pop() undoObj.undo() self.redo.append(undoObj) - g.frame.modified = True + g.frame.SetModified() g.frame.SetStatusText('Undone') def Redo(self): undoObj = self.redo.pop() undoObj.redo() self.undo.append(undoObj) - g.frame.modified = True + g.frame.SetModified() g.frame.SetStatusText('Redone') def Clear(self): for i in self.undo: i.destroy() diff --git a/wxPython/wx/tools/XRCed/xxx.py b/wxPython/wx/tools/XRCed/xxx.py index 4af295088d..62e7aaa8b8 100644 --- a/wxPython/wx/tools/XRCed/xxx.py +++ b/wxPython/wx/tools/XRCed/xxx.py @@ -208,12 +208,24 @@ 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.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) @@ -222,9 +234,9 @@ class xxxObject: for node in nodes: if node.nodeType == minidom.Node.ELEMENT_NODE: tag = node.tagName - if tag == 'object': + 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: @@ -292,8 +304,10 @@ 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 @@ -301,6 +315,32 @@ class xxxObject: obj.name = name obj.element.setAttribute('name', name) +# 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 + wxLogError('XRC resource "%s" not found!' % name) + + ################################################################################ # This is a little special: it is both xxxObject and xxxNode @@ -717,13 +757,13 @@ class xxxGridBagSizer(xxxSizer): 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 @@ -740,11 +780,11 @@ 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): + 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[:] @@ -753,8 +793,8 @@ class xxxSizerItem(xxxChildContainer): class xxxSizerItemButton(xxxSizerItem): allParams = [] paramDict = {} - def __init__(self, parent, element): - xxxChildContainer.__init__(self, parent, element) + 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[:] @@ -764,8 +804,8 @@ class xxxNotebookPage(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[:] @@ -888,17 +928,25 @@ for cl in xxxDict.values(): # 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'] # Make XXX object from some DOM object, selecting correct class def MakeXXXFromDOM(parent, element): + if element.tagName == 'object_ref': + ref = element.getAttribute('ref') + refElem = FindResource(ref) + if refElem: cls = refElem.getAttribute('class') + else: return xxxUnknown(parent, element) + else: + refElem = None + cls = element.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') klass = xxxUnknown - return klass(parent, element) + return klass(parent, element, refElem) # Make empty DOM element def MakeEmptyDOM(className): @@ -935,3 +983,26 @@ def MakeEmptyXXX(parent, className): # Now just make object return MakeXXXFromDOM(parent, elem) +# 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 + # Now just make object + return MakeXXXFromDOM(parent, elem) +