Updates to undo/redo logic -- part 1

svn: r15277
This commit is contained in:
Gerald Britton 2010-04-23 19:02:24 +00:00
parent 71575f91ea
commit 72e19bb7a9
2 changed files with 52 additions and 27 deletions

View File

@ -29,6 +29,7 @@
#------------------------------------------------------------------------
import time
from gen.ggettext import gettext as _
from itertools import chain
#-------------------------------------------------------------------------
#
@ -110,29 +111,27 @@ class UndoHistory(ManagedWindow.ManagedWindow):
self.show()
def _selection_changed(self, obj):
assert self.undodb.undo_count == self.undodb.undoindex + 1
(model, node) = self.selection.get_selected()
if not node:
return
path = self.model.get_path(node)
start = min(path[0], self.undodb.undoindex+1)
end = max(path[0], self.undodb.undoindex+1)
start = min(path[0], self.undodb.undo_count)
end = max(path[0], self.undodb.undo_count)
self._paint_rows(0, len(self.model)-1, False)
self._paint_rows(start, end, True)
if path[0] < self.undodb.undoindex+1:
if path[0] < self.undodb.undo_count:
# This transaction is an undo candidate
self.redo_button.set_sensitive(False)
self.undo_button.set_sensitive(self.undodb.undo_available())
elif path[0] > self.undodb.undoindex+1:
else: # path[0] >= self.undodb.undo_count:
# This transaction is an redo candidate
self.undo_button.set_sensitive(False)
self.redo_button.set_sensitive(self.undodb.redo_available())
else: #path[0] == self.undodb.undoindex+1
self.undo_button.set_sensitive(self.undodb.undo_available())
self.redo_button.set_sensitive(self.undodb.redo_available())
def _paint_rows(self, start, end, selected=False):
if selected:
(fg, bg) = get_colors(self.tree, gtk.STATE_SELECTED)
@ -145,23 +144,26 @@ class UndoHistory(ManagedWindow.ManagedWindow):
self.model.set(the_iter, 3, bg)
def _response(self, obj, response_id):
assert self.undodb.undo_count == self.undodb.undoindex + 1
if response_id == gtk.RESPONSE_CLOSE:
self.close(obj)
elif response_id == gtk.RESPONSE_REJECT:
# Undo the selected entries
(model, node) = self.selection.get_selected()
if not node:
return
path = self.model.get_path(node)
nsteps = path[0]-self.undodb.undoindex-1
nsteps = path[0]-self.undodb.undo_count-1
self._move(nsteps or -1)
elif response_id == gtk.RESPONSE_ACCEPT:
# Redo the selected entries
(model, node) = self.selection.get_selected()
if not node:
return
path = self.model.get_path(node)
nsteps = path[0]-self.undodb.undoindex-1
nsteps = path[0]-self.undodb.undo_count
self._move(nsteps or 1)
elif response_id == gtk.RESPONSE_APPLY:
@ -181,7 +183,7 @@ class UndoHistory(ManagedWindow.ManagedWindow):
def clear(self):
self.undodb.clear()
self.undodb.abort_possible = False
self.db.abort_possible = False
self.update()
if self.db.undo_callback:
self.db.undo_callback(None)
@ -206,6 +208,7 @@ class UndoHistory(ManagedWindow.ManagedWindow):
)
def _build_model(self):
assert self.undodb.undoindex+1 == len(self.undodb.undoq)
self.model.clear()
fg = bg = None
@ -217,13 +220,12 @@ class UndoHistory(ManagedWindow.ManagedWindow):
time_text = time.ctime(self.undodb.undo_history_timestamp)
self.model.append(row=[time_text, mod_text, fg, bg])
# Get the not-None portion of transaction list
translist = filter(None, self.undodb.translist)
for transaction in translist:
time_text = time.ctime(transaction.timestamp)
mod_text = transaction.get_description()
# Add the undo and redo queues to the model
for txn in chain(self.undodb.undoq, reversed(self.undodb.redoq)):
time_text = time.ctime(txn.timestamp)
mod_text = txn.get_description()
self.model.append(row=[time_text, mod_text, fg, bg])
path = (self.undodb.undoindex+1,)
path = (self.undodb.undo_count,)
self.selection.select_path(path)
def update(self):

View File

@ -35,6 +35,7 @@ import time, os
import cPickle as pickle
from bsddb import db
from gen.ggettext import gettext as _
from collections import deque
#-------------------------------------------------------------------------
#
@ -53,8 +54,8 @@ import Errors
DBERRS = (db.DBRunRecoveryError, db.DBAccessError,
db.DBPageNotFoundError, db.DBInvalidArgError)
_SIGBASE = ('person', 'family', 'source', 'event', 'media',
'place', 'repository', 'reference', 'note')
_SIGBASE = ('person', 'family', 'source', 'event', 'media', 'place',
'repository', 'reference', 'note', 'undoq', 'redoq')
#-------------------------------------------------------------------------
#
# DbUndo class
@ -91,6 +92,8 @@ class DbUndo(object):
"""
Clear the undo/redo list (but not the backing storage)
"""
self.undoq = deque()
self.redoq = deque()
self.translist = []
self.undoindex = -1
self.undo_history_timestamp = time.time()
@ -161,6 +164,7 @@ class DbUndo(object):
txn.timestamp = time.time()
# If we're within our undo limit, add this transaction
self.undoq.append(txn)
self.undoindex += 1
if self.undoindex < DBUNDO:
if self.undoindex >= len(self.translist):
@ -168,17 +172,21 @@ class DbUndo(object):
else:
self.translist[self.undoindex] = txn
del self.translist[self.undoindex+1:]
self.redoq.clear()
# Otherwise, we've exceeded our undo limit
else:
self.db.abort_possible = False
self.undo_history_timestamp = time.time()
self.translist[-1] = txn
self.redoq.clear()
def undo_available(self):
"""
Return boolean of whether or not there's a possibility of undo.
"""
#print "Undo available:", bool(self.undoq)
return len(self.undoq)
if 0 <= self.undoindex < len(self.translist):
return True
return False
@ -187,6 +195,8 @@ class DbUndo(object):
"""
Return boolean of whether or not there's a possibility of redo.
"""
#print "Redo available:", bool(self.redoq)
return len(self.redoq)
if 0 <= self.undoindex+1 < len(self.translist):
return True
return False
@ -229,7 +239,11 @@ class DbUndo(object):
Access the last committed transaction, and revert the data to the
state before the transaction was committed.
"""
transaction = self.translist[self.undoindex]
txn = self.undoq.pop()
self.redoq.append(txn)
#transaction = self.translist[self.undoindex]
#assert transaction == txn
transaction = txn
db = self.db
self.undoindex -= 1
subitems = transaction.get_recnos(reverse=True)
@ -262,12 +276,15 @@ class DbUndo(object):
def __redo(self, db=None, update_history=True):
"""
Accesse the last undone transaction, and revert the data to the state
Access the last undone transaction, and revert the data to the state
before the transaction was undone.
"""
txn = self.redoq.pop()
self.undoq.append(txn)
self.undoindex += 1
transaction = self.translist[self.undoindex]
#transaction = self.translist[self.undoindex]
#assert transaction == txn
transaction = txn
db = self.db
subitems = transaction.get_recnos()
@ -287,8 +304,9 @@ class DbUndo(object):
% transaction.get_description())
if db.redo_callback:
if self.redo_available():
new_transaction = self.translist[self.undoindex+1]
if len(self.redoq) > 1:
#new_transaction = self.translist[self.undoindex+1]
new_transaction = self.redoq[-2]
db.redo_callback(_("_Redo %s")
% new_transaction.get_description())
else:
@ -333,6 +351,11 @@ class DbUndo(object):
self.db._log_error()
raise Errors.DbError(msg)
@property
def undo_count(self):
"""Number of undo requests in the queue"""
return len(self.undoq)
class DbUndoList(DbUndo):
"""
Implementation of the gramps undo database using a Python list