# 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 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)
    def destroy(self):
        if self.xxx: self.xxx.element.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 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())
