75aa19469b
New feature added from a patch submitted on sourceforge by botg: moving of tree items. Bugs fixed: - ChecklistBox content editing; - Window styles more in sync with the docs; - Replacing items; - Reference property page created correctly (every property is optional). git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@44381 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.element
|
|
if xxx is self.xxx: # sizeritem or notebookpage - replace child
|
|
parent.replaceChild(self.xxx.child.element, xxx.child.element)
|
|
else:
|
|
parent.replaceChild(self.xxx.element, xxx.element)
|
|
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.element) # detach child
|
|
elem.unlink() # delete child container
|
|
elem = xxx.child.element # 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.element) # detach child
|
|
elem.unlink() # delete child container
|
|
elem = xxx.child.element # 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())
|