]> git.saurik.com Git - wxWidgets.git/blob - wxPython/wx/tools/XRCed/undo.py
* bugfixes for tree move operations and undo/redo
[wxWidgets.git] / wxPython / wx / tools / XRCed / undo.py
1 # Name: undo.py
2 # Purpose: XRC editor, undo/redo module
3 # Author: Roman Rolinsky <rolinsky@mema.ucl.ac.be>
4 # Created: 01.12.2002
5 # RCS-ID: $Id$
6
7 from globals import *
8 from xxx import MakeXXXFromDOM
9 from tree import *
10 #from panel import *
11
12 # Undo/redo classes
13 class UndoManager:
14 # Undo/redo stacks
15 undo = []
16 redo = []
17 def RegisterUndo(self, undoObj):
18 self.undo.append(undoObj)
19 for i in self.redo: i.destroy()
20 self.redo = []
21 def Undo(self):
22 undoObj = self.undo.pop()
23 undoObj.undo()
24 self.redo.append(undoObj)
25 g.frame.SetModified()
26 g.frame.SetStatusText('Undone')
27 def Redo(self):
28 undoObj = self.redo.pop()
29 undoObj.redo()
30 self.undo.append(undoObj)
31 g.frame.SetModified()
32 g.frame.SetStatusText('Redone')
33 def Clear(self):
34 for i in self.undo: i.destroy()
35 self.undo = []
36 for i in self.redo: i.destroy()
37 self.redo = []
38 def CanUndo(self):
39 return not not self.undo
40 def CanRedo(self):
41 return not not self.redo
42
43 class UndoCutDelete:
44 def __init__(self, itemIndex, parent, elem):
45 self.itemIndex = itemIndex
46 self.parent = parent
47 self.elem = elem
48 def destroy(self):
49 if self.elem: self.elem.unlink()
50 def undo(self):
51 item = g.tree.InsertNode(g.tree.ItemAtFullIndex(self.itemIndex[:-1]),
52 self.parent, self.elem,
53 g.tree.ItemAtFullIndex(self.itemIndex))
54 # Scroll to show new item (!!! redundant?)
55 g.tree.EnsureVisible(item)
56 g.tree.SelectItem(item)
57 self.elem = None
58 # Update testWin if needed
59 if g.testWin and g.tree.IsHighlatable(item):
60 if g.conf.autoRefresh:
61 g.tree.needUpdate = True
62 g.tree.pendingHighLight = item
63 else:
64 g.tree.pendingHighLight = None
65 def redo(self):
66 item = g.tree.ItemAtFullIndex(self.itemIndex)
67 # Delete testWin?
68 if g.testWin:
69 # If deleting top-level item, delete testWin
70 if item == g.testWin.item:
71 g.testWin.Destroy()
72 g.testWin = None
73 else:
74 # Remove highlight, update testWin
75 if g.testWin.highLight:
76 g.testWin.highLight.Remove()
77 g.tree.needUpdate = True
78 self.elem = g.tree.RemoveLeaf(item)
79 g.tree.UnselectAll()
80 g.panel.Clear()
81
82 class UndoPasteCreate:
83 def __init__(self, itemParent, parent, item, selected):
84 self.itemParentIndex = g.tree.ItemFullIndex(itemParent)
85 self.parent = parent
86 self.itemIndex = g.tree.ItemFullIndex(item) # pasted item
87 self.selectedIndex = g.tree.ItemFullIndex(selected) # maybe different from item
88 self.elem = None
89 def destroy(self):
90 if self.elem: self.elem.unlink()
91 def undo(self):
92 self.elem = g.tree.RemoveLeaf(g.tree.ItemAtFullIndex(self.itemIndex))
93 # Restore old selection
94 selected = g.tree.ItemAtFullIndex(self.selectedIndex)
95 g.tree.EnsureVisible(selected)
96 g.tree.SelectItem(selected)
97 # Delete testWin?
98 if g.testWin:
99 # If deleting top-level item, delete testWin
100 if selected == g.testWin.item:
101 g.testWin.Destroy()
102 g.testWin = None
103 else:
104 # Remove highlight, update testWin
105 if g.testWin.highLight:
106 g.testWin.highLight.Remove()
107 g.tree.needUpdate = True
108 def redo(self):
109 item = g.tree.InsertNode(g.tree.ItemAtFullIndex(self.itemParentIndex),
110 self.parent, self.elem,
111 g.tree.ItemAtFullIndex(self.itemIndex))
112 # Scroll to show new item
113 g.tree.EnsureVisible(item)
114 g.tree.SelectItem(item)
115 self.elem = None
116 # Update testWin if needed
117 if g.testWin and g.tree.IsHighlatable(item):
118 if g.conf.autoRefresh:
119 g.tree.needUpdate = True
120 g.tree.pendingHighLight = item
121 else:
122 g.tree.pendingHighLight = None
123
124 class UndoReplace:
125 def __init__(self, item):
126 self.itemIndex = g.tree.ItemFullIndex(item)
127 #self.xxx = g.tree.GetPyData(item)
128 self.elem = None
129 def destroy(self):
130 if self.elem: self.elem.unlink()
131 def undo(self):
132 print 'Sorry, UndoReplace is not yet implemented.'
133 return
134 item = g.tree.ItemAtFullIndex(self.itemIndex)
135 xxx = g.tree.GetPyData(item)
136 # Replace with old element
137 parent = xxx.parent.node
138 if xxx is self.xxx: # sizeritem or notebookpage - replace child
139 parent.replaceChild(self.xxx.child.node, xxx.child.node)
140 else:
141 parent.replaceChild(self.xxx.node, xxx.node)
142 self.xxx.parent = xxx.parent
143 xxx = self.xxx
144 g.tree.SetPyData(item, xxx)
145 g.tree.SetItemText(item, xxx.treeName())
146 g.tree.SetItemImage(item, xxx.treeImage())
147
148 # Update panel
149 g.panel.SetData(xxx)
150 # Update tools
151 g.tools.UpdateUI()
152 g.tree.EnsureVisible(item)
153 g.tree.SelectItem(item)
154 # Delete testWin?
155 if g.testWin:
156 # If deleting top-level item, delete testWin
157 if selected == g.testWin.item:
158 g.testWin.Destroy()
159 g.testWin = None
160 else:
161 # Remove highlight, update testWin
162 if g.testWin.highLight:
163 g.testWin.highLight.Remove()
164 g.tree.needUpdate = True
165 def redo(self):
166 return
167
168 class UndoMove:
169 def __init__(self, oldParent, oldIndex, newParent, newIndex):
170 self.oldParent = oldParent
171 self.oldIndex = oldIndex
172 self.newParent = newParent
173 self.newIndex = newIndex
174 def destroy(self):
175 pass
176 def undo(self):
177 item = g.tree.GetFirstChild(self.newParent)[0]
178 for i in range(self.newIndex): item = g.tree.GetNextSibling(item)
179 elem = g.tree.RemoveLeaf(item)
180 nextItem = g.tree.GetFirstChild(self.oldParent)[0]
181 for i in range(self.oldIndex): nextItem = g.tree.GetNextSibling(nextItem)
182
183 parent = g.tree.GetPyData(self.oldParent).treeObject()
184
185 # Check parent and child relationships.
186 # If parent is sizer or notebook, child is of wrong class or
187 # parent is normal window, child is child container then detach child.
188 xxx = MakeXXXFromDOM(parent, elem)
189 isChildContainer = isinstance(xxx, xxxChildContainer)
190 if isChildContainer and \
191 ((parent.isSizer and not isinstance(xxx, xxxSizerItem)) or \
192 (isinstance(parent, xxxNotebook) and not isinstance(xxx, xxxNotebookPage)) or \
193 not (parent.isSizer or isinstance(parent, xxxNotebook))):
194 elem.removeChild(xxx.child.node) # detach child
195 elem.unlink() # delete child container
196 elem = xxx.child.node # replace
197 # This may help garbage collection
198 xxx.child.parent = None
199 isChildContainer = False
200 # Parent is sizer or notebook, child is not child container
201 if parent.isSizer and not isChildContainer and not isinstance(xxx, xxxSpacer):
202 # Create sizer item element
203 sizerItemElem = MakeEmptyDOM('sizeritem')
204 sizerItemElem.appendChild(elem)
205 elem = sizerItemElem
206 elif isinstance(parent, xxxNotebook) and not isChildContainer:
207 pageElem = MakeEmptyDOM('notebookpage')
208 pageElem.appendChild(elem)
209 elem = pageElem
210
211 selected = g.tree.InsertNode(self.oldParent, parent, elem, nextItem)
212 g.tree.EnsureVisible(selected)
213 # Highlight is outdated
214 if g.testWin and g.testWin.highLight:
215 g.testWin.highLight.Remove()
216 g.tree.needUpdate = True
217 g.tree.SelectItem(selected)
218 def redo(self):
219 item = g.tree.GetFirstChild(self.oldParent)[0]
220 for i in range(self.oldIndex): item = g.tree.GetNextSibling(item)
221 elem = g.tree.RemoveLeaf(item)
222
223 parent = g.tree.GetPyData(self.newParent).treeObject()
224
225 # Check parent and child relationships.
226 # If parent is sizer or notebook, child is of wrong class or
227 # parent is normal window, child is child container then detach child.
228 xxx = MakeXXXFromDOM(parent, elem)
229 isChildContainer = isinstance(xxx, xxxChildContainer)
230 if isChildContainer and \
231 ((parent.isSizer and not isinstance(xxx, xxxSizerItem)) or \
232 (isinstance(parent, xxxNotebook) and not isinstance(xxx, xxxNotebookPage)) or \
233 not (parent.isSizer or isinstance(parent, xxxNotebook))):
234 elem.removeChild(xxx.child.node) # detach child
235 elem.unlink() # delete child container
236 elem = xxx.child.node # replace
237 # This may help garbage collection
238 xxx.child.parent = None
239 isChildContainer = False
240 # Parent is sizer or notebook, child is not child container
241 if parent.isSizer and not isChildContainer and not isinstance(xxx, xxxSpacer):
242 # Create sizer item element
243 sizerItemElem = MakeEmptyDOM('sizeritem')
244 sizerItemElem.appendChild(elem)
245 elem = sizerItemElem
246 elif isinstance(parent, xxxNotebook) and not isChildContainer:
247 pageElem = MakeEmptyDOM('notebookpage')
248 pageElem.appendChild(elem)
249 elem = pageElem
250
251 nextItem = g.tree.GetFirstChild(self.newParent)[0]
252 for i in range(self.newIndex): nextItem = g.tree.GetNextSibling(nextItem)
253 selected = g.tree.InsertNode(self.newParent, parent, elem, nextItem)
254 g.tree.EnsureVisible(selected)
255 # Highlight is outdated
256 if g.testWin and g.testWin.highLight:
257 g.testWin.highLight.Remove()
258 g.tree.needUpdate = True
259 g.tree.SelectItem(selected)
260
261 class UndoEdit:
262 def __init__(self):
263 self.pages = map(ParamPage.GetState, g.panel.pages)
264 self.selectedIndex = g.tree.ItemFullIndex(g.tree.GetSelection())
265 def destroy(self):
266 pass
267 # Update test view
268 def update(self, selected):
269 g.tree.Apply(g.tree.GetPyData(selected), selected)
270 # Update view
271 if g.testWin:
272 if g.testWin.highLight:
273 g.testWin.highLight.Remove()
274 g.tree.pendingHighLight = selected
275 if g.testWin:
276 g.tree.needUpdate = True
277 def undo(self):
278 # Restore selection
279 selected = g.tree.ItemAtFullIndex(self.selectedIndex)
280 if selected != g.tree.GetSelection():
281 g.tree.SelectItem(selected)
282 # Save current state for redo
283 map(ParamPage.SaveState, g.panel.pages)
284 pages = map(ParamPage.GetState, g.panel.pages)
285 if self.pages:
286 map(ParamPage.SetState, g.panel.pages, self.pages)
287 self.pages = pages
288 self.update(selected)
289 def redo(self):
290 self.undo()
291 self.update(g.tree.GetSelection())