are not Elements) had to add xxxObject.isElement flag and changed xxxObject.element variable to xxxObject.node (xxxComment is derived from xxxObject to minimize changes in processing). More testing is still needed to verify that things didn't break. Use previous commit (0.1.8-4 release on 2007/03/10) if you need a stable version. git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@44764 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
283 lines
11 KiB
Python
283 lines
11 KiB
Python
# Name: undo.py
|
|
# Purpose: XRC editor, undo/redo module
|
|
# Author: Roman Rolinsky <rolinsky@mema.ucl.ac.be>
|
|
# Created: 01.12.2002
|
|
# RCS-ID: $Id$
|
|
|
|
from globals import *
|
|
from xxx import MakeXXXFromDOM
|
|
from tree import *
|
|
#from panel import *
|
|
|
|
# Undo/redo classes
|
|
class UndoManager:
|
|
# Undo/redo stacks
|
|
undo = []
|
|
redo = []
|
|
def RegisterUndo(self, undoObj):
|
|
self.undo.append(undoObj)
|
|
for i in self.redo: i.destroy()
|
|
self.redo = []
|
|
def Undo(self):
|
|
undoObj = self.undo.pop()
|
|
undoObj.undo()
|
|
self.redo.append(undoObj)
|
|
g.frame.SetModified()
|
|
g.frame.SetStatusText('Undone')
|
|
def Redo(self):
|
|
undoObj = self.redo.pop()
|
|
undoObj.redo()
|
|
self.undo.append(undoObj)
|
|
g.frame.SetModified()
|
|
g.frame.SetStatusText('Redone')
|
|
def Clear(self):
|
|
for i in self.undo: i.destroy()
|
|
self.undo = []
|
|
for i in self.redo: i.destroy()
|
|
self.redo = []
|
|
def CanUndo(self):
|
|
return not not self.undo
|
|
def CanRedo(self):
|
|
return not not self.redo
|
|
|
|
class UndoCutDelete:
|
|
def __init__(self, itemIndex, parent, elem):
|
|
self.itemIndex = itemIndex
|
|
self.parent = parent
|
|
self.elem = elem
|
|
def destroy(self):
|
|
if self.elem: self.elem.unlink()
|
|
def undo(self):
|
|
item = g.tree.InsertNode(g.tree.ItemAtFullIndex(self.itemIndex[:-1]),
|
|
self.parent, self.elem,
|
|
g.tree.ItemAtFullIndex(self.itemIndex))
|
|
# Scroll to show new item (!!! redundant?)
|
|
g.tree.EnsureVisible(item)
|
|
g.tree.SelectItem(item)
|
|
self.elem = None
|
|
# Update testWin if needed
|
|
if g.testWin and g.tree.IsHighlatable(item):
|
|
if g.conf.autoRefresh:
|
|
g.tree.needUpdate = True
|
|
g.tree.pendingHighLight = item
|
|
else:
|
|
g.tree.pendingHighLight = None
|
|
def redo(self):
|
|
item = g.tree.ItemAtFullIndex(self.itemIndex)
|
|
# Delete testWin?
|
|
if g.testWin:
|
|
# If deleting top-level item, delete testWin
|
|
if item == g.testWin.item:
|
|
g.testWin.Destroy()
|
|
g.testWin = None
|
|
else:
|
|
# Remove highlight, update testWin
|
|
if g.testWin.highLight:
|
|
g.testWin.highLight.Remove()
|
|
g.tree.needUpdate = True
|
|
self.elem = g.tree.RemoveLeaf(item)
|
|
g.tree.UnselectAll()
|
|
g.panel.Clear()
|
|
|
|
class UndoPasteCreate:
|
|
def __init__(self, itemParent, parent, item, selected):
|
|
self.itemParentIndex = g.tree.ItemFullIndex(itemParent)
|
|
self.parent = parent
|
|
self.itemIndex = g.tree.ItemFullIndex(item) # pasted item
|
|
self.selectedIndex = g.tree.ItemFullIndex(selected) # maybe different from item
|
|
self.elem = None
|
|
def destroy(self):
|
|
if self.elem: self.elem.unlink()
|
|
def undo(self):
|
|
self.elem = g.tree.RemoveLeaf(g.tree.ItemAtFullIndex(self.itemIndex))
|
|
# Restore old selection
|
|
selected = g.tree.ItemAtFullIndex(self.selectedIndex)
|
|
g.tree.EnsureVisible(selected)
|
|
g.tree.SelectItem(selected)
|
|
# Delete testWin?
|
|
if g.testWin:
|
|
# If deleting top-level item, delete testWin
|
|
if selected == g.testWin.item:
|
|
g.testWin.Destroy()
|
|
g.testWin = None
|
|
else:
|
|
# Remove highlight, update testWin
|
|
if g.testWin.highLight:
|
|
g.testWin.highLight.Remove()
|
|
g.tree.needUpdate = True
|
|
def redo(self):
|
|
item = g.tree.InsertNode(g.tree.ItemAtFullIndex(self.itemParentIndex),
|
|
self.parent, self.elem,
|
|
g.tree.ItemAtFullIndex(self.itemIndex))
|
|
# Scroll to show new item
|
|
g.tree.EnsureVisible(item)
|
|
g.tree.SelectItem(item)
|
|
self.elem = None
|
|
# Update testWin if needed
|
|
if g.testWin and g.tree.IsHighlatable(item):
|
|
if g.conf.autoRefresh:
|
|
g.tree.needUpdate = True
|
|
g.tree.pendingHighLight = item
|
|
else:
|
|
g.tree.pendingHighLight = None
|
|
|
|
class UndoReplace:
|
|
def __init__(self, item):
|
|
self.itemIndex = g.tree.ItemFullIndex(item)
|
|
#self.xxx = g.tree.GetPyData(item)
|
|
self.elem = None
|
|
def destroy(self):
|
|
if self.elem: self.elem.unlink()
|
|
def undo(self):
|
|
print 'Sorry, UndoReplace is not yet implemented.'
|
|
return
|
|
item = g.tree.ItemAtFullIndex(self.itemIndex)
|
|
xxx = g.tree.GetPyData(item)
|
|
# Replace with old element
|
|
parent = xxx.parent.node
|
|
if xxx is self.xxx: # sizeritem or notebookpage - replace child
|
|
parent.replaceChild(self.xxx.child.node, xxx.child.node)
|
|
else:
|
|
parent.replaceChild(self.xxx.node, xxx.node)
|
|
self.xxx.parent = xxx.parent
|
|
xxx = self.xxx
|
|
g.tree.SetPyData(item, xxx)
|
|
g.tree.SetItemText(item, xxx.treeName())
|
|
g.tree.SetItemImage(item, xxx.treeImage())
|
|
|
|
# Update panel
|
|
g.panel.SetData(xxx)
|
|
# Update tools
|
|
g.tools.UpdateUI()
|
|
g.tree.EnsureVisible(item)
|
|
g.tree.SelectItem(item)
|
|
# Delete testWin?
|
|
if g.testWin:
|
|
# If deleting top-level item, delete testWin
|
|
if selected == g.testWin.item:
|
|
g.testWin.Destroy()
|
|
g.testWin = None
|
|
else:
|
|
# Remove highlight, update testWin
|
|
if g.testWin.highLight:
|
|
g.testWin.highLight.Remove()
|
|
g.tree.needUpdate = True
|
|
def redo(self):
|
|
return
|
|
|
|
class UndoMove:
|
|
def __init__(self, oldParent, oldIndex, newParent, newIndex):
|
|
self.oldParent = oldParent
|
|
self.oldIndex = oldIndex
|
|
self.newParent = newParent
|
|
self.newIndex = newIndex
|
|
def destroy(self):
|
|
pass
|
|
def undo(self):
|
|
item = g.tree.GetFirstChild(self.newParent)[0]
|
|
for i in range(self.newIndex): item = g.tree.GetNextSibling(item)
|
|
elem = g.tree.RemoveLeaf(item)
|
|
nextItem = g.tree.GetFirstChild(self.oldParent)[0]
|
|
for i in range(self.oldIndex): nextItem = g.tree.GetNextSibling(nextItem)
|
|
|
|
parent = g.tree.GetPyData(self.oldParent).treeObject()
|
|
|
|
# Check parent and child relationships.
|
|
# If parent is sizer or notebook, child is of wrong class or
|
|
# parent is normal window, child is child container then detach child.
|
|
xxx = MakeXXXFromDOM(parent, elem)
|
|
isChildContainer = isinstance(xxx, xxxChildContainer)
|
|
if isChildContainer and \
|
|
((parent.isSizer and not isinstance(xxx, xxxSizerItem)) or \
|
|
(isinstance(parent, xxxNotebook) and not isinstance(xxx, xxxNotebookPage)) or \
|
|
not (parent.isSizer or isinstance(parent, xxxNotebook))):
|
|
elem.removeChild(xxx.child.node) # detach child
|
|
elem.unlink() # delete child container
|
|
elem = xxx.child.node # replace
|
|
# This may help garbage collection
|
|
xxx.child.parent = None
|
|
isChildContainer = False
|
|
# Parent is sizer or notebook, child is not child container
|
|
if parent.isSizer and not isChildContainer and not isinstance(xxx, xxxSpacer):
|
|
# Create sizer item element
|
|
sizerItemElem = MakeEmptyDOM('sizeritem')
|
|
sizerItemElem.appendChild(elem)
|
|
elem = sizerItemElem
|
|
elif isinstance(parent, xxxNotebook) and not isChildContainer:
|
|
pageElem = MakeEmptyDOM('notebookpage')
|
|
pageElem.appendChild(elem)
|
|
elem = pageElem
|
|
|
|
selected = g.tree.InsertNode(self.oldParent, parent, elem, nextItem)
|
|
g.tree.EnsureVisible(selected)
|
|
g.tree.SelectItem(selected)
|
|
def redo(self):
|
|
item = g.tree.GetFirstChild(self.oldParent)[0]
|
|
for i in range(self.oldIndex): item = g.tree.GetNextSibling(item)
|
|
elem = g.tree.RemoveLeaf(item)
|
|
|
|
parent = g.tree.GetPyData(self.newParent).treeObject()
|
|
|
|
# Check parent and child relationships.
|
|
# If parent is sizer or notebook, child is of wrong class or
|
|
# parent is normal window, child is child container then detach child.
|
|
xxx = MakeXXXFromDOM(parent, elem)
|
|
isChildContainer = isinstance(xxx, xxxChildContainer)
|
|
if isChildContainer and \
|
|
((parent.isSizer and not isinstance(xxx, xxxSizerItem)) or \
|
|
(isinstance(parent, xxxNotebook) and not isinstance(xxx, xxxNotebookPage)) or \
|
|
not (parent.isSizer or isinstance(parent, xxxNotebook))):
|
|
elem.removeChild(xxx.child.node) # detach child
|
|
elem.unlink() # delete child container
|
|
elem = xxx.child.node # replace
|
|
# This may help garbage collection
|
|
xxx.child.parent = None
|
|
isChildContainer = False
|
|
# Parent is sizer or notebook, child is not child container
|
|
if parent.isSizer and not isChildContainer and not isinstance(xxx, xxxSpacer):
|
|
# Create sizer item element
|
|
sizerItemElem = MakeEmptyDOM('sizeritem')
|
|
sizerItemElem.appendChild(elem)
|
|
elem = sizerItemElem
|
|
elif isinstance(parent, xxxNotebook) and not isChildContainer:
|
|
pageElem = MakeEmptyDOM('notebookpage')
|
|
pageElem.appendChild(elem)
|
|
elem = pageElem
|
|
|
|
nextItem = g.tree.GetFirstChild(self.newParent)[0]
|
|
for i in range(self.newIndex): nextItem = g.tree.GetNextSibling(nextItem)
|
|
selected = g.tree.InsertNode(self.newParent, parent, elem, nextItem)
|
|
g.tree.EnsureVisible(selected)
|
|
g.tree.SelectItem(selected)
|
|
|
|
class UndoEdit:
|
|
def __init__(self):
|
|
self.pages = map(ParamPage.GetState, g.panel.pages)
|
|
self.selectedIndex = g.tree.ItemFullIndex(g.tree.GetSelection())
|
|
def destroy(self):
|
|
pass
|
|
# Update test view
|
|
def update(self, selected):
|
|
g.tree.Apply(g.tree.GetPyData(selected), selected)
|
|
# Update view
|
|
if g.testWin:
|
|
if g.testWin.highLight:
|
|
g.testWin.highLight.Remove()
|
|
g.tree.pendingHighLight = selected
|
|
if g.testWin:
|
|
g.tree.needUpdate = True
|
|
def undo(self):
|
|
# Restore selection
|
|
selected = g.tree.ItemAtFullIndex(self.selectedIndex)
|
|
if selected != g.tree.GetSelection():
|
|
g.tree.SelectItem(selected)
|
|
# Save current state for redo
|
|
map(ParamPage.SaveState, g.panel.pages)
|
|
pages = map(ParamPage.GetState, g.panel.pages)
|
|
map(ParamPage.SetState, g.panel.pages, self.pages)
|
|
self.pages = pages
|
|
self.update(selected)
|
|
def redo(self):
|
|
self.undo()
|
|
self.update(g.tree.GetSelection())
|