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