Mercurial > fife-parpg
comparison tools/editor/plugins/HistoryManager.py @ 378:64738befdf3b
bringing in the changes from the build_system_rework branch in preparation for the 0.3.0 release. This commit will require the Jan2010 devkit. Clients will also need to be modified to the new way to import fife.
author | vtchill@33b003aa-7bff-0310-803a-e67f0ece8222 |
---|---|
date | Mon, 11 Jan 2010 23:34:52 +0000 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
377:fe6fb0e0ed23 | 378:64738befdf3b |
---|---|
1 # -*- coding: utf-8 -*- | |
2 | |
3 # #################################################################### | |
4 # Copyright (C) 2005-2009 by the FIFE team | |
5 # http://www.fifengine.de | |
6 # This file is part of FIFE. | |
7 # | |
8 # FIFE is free software; you can redistribute it and/or | |
9 # modify it under the terms of the GNU Lesser General Public | |
10 # License as published by the Free Software Foundation; either | |
11 # version 2.1 of the License, or (at your option) any later version. | |
12 # | |
13 # This library is distributed in the hope that it will be useful, | |
14 # but WITHOUT ANY WARRANTY; without even the implied warranty of | |
15 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
16 # Lesser General Public License for more details. | |
17 # | |
18 # You should have received a copy of the GNU Lesser General Public | |
19 # License along with this library; if not, write to the | |
20 # Free Software Foundation, Inc., | |
21 # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | |
22 # #################################################################### | |
23 | |
24 from fife.extensions import pychan | |
25 from fife.extensions.pychan import widgets, tools, attrs, internal | |
26 import scripts | |
27 import scripts.plugin as plugin | |
28 from scripts.events import * | |
29 from scripts.gui.action import Action, ActionGroup | |
30 import fife | |
31 from fife.fife import Color | |
32 from scripts import undomanager | |
33 import scripts.gui | |
34 from scripts.gui.panel import Panel | |
35 import pdb | |
36 | |
37 class HistoryManager(plugin.Plugin): | |
38 def __init__(self): | |
39 self.editor = None | |
40 self.engine = None | |
41 | |
42 self._enabled = False | |
43 self.undomanager = None | |
44 | |
45 def enable(self): | |
46 if self._enabled is True: | |
47 return | |
48 | |
49 self.editor = scripts.editor.getEditor() | |
50 self.engine = self.editor.getEngine() | |
51 | |
52 self._show_action = Action(u"History manager", checkable=True) | |
53 self._undo_action = Action(u"Undo", "gui/icons/undo.png") | |
54 self._redo_action = Action(u"Redo", "gui/icons/redo.png") | |
55 self._next_action = Action(u"Next branch", "gui/icons/next_branch.png") | |
56 self._prev_action = Action(u"Previous branch", "gui/icons/previous_branch.png") | |
57 | |
58 self._show_action.helptext = u"Toggle HistoryManager" | |
59 self._undo_action.helptext = u"Undo action (CTRL+Z)" | |
60 self._redo_action.helptext = u"Redo action (CTRL+SHIFT+Z)" | |
61 self._next_action.helptext = u"Next branch (CTRL+ALT+Z" | |
62 self._prev_action.helptext = u"Previous branch (CTRL+ALT+SHIFT+Z)" | |
63 | |
64 scripts.gui.action.activated.connect(self.toggle, sender=self._show_action) | |
65 scripts.gui.action.activated.connect(self._undo, sender=self._undo_action) | |
66 scripts.gui.action.activated.connect(self._redo, sender=self._redo_action) | |
67 scripts.gui.action.activated.connect(self._next, sender=self._next_action) | |
68 scripts.gui.action.activated.connect(self._prev, sender=self._prev_action) | |
69 | |
70 self._undo_group = ActionGroup(name=u"UndoGroup") | |
71 self._undo_group.addAction(self._undo_action) | |
72 self._undo_group.addAction(self._redo_action) | |
73 self._undo_group.addAction(self._next_action) | |
74 self._undo_group.addAction(self._prev_action) | |
75 | |
76 self.editor._tools_menu.addAction(self._show_action) | |
77 self.editor._edit_menu.insertAction(self._undo_group, 0) | |
78 self.editor._edit_menu.insertSeparator(position=1) | |
79 | |
80 events.postMapShown.connect(self.update) | |
81 undomanager.changed.connect(self.update) | |
82 | |
83 self.buildGui() | |
84 | |
85 def disable(self): | |
86 if self._enabled is False: | |
87 return | |
88 | |
89 self.gui.hide() | |
90 self.removeAllChildren() | |
91 | |
92 events.postMapShown.disconnect(self.update) | |
93 undomanager.changed.disconnect(self.update) | |
94 | |
95 scripts.gui.action.activated.connect(self.toggle, sender=self._show_action) | |
96 scripts.gui.action.activated.disconnect(self._undo, sender=self._undo_action) | |
97 scripts.gui.action.activated.disconnect(self._redo, sender=self._redo_action) | |
98 scripts.gui.action.activated.disconnect(self._next, sender=self._next_action) | |
99 scripts.gui.action.activated.disconnect(self._prev, sender=self._prev_action) | |
100 | |
101 self.editor._tools_menu.removeAction(self._show_action) | |
102 self.editor._tools_menu.removeAction(self._undo_group) | |
103 | |
104 | |
105 def isEnabled(self): | |
106 return self._enabled; | |
107 | |
108 def getName(self): | |
109 return "History manager" | |
110 | |
111 | |
112 def buildGui(self): | |
113 self.gui = Panel(title=u"History") | |
114 self.scrollarea = widgets.ScrollArea(min_size=(200,300)) | |
115 self.list = widgets.ListBox() | |
116 self.list.capture(self._itemSelected) | |
117 | |
118 self.gui.addChild(self.scrollarea) | |
119 self.scrollarea.addChild(self.list) | |
120 | |
121 self.gui.position_technique = "right:center" | |
122 | |
123 def _linearUndo(self, target): | |
124 mapview = self.editor.getActiveMapView() | |
125 if mapview is None: | |
126 return | |
127 | |
128 undomanager = mapview.getController().getUndoManager() | |
129 current_item = undomanager.current_item | |
130 | |
131 # Redo? | |
132 item = current_item | |
133 count = 0 | |
134 while item is not None: | |
135 if item == target: | |
136 undomanager.redo(count) | |
137 break | |
138 count += 1 | |
139 item = item.next | |
140 | |
141 else: | |
142 # Undo? | |
143 count = 0 | |
144 item = current_item | |
145 while item is not None: | |
146 if item == target: | |
147 undomanager.undo(count) | |
148 break | |
149 count += 1 | |
150 item = item.previous | |
151 | |
152 else: | |
153 print "HistoryManager: Didn't find target item!" | |
154 | |
155 # Select the current item, important to see if the undo/redo didn't work as expected | |
156 self.update() | |
157 | |
158 | |
159 def _itemSelected(self): | |
160 mapview = self.editor.getActiveMapView() | |
161 if mapview is None: | |
162 return | |
163 | |
164 undomanager = mapview.getController().getUndoManager() | |
165 | |
166 stackitem = self.list.selected_item.item | |
167 if stackitem == undomanager.current_item: | |
168 return | |
169 | |
170 if undomanager.getBranchMode() is False: | |
171 self._linearUndo(stackitem) | |
172 return | |
173 | |
174 searchlist = [] | |
175 searchlist2 = [] | |
176 parent = stackitem | |
177 branch = parent.next | |
178 while parent is not None: | |
179 if parent is undomanager.first_item or len(parent._branches) > 1: | |
180 searchlist.append( (parent, branch) ) | |
181 branch = parent | |
182 parent = parent.parent | |
183 | |
184 current_item = undomanager.current_item | |
185 | |
186 parent = current_item | |
187 branch = parent.next | |
188 while parent is not None: | |
189 if parent is undomanager.first_item or len(parent._branches) > 1: | |
190 searchlist2.append( (parent, branch) ) | |
191 branch = parent | |
192 parent = parent.parent | |
193 | |
194 searchlist.reverse() | |
195 searchlist2.reverse() | |
196 | |
197 # Remove duplicate entries, except the last duplicate, so we don't undo | |
198 # more items than necessary | |
199 sl = len(searchlist); | |
200 if len(searchlist2) < sl: | |
201 sl = len(searchlist2) | |
202 for s in range(sl): | |
203 if searchlist[s][0] != searchlist[s][0]: | |
204 searchlist = searchlist[s-1:] | |
205 | |
206 s_item = searchlist[0][0] | |
207 | |
208 # Undo until we reach the first shared parent | |
209 i = 0 | |
210 item = current_item | |
211 while item is not None: | |
212 if item == s_item: | |
213 undomanager.undo(i) | |
214 current_item = item | |
215 break | |
216 i += 1 | |
217 item = item.previous | |
218 else: | |
219 print "Nada (undo)" | |
220 return | |
221 | |
222 # Switch branches | |
223 for s_item in searchlist: | |
224 if s_item[0].setBranch(s_item[1]) is False: | |
225 print "Warning: HistoryManager: Switching branch failed for: ", s_item | |
226 | |
227 # Redo to stackitem | |
228 item = current_item | |
229 i = 0 | |
230 while item is not None: | |
231 if item == stackitem: | |
232 undomanager.redo(i) | |
233 break | |
234 i += 1 | |
235 item = item.next | |
236 else: | |
237 print "Nada (redo)" | |
238 | |
239 # Select the current item, important to see if the undo/redo didn't work as expected | |
240 self.update() | |
241 | |
242 | |
243 def recursiveUpdate(self, item, indention, parent=None, branchstr="-"): | |
244 items = [] | |
245 | |
246 branchnr = 0 | |
247 | |
248 class _ListItem: | |
249 def __init__(self, str, item, parent): | |
250 self.str = str | |
251 self.item = item | |
252 self.parent = parent | |
253 | |
254 def __str__(self): | |
255 return self.str.encode("utf-8") | |
256 | |
257 while item is not None: | |
258 listitem = _ListItem(u" "*indention + branchstr + " " + item.object.name, item, parent) | |
259 items.append(listitem) | |
260 branchnr = -1 | |
261 | |
262 for branch in item.getBranches(): | |
263 branchnr += 1 | |
264 if branchnr == 0: | |
265 continue | |
266 | |
267 items.extend(self.recursiveUpdate(branch, indention+2, listitem, str(branchnr))) | |
268 | |
269 if self.undomanager.getBranchMode(): | |
270 if len(item._branches) > 0: | |
271 item = item._branches[0] | |
272 else: | |
273 break | |
274 else: item = item.next | |
275 | |
276 return items | |
277 | |
278 def update(self): | |
279 mapview = self.editor.getActiveMapView() | |
280 if mapview is None: | |
281 self.list.items = [] | |
282 return | |
283 | |
284 self.undomanager = undomanager = mapview.getController().getUndoManager() | |
285 items = [] | |
286 items = self.recursiveUpdate(undomanager.first_item, 0) | |
287 | |
288 self.list.items = items | |
289 i = 0 | |
290 for it in items: | |
291 if it.item == undomanager.current_item: | |
292 self.list.selected = i | |
293 break | |
294 i += 1 | |
295 self.scrollarea.adaptLayout(False) | |
296 | |
297 def show(self): | |
298 self.update() | |
299 self.gui.show() | |
300 self._show_action.setChecked(True) | |
301 | |
302 def hide(self): | |
303 self.gui.setDocked(False) | |
304 self.gui.hide() | |
305 self._show_action.setChecked(False) | |
306 | |
307 def _undo(self): | |
308 if self.undomanager: | |
309 self.undomanager.undo() | |
310 | |
311 def _redo(self): | |
312 if self.undomanager: | |
313 self.undomanager.redo() | |
314 | |
315 def _next(self): | |
316 if self.undomanager: | |
317 self.undomanager.nextBranch() | |
318 | |
319 def _prev(self): | |
320 if self.undomanager: | |
321 self.undomanager.previousBranch() | |
322 | |
323 def toggle(self): | |
324 if self.gui.isVisible() or self.gui.isDocked(): | |
325 self.hide() | |
326 else: | |
327 self.show() |