]>
Commit | Line | Data |
---|---|---|
d14a1e28 RD |
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$ | |
1fded56b | 6 | |
d14a1e28 | 7 | from globals import * |
baba4aa5 | 8 | from xxx import MakeXXXFromDOM |
75aa1946 | 9 | from tree import * |
d14a1e28 | 10 | #from panel import * |
1fded56b | 11 | |
d14a1e28 RD |
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) | |
03319b65 | 25 | g.frame.SetModified() |
d14a1e28 RD |
26 | g.frame.SetStatusText('Undone') |
27 | def Redo(self): | |
28 | undoObj = self.redo.pop() | |
29 | undoObj.redo() | |
30 | self.undo.append(undoObj) | |
03319b65 | 31 | g.frame.SetModified() |
d14a1e28 RD |
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) | |
83173c7a | 79 | g.tree.UnselectAll() |
d14a1e28 RD |
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 | ||
baba4aa5 RR |
124 | class UndoReplace: |
125 | def __init__(self, item): | |
126 | self.itemIndex = g.tree.ItemFullIndex(item) | |
75aa1946 RR |
127 | #self.xxx = g.tree.GetPyData(item) |
128 | self.elem = None | |
baba4aa5 | 129 | def destroy(self): |
75aa1946 | 130 | if self.elem: self.elem.unlink() |
baba4aa5 RR |
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 | |
b372319f | 137 | parent = xxx.parent.node |
306b6fe9 | 138 | if xxx is self.xxx: # sizeritem or notebookpage - replace child |
b372319f | 139 | parent.replaceChild(self.xxx.child.node, xxx.child.node) |
baba4aa5 | 140 | else: |
b372319f | 141 | parent.replaceChild(self.xxx.node, xxx.node) |
baba4aa5 RR |
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 | ||
75aa1946 RR |
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))): | |
b372319f | 194 | elem.removeChild(xxx.child.node) # detach child |
75aa1946 | 195 | elem.unlink() # delete child container |
b372319f | 196 | elem = xxx.child.node # replace |
75aa1946 RR |
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 | g.tree.SelectItem(selected) | |
214 | def redo(self): | |
215 | item = g.tree.GetFirstChild(self.oldParent)[0] | |
216 | for i in range(self.oldIndex): item = g.tree.GetNextSibling(item) | |
217 | elem = g.tree.RemoveLeaf(item) | |
218 | ||
219 | parent = g.tree.GetPyData(self.newParent).treeObject() | |
220 | ||
221 | # Check parent and child relationships. | |
222 | # If parent is sizer or notebook, child is of wrong class or | |
223 | # parent is normal window, child is child container then detach child. | |
224 | xxx = MakeXXXFromDOM(parent, elem) | |
225 | isChildContainer = isinstance(xxx, xxxChildContainer) | |
226 | if isChildContainer and \ | |
227 | ((parent.isSizer and not isinstance(xxx, xxxSizerItem)) or \ | |
228 | (isinstance(parent, xxxNotebook) and not isinstance(xxx, xxxNotebookPage)) or \ | |
229 | not (parent.isSizer or isinstance(parent, xxxNotebook))): | |
b372319f | 230 | elem.removeChild(xxx.child.node) # detach child |
75aa1946 | 231 | elem.unlink() # delete child container |
b372319f | 232 | elem = xxx.child.node # replace |
75aa1946 RR |
233 | # This may help garbage collection |
234 | xxx.child.parent = None | |
235 | isChildContainer = False | |
236 | # Parent is sizer or notebook, child is not child container | |
237 | if parent.isSizer and not isChildContainer and not isinstance(xxx, xxxSpacer): | |
238 | # Create sizer item element | |
239 | sizerItemElem = MakeEmptyDOM('sizeritem') | |
240 | sizerItemElem.appendChild(elem) | |
241 | elem = sizerItemElem | |
242 | elif isinstance(parent, xxxNotebook) and not isChildContainer: | |
243 | pageElem = MakeEmptyDOM('notebookpage') | |
244 | pageElem.appendChild(elem) | |
245 | elem = pageElem | |
246 | ||
247 | nextItem = g.tree.GetFirstChild(self.newParent)[0] | |
248 | for i in range(self.newIndex): nextItem = g.tree.GetNextSibling(nextItem) | |
249 | selected = g.tree.InsertNode(self.newParent, parent, elem, nextItem) | |
250 | g.tree.EnsureVisible(selected) | |
251 | g.tree.SelectItem(selected) | |
252 | ||
d14a1e28 RD |
253 | class UndoEdit: |
254 | def __init__(self): | |
255 | self.pages = map(ParamPage.GetState, g.panel.pages) | |
256 | self.selectedIndex = g.tree.ItemFullIndex(g.tree.GetSelection()) | |
257 | def destroy(self): | |
258 | pass | |
259 | # Update test view | |
260 | def update(self, selected): | |
261 | g.tree.Apply(g.tree.GetPyData(selected), selected) | |
262 | # Update view | |
263 | if g.testWin: | |
264 | if g.testWin.highLight: | |
265 | g.testWin.highLight.Remove() | |
266 | g.tree.pendingHighLight = selected | |
267 | if g.testWin: | |
268 | g.tree.needUpdate = True | |
269 | def undo(self): | |
270 | # Restore selection | |
271 | selected = g.tree.ItemAtFullIndex(self.selectedIndex) | |
272 | if selected != g.tree.GetSelection(): | |
273 | g.tree.SelectItem(selected) | |
274 | # Save current state for redo | |
275 | map(ParamPage.SaveState, g.panel.pages) | |
276 | pages = map(ParamPage.GetState, g.panel.pages) | |
277 | map(ParamPage.SetState, g.panel.pages, self.pages) | |
278 | self.pages = pages | |
279 | self.update(selected) | |
280 | def redo(self): | |
281 | self.undo() | |
282 | self.update(g.tree.GetSelection()) |