/usr/share/pyshared/labyrinth_lib/UndoManager.py is in labyrinth 0.6-0ubuntu3.
This file is owned by root:root, with mode 0o644.
The actual contents of the file can be viewed below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 | # UndoManager.py
# This file is part of Labyrinth
#
# Copyright (C) 2006 - Don Scorgie <Don@Scorgie.org>
#
# Labyrinth is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# Labyrinth is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Labyrinth; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor,
# Boston, MA 02110-1301 USA
#
# Different modes of operation - redo, undo
UNDO = 0
REDO = 1
# Some general actions we should always expect.
# Some require special handling within ourselves
# (taking care of letter insertion / word insertion)
INSERT_LETTER = 100
INSERT_WORD = 101
DELETE_LETTER = 102
DELETE_WORD = 103
TRANSFORM_CANVAS = 104
class UndoAction:
def __init__(self, owner, undo_type, callback, *args):
self.owner = owner
self.undo_type = undo_type
self.callback = callback
self.text = ""
if undo_type == INSERT_LETTER or undo_type == INSERT_WORD or undo_type == DELETE_LETTER or \
undo_type == DELETE_WORD:
for z in args:
if isinstance(z, basestring):
self.text = z
break
self.args = args
def add_arg (self, *args):
for t in args:
self.args += (t,)
class UndoManager:
''' A basic manager for undoing and redoing actions.\
Doesn't do anything itself, instead it marshals \
all the minion classes to do its bidding. Any class \
can add items to its lists and they're corresponding \
methods will be called if and when needed. The \
manager doesn't care what you give it, so long as
it has a method to call and an owner'''
def __init__(self, top_owner, undo_widget = None, redo_widget = None):
self.undo = undo_widget
self.redo = redo_widget
self.blocked = False
self.undo_list = []
self.redo_list = []
if self.undo:
self.undo.connect('activate', self.undo_action)
if self.redo:
self.redo.connect('activate', self.redo_action)
self.owner = top_owner
self.update_sensitive ()
def block (self):
''' Used as generally, when an undo is performed a \
signal will be emitted that causes an undo action \
to be added. Use this to block tht from happening \
To add actions again, call unblock'''
self.blocked = True
def unblock (self):
self.blocked = False
def set_widgets (self, undo, redo):
self.undo = undo
self.redo = redo
self.undo.connect('activate', self.undo_action)
self.redo.connect('activate', self.redo_action)
self.update_sensitive ()
def update_sensitive (self):
if not self.undo or not self.redo:
return
self.undo.set_sensitive(len(self.undo_list) > 0)
self.redo.set_sensitive(len(self.redo_list) > 0)
def undo_action (self, arg):
result = self.undo_list.pop()
self.redo_list.append (result)
self.update_sensitive ()
result.callback (result, mode=UNDO)
def redo_action (self, arg):
result = self.redo_list.pop()
self.undo_list.append (result)
self.update_sensitive ()
result.callback (result, mode=REDO)
def combine_insertions (self, action):
final_text = action.text
start_iter = action.args[0]
length = action.args[2]
owner = action.owner
cb = action.callback
old_attrs = action.args[3]
new_attrs = action.args[4]
if len (self.undo_list) > 0:
back = self.undo_list.pop ()
else:
self.undo_list.append (action)
return
add_back = True
while back and back.owner == owner \
and (back.undo_type == INSERT_LETTER or back.undo_type == INSERT_WORD):
if back.text.rfind(' ') != -1:
break
old_attrs = back.args[3]
if back.args[0] <= start_iter:
start_iter = back.args[0]
final_text = back.text+final_text
else:
final_text += back.text
length += back.args[2]
if len (self.undo_list) == 0:
add_back = False
break
back = self.undo_list.pop ()
if add_back:
self.undo_list.append (back)
combi = UndoAction (owner, INSERT_WORD, cb, start_iter, final_text, length, old_attrs, new_attrs)
self.undo_list.append (combi)
def combine_deletions (self, action):
bytes = True
byte_collection = action.args[3]
final_text = action.text
start_iter = action.args[0]
length = action.args[2]
owner = action.owner
cb = action.callback
old_attrs = action.args[4]
new_attrs = action.args[5]
if len (self.undo_list) > 0:
back = self.undo_list.pop ()
else:
self.undo_list.append (action)
return
add_back = True
while back and back.owner == owner \
and (back.undo_type == DELETE_LETTER or back.undo_type == DELETE_WORD):
if back.text.rfind(' ') != -1:
break
old_attrs = back.args[4]
if back.args[0] <= start_iter:
start_iter = back.args[0]
final_text = back.text+final_text
if bytes:
byte_collection = back.args[3] + byte_collection
else:
final_text += back.text
if bytes:
byte_collection += back.args[3]
length += back.args[2]
if len (self.undo_list) == 0:
add_back = False
break
back = self.undo_list.pop ()
if add_back:
self.undo_list.append (back)
if bytes:
combi = UndoAction (owner, DELETE_WORD, cb, start_iter, final_text, length, byte_collection, old_attrs, new_attrs)
else:
combi = UndoAction (owner, DELETE_WORD, cb, start_iter, final_text, length, -1, old_attrs, new_attrs)
self.undo_list.append (combi)
def combine_transforms (self, action):
if len (self.undo_list) > 0:
back = self.undo_list.pop ()
else:
self.undo_list.append (action)
return
add_back = True
final_zoom = action.args[1]
final_trans = action.args[3]
orig_zoom = action.args[0]
orig_trans = action.args[2]
owner = action.owner
cb = action.callback
while back and back.owner == owner and \
back.undo_type == TRANSFORM_CANVAS:
orig_zoom = back.args[0]
orig_trans = back.args[2]
if len (self.undo_list) == 0:
add_back = False
break
back = self.undo_list.pop ()
if add_back:
self.undo_list.append (back)
self.undo_list.append (UndoAction (owner, TRANSFORM_CANVAS, cb, orig_zoom,
final_zoom, orig_trans, final_trans))
def peak (self):
if len (self.undo_list) > 0:
return self.undo_list[-1]
else:
return UndoAction (None, None, None)
def pop (self):
if len (self.undo_list) > 0:
return self.undo_list.pop ()
else:
return None
def exists_undo_action (self):
return len(self.undo_list) > 0
def exists_redo_action (self):
return len(self.redo_list) > 0
def add_undo (self, action):
if self.blocked:
return
if not isinstance(action, UndoAction):
print "Error: Not a valid undo action. Ignoring."
return
del self.redo_list[:]
if action.undo_type == INSERT_LETTER:
self.combine_insertions (action)
elif action.undo_type == DELETE_LETTER:
self.combine_deletions (action)
elif action.undo_type == TRANSFORM_CANVAS:
self.combine_transforms (action)
else:
self.undo_list.append (action)
self.update_sensitive ()
|