Support for object_ref. CreateTestWin saves all DOM in temporary
memory file now, to allow reference resolution.

Tree changed to multiple selection (not really supported yet), so
after deleting Unselect can be used (otherwise parent item is
selected automatically which results in scrolling jumps - distracting).

!!! Not tested on wxMSW yet.


git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@35165 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
This commit is contained in:
Roman Rolinsky
2005-08-09 19:27:27 +00:00
parent 6cb85701e2
commit 03319b655c
5 changed files with 123 additions and 46 deletions

View File

@@ -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
-------

View File

@@ -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:

View File

@@ -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()

View File

@@ -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()

View File

@@ -208,11 +208,23 @@ 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
# 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')
@@ -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)