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