Updates to undo/redo logic -- part 1
svn: r15277
This commit is contained in:
parent
71575f91ea
commit
72e19bb7a9
@ -29,6 +29,7 @@
|
|||||||
#------------------------------------------------------------------------
|
#------------------------------------------------------------------------
|
||||||
import time
|
import time
|
||||||
from gen.ggettext import gettext as _
|
from gen.ggettext import gettext as _
|
||||||
|
from itertools import chain
|
||||||
|
|
||||||
#-------------------------------------------------------------------------
|
#-------------------------------------------------------------------------
|
||||||
#
|
#
|
||||||
@ -110,29 +111,27 @@ class UndoHistory(ManagedWindow.ManagedWindow):
|
|||||||
self.show()
|
self.show()
|
||||||
|
|
||||||
def _selection_changed(self, obj):
|
def _selection_changed(self, obj):
|
||||||
|
assert self.undodb.undo_count == self.undodb.undoindex + 1
|
||||||
(model, node) = self.selection.get_selected()
|
(model, node) = self.selection.get_selected()
|
||||||
if not node:
|
if not node:
|
||||||
return
|
return
|
||||||
path = self.model.get_path(node)
|
path = self.model.get_path(node)
|
||||||
|
start = min(path[0], self.undodb.undo_count)
|
||||||
start = min(path[0], self.undodb.undoindex+1)
|
end = max(path[0], self.undodb.undo_count)
|
||||||
end = max(path[0], self.undodb.undoindex+1)
|
|
||||||
|
|
||||||
self._paint_rows(0, len(self.model)-1, False)
|
self._paint_rows(0, len(self.model)-1, False)
|
||||||
self._paint_rows(start, end, True)
|
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.redo_button.set_sensitive(False)
|
||||||
self.undo_button.set_sensitive(self.undodb.undo_available())
|
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.undo_button.set_sensitive(False)
|
||||||
self.redo_button.set_sensitive(self.undodb.redo_available())
|
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):
|
def _paint_rows(self, start, end, selected=False):
|
||||||
if selected:
|
if selected:
|
||||||
(fg, bg) = get_colors(self.tree, gtk.STATE_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)
|
self.model.set(the_iter, 3, bg)
|
||||||
|
|
||||||
def _response(self, obj, response_id):
|
def _response(self, obj, response_id):
|
||||||
|
assert self.undodb.undo_count == self.undodb.undoindex + 1
|
||||||
if response_id == gtk.RESPONSE_CLOSE:
|
if response_id == gtk.RESPONSE_CLOSE:
|
||||||
self.close(obj)
|
self.close(obj)
|
||||||
|
|
||||||
elif response_id == gtk.RESPONSE_REJECT:
|
elif response_id == gtk.RESPONSE_REJECT:
|
||||||
|
# Undo the selected entries
|
||||||
(model, node) = self.selection.get_selected()
|
(model, node) = self.selection.get_selected()
|
||||||
if not node:
|
if not node:
|
||||||
return
|
return
|
||||||
path = self.model.get_path(node)
|
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)
|
self._move(nsteps or -1)
|
||||||
|
|
||||||
elif response_id == gtk.RESPONSE_ACCEPT:
|
elif response_id == gtk.RESPONSE_ACCEPT:
|
||||||
|
# Redo the selected entries
|
||||||
(model, node) = self.selection.get_selected()
|
(model, node) = self.selection.get_selected()
|
||||||
if not node:
|
if not node:
|
||||||
return
|
return
|
||||||
path = self.model.get_path(node)
|
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)
|
self._move(nsteps or 1)
|
||||||
|
|
||||||
elif response_id == gtk.RESPONSE_APPLY:
|
elif response_id == gtk.RESPONSE_APPLY:
|
||||||
@ -181,7 +183,7 @@ class UndoHistory(ManagedWindow.ManagedWindow):
|
|||||||
|
|
||||||
def clear(self):
|
def clear(self):
|
||||||
self.undodb.clear()
|
self.undodb.clear()
|
||||||
self.undodb.abort_possible = False
|
self.db.abort_possible = False
|
||||||
self.update()
|
self.update()
|
||||||
if self.db.undo_callback:
|
if self.db.undo_callback:
|
||||||
self.db.undo_callback(None)
|
self.db.undo_callback(None)
|
||||||
@ -206,6 +208,7 @@ class UndoHistory(ManagedWindow.ManagedWindow):
|
|||||||
)
|
)
|
||||||
|
|
||||||
def _build_model(self):
|
def _build_model(self):
|
||||||
|
assert self.undodb.undoindex+1 == len(self.undodb.undoq)
|
||||||
self.model.clear()
|
self.model.clear()
|
||||||
fg = bg = None
|
fg = bg = None
|
||||||
|
|
||||||
@ -217,13 +220,12 @@ class UndoHistory(ManagedWindow.ManagedWindow):
|
|||||||
time_text = time.ctime(self.undodb.undo_history_timestamp)
|
time_text = time.ctime(self.undodb.undo_history_timestamp)
|
||||||
self.model.append(row=[time_text, mod_text, fg, bg])
|
self.model.append(row=[time_text, mod_text, fg, bg])
|
||||||
|
|
||||||
# Get the not-None portion of transaction list
|
# Add the undo and redo queues to the model
|
||||||
translist = filter(None, self.undodb.translist)
|
for txn in chain(self.undodb.undoq, reversed(self.undodb.redoq)):
|
||||||
for transaction in translist:
|
time_text = time.ctime(txn.timestamp)
|
||||||
time_text = time.ctime(transaction.timestamp)
|
mod_text = txn.get_description()
|
||||||
mod_text = transaction.get_description()
|
|
||||||
self.model.append(row=[time_text, mod_text, fg, bg])
|
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)
|
self.selection.select_path(path)
|
||||||
|
|
||||||
def update(self):
|
def update(self):
|
||||||
|
@ -35,6 +35,7 @@ import time, os
|
|||||||
import cPickle as pickle
|
import cPickle as pickle
|
||||||
from bsddb import db
|
from bsddb import db
|
||||||
from gen.ggettext import gettext as _
|
from gen.ggettext import gettext as _
|
||||||
|
from collections import deque
|
||||||
|
|
||||||
#-------------------------------------------------------------------------
|
#-------------------------------------------------------------------------
|
||||||
#
|
#
|
||||||
@ -53,8 +54,8 @@ import Errors
|
|||||||
DBERRS = (db.DBRunRecoveryError, db.DBAccessError,
|
DBERRS = (db.DBRunRecoveryError, db.DBAccessError,
|
||||||
db.DBPageNotFoundError, db.DBInvalidArgError)
|
db.DBPageNotFoundError, db.DBInvalidArgError)
|
||||||
|
|
||||||
_SIGBASE = ('person', 'family', 'source', 'event', 'media',
|
_SIGBASE = ('person', 'family', 'source', 'event', 'media', 'place',
|
||||||
'place', 'repository', 'reference', 'note')
|
'repository', 'reference', 'note', 'undoq', 'redoq')
|
||||||
#-------------------------------------------------------------------------
|
#-------------------------------------------------------------------------
|
||||||
#
|
#
|
||||||
# DbUndo class
|
# DbUndo class
|
||||||
@ -91,6 +92,8 @@ class DbUndo(object):
|
|||||||
"""
|
"""
|
||||||
Clear the undo/redo list (but not the backing storage)
|
Clear the undo/redo list (but not the backing storage)
|
||||||
"""
|
"""
|
||||||
|
self.undoq = deque()
|
||||||
|
self.redoq = deque()
|
||||||
self.translist = []
|
self.translist = []
|
||||||
self.undoindex = -1
|
self.undoindex = -1
|
||||||
self.undo_history_timestamp = time.time()
|
self.undo_history_timestamp = time.time()
|
||||||
@ -161,6 +164,7 @@ class DbUndo(object):
|
|||||||
txn.timestamp = time.time()
|
txn.timestamp = time.time()
|
||||||
|
|
||||||
# If we're within our undo limit, add this transaction
|
# If we're within our undo limit, add this transaction
|
||||||
|
self.undoq.append(txn)
|
||||||
self.undoindex += 1
|
self.undoindex += 1
|
||||||
if self.undoindex < DBUNDO:
|
if self.undoindex < DBUNDO:
|
||||||
if self.undoindex >= len(self.translist):
|
if self.undoindex >= len(self.translist):
|
||||||
@ -168,17 +172,21 @@ class DbUndo(object):
|
|||||||
else:
|
else:
|
||||||
self.translist[self.undoindex] = txn
|
self.translist[self.undoindex] = txn
|
||||||
del self.translist[self.undoindex+1:]
|
del self.translist[self.undoindex+1:]
|
||||||
|
self.redoq.clear()
|
||||||
|
|
||||||
# Otherwise, we've exceeded our undo limit
|
# Otherwise, we've exceeded our undo limit
|
||||||
else:
|
else:
|
||||||
self.db.abort_possible = False
|
self.db.abort_possible = False
|
||||||
self.undo_history_timestamp = time.time()
|
self.undo_history_timestamp = time.time()
|
||||||
self.translist[-1] = txn
|
self.translist[-1] = txn
|
||||||
|
self.redoq.clear()
|
||||||
|
|
||||||
def undo_available(self):
|
def undo_available(self):
|
||||||
"""
|
"""
|
||||||
Return boolean of whether or not there's a possibility of undo.
|
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):
|
if 0 <= self.undoindex < len(self.translist):
|
||||||
return True
|
return True
|
||||||
return False
|
return False
|
||||||
@ -187,6 +195,8 @@ class DbUndo(object):
|
|||||||
"""
|
"""
|
||||||
Return boolean of whether or not there's a possibility of redo.
|
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):
|
if 0 <= self.undoindex+1 < len(self.translist):
|
||||||
return True
|
return True
|
||||||
return False
|
return False
|
||||||
@ -229,7 +239,11 @@ class DbUndo(object):
|
|||||||
Access the last committed transaction, and revert the data to the
|
Access the last committed transaction, and revert the data to the
|
||||||
state before the transaction was committed.
|
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
|
db = self.db
|
||||||
self.undoindex -= 1
|
self.undoindex -= 1
|
||||||
subitems = transaction.get_recnos(reverse=True)
|
subitems = transaction.get_recnos(reverse=True)
|
||||||
@ -262,12 +276,15 @@ class DbUndo(object):
|
|||||||
|
|
||||||
def __redo(self, db=None, update_history=True):
|
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.
|
before the transaction was undone.
|
||||||
"""
|
"""
|
||||||
|
txn = self.redoq.pop()
|
||||||
|
self.undoq.append(txn)
|
||||||
self.undoindex += 1
|
self.undoindex += 1
|
||||||
transaction = self.translist[self.undoindex]
|
#transaction = self.translist[self.undoindex]
|
||||||
|
#assert transaction == txn
|
||||||
|
transaction = txn
|
||||||
db = self.db
|
db = self.db
|
||||||
subitems = transaction.get_recnos()
|
subitems = transaction.get_recnos()
|
||||||
|
|
||||||
@ -287,8 +304,9 @@ class DbUndo(object):
|
|||||||
% transaction.get_description())
|
% transaction.get_description())
|
||||||
|
|
||||||
if db.redo_callback:
|
if db.redo_callback:
|
||||||
if self.redo_available():
|
if len(self.redoq) > 1:
|
||||||
new_transaction = self.translist[self.undoindex+1]
|
#new_transaction = self.translist[self.undoindex+1]
|
||||||
|
new_transaction = self.redoq[-2]
|
||||||
db.redo_callback(_("_Redo %s")
|
db.redo_callback(_("_Redo %s")
|
||||||
% new_transaction.get_description())
|
% new_transaction.get_description())
|
||||||
else:
|
else:
|
||||||
@ -331,7 +349,12 @@ class DbUndo(object):
|
|||||||
|
|
||||||
except DBERRS, msg:
|
except DBERRS, msg:
|
||||||
self.db._log_error()
|
self.db._log_error()
|
||||||
raise Errors.DbError(msg)
|
raise Errors.DbError(msg)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def undo_count(self):
|
||||||
|
"""Number of undo requests in the queue"""
|
||||||
|
return len(self.undoq)
|
||||||
|
|
||||||
class DbUndoList(DbUndo):
|
class DbUndoList(DbUndo):
|
||||||
"""
|
"""
|
||||||
|
Loading…
Reference in New Issue
Block a user