2006-05-06 Alex Roitman <shura@gramps-project.org>

* src/GrampsDb/_GrampsBSDDB.py (load): Use common undodb
	methods; reset undo history.
	* src/GrampsDb/_GrampsInMemDB.py (load): Use common undodb
	methods; reset undo history.
	* src/GrampsDb/_GrampsXMLDB.py: Minor fix.
	* src/GrampsDb/_GrampsGEDDB.py: Minor fix.
	* src/GrampsDb/_GrampsDbBase.py: Undo history support.
	* src/UndoHistory.py: Fixes and additions.
	* src/ViewManager.py (post_load): Re-set undo/redo labels.



svn: r6569
This commit is contained in:
Alex Roitman
2006-05-07 05:22:44 +00:00
parent 7c9539ca4c
commit 86cffe6504
8 changed files with 144 additions and 76 deletions

View File

@ -1,3 +1,14 @@
2006-05-06 Alex Roitman <shura@gramps-project.org>
* src/GrampsDb/_GrampsBSDDB.py (load): Use common undodb
methods; reset undo history.
* src/GrampsDb/_GrampsInMemDB.py (load): Use common undodb
methods; reset undo history.
* src/GrampsDb/_GrampsXMLDB.py: Minor fix.
* src/GrampsDb/_GrampsGEDDB.py: Minor fix.
* src/GrampsDb/_GrampsDbBase.py: Undo history support.
* src/UndoHistory.py: Fixes and additions.
* src/ViewManager.py (post_load): Re-set undo/redo labels.
2006-05-06 Don Allingham <don@gramps-project.org> 2006-05-06 Don Allingham <don@gramps-project.org>
* src/PluginUtils/_ReportUtils.py: fix set_nick_name * src/PluginUtils/_ReportUtils.py: fix set_nick_name
* src/RelLib/_MediaRef.py: handle initialization of Ref object * src/RelLib/_MediaRef.py: handle initialization of Ref object

View File

@ -311,7 +311,6 @@ class GrampsBSDDB(GrampsDbBase):
env_flags = db.DB_CREATE|db.DB_PRIVATE|\ env_flags = db.DB_CREATE|db.DB_PRIVATE|\
db.DB_INIT_MPOOL|db.DB_INIT_LOG db.DB_INIT_MPOOL|db.DB_INIT_LOG
self.undolog = "%s.undo" % name
env_name = os.path.expanduser(const.bsddbenv_dir) env_name = os.path.expanduser(const.bsddbenv_dir)
if not os.path.isdir(env_name): if not os.path.isdir(env_name):
os.mkdir(env_name) os.mkdir(env_name)
@ -373,12 +372,16 @@ class GrampsBSDDB(GrampsDbBase):
callback(75) callback(75)
if not self.readonly: self.open_undodb()
self.undodb = db.DB()
self.undodb.open(self.undolog, db.DB_RECNO, db.DB_CREATE)
self.db_is_open = True self.db_is_open = True
callback(87) callback(87)
# Re-set the undo history to a fresh session start
self.undoindex = -1
self.translist = [None] * len(self.translist)
self.abort_possible = True
self.undo_history_timestamp = time.time()
return 1 return 1
@ -840,13 +843,8 @@ class GrampsBSDDB(GrampsDbBase):
self.event_map.close() self.event_map.close()
self.env.close() self.env.close()
if not self.readonly: self.close_undodb()
self.undodb.close()
try:
os.remove(self.undolog)
except:
pass
self.person_map = None self.person_map = None
self.family_map = None self.family_map = None
self.repository_map = None self.repository_map = None

View File

@ -39,6 +39,7 @@ import random
import locale import locale
import os import os
from sys import maxint from sys import maxint
from bsddb import db
from gettext import gettext as _ from gettext import gettext as _
try: try:
@ -261,6 +262,7 @@ class GrampsDbBase(GrampsDBCallback):
self.undoindex = -1 self.undoindex = -1
self.translist = [None] * _UNDO_SIZE self.translist = [None] * _UNDO_SIZE
self.abort_possible = True self.abort_possible = True
self.undo_history_timestamp = 0
self.default = None self.default = None
self.owner = Researcher() self.owner = Researcher()
self.bookmarks = [] self.bookmarks = []
@ -333,6 +335,20 @@ class GrampsDbBase(GrampsDBCallback):
def get_repository_cursor(self): def get_repository_cursor(self):
assert False, "Needs to be overridden in the derived class" assert False, "Needs to be overridden in the derived class"
def open_undodb(self):
if not self.readonly:
self.undolog = "%s.undo" % self.full_name
self.undodb = db.DB()
self.undodb.open(self.undolog, db.DB_RECNO, db.DB_CREATE)
def close_undodb(self):
if not self.readonly:
self.undodb.close()
try:
os.remove(self.undolog)
except:
pass
def load(self, name, callback, mode="w"): def load(self, name, callback, mode="w"):
""" """
Opens the specified database. The method needs to be overridden Opens the specified database. The method needs to be overridden
@ -1209,6 +1225,7 @@ class GrampsDbBase(GrampsDBCallback):
# A batch transaction does not store the commits # A batch transaction does not store the commits
# Aborting the session completely will become impossible. # Aborting the session completely will become impossible.
self.abort_possible = False self.abort_possible = False
self.undo_history_timestamp = time.time()
# Undo is also impossible after batch transaction # Undo is also impossible after batch transaction
self.undoindex = -1 self.undoindex = -1
return Transaction(msg, self.undodb, batch) return Transaction(msg, self.undodb, batch)
@ -1230,6 +1247,7 @@ class GrampsDbBase(GrampsDBCallback):
# We overran the undo size. # We overran the undo size.
# Aborting the session completely will become impossible. # Aborting the session completely will become impossible.
self.abort_possible = False self.abort_possible = False
self.undo_history_timestamp = time.time()
self.translist = self.translist[0:-1] + [ transaction ] self.translist = self.translist[0:-1] + [ transaction ]
else: else:
self.translist[self.undoindex] = transaction self.translist[self.undoindex] = transaction
@ -1306,12 +1324,29 @@ class GrampsDbBase(GrampsDBCallback):
retlist.append(str(handle)) retlist.append(str(handle))
return retlist return retlist
def undo_available(self):
# returns boolean of whether or not there's a possibility of undo
if self.undoindex == -1 or self.readonly:
return False
return True
def redo_available(self):
# returns boolean of whether or not there's a possibility of redo
if self.undoindex >= _UNDO_SIZE or self.readonly:
return False
if self.translist[self.undoindex+1] == None:
return False
return True
def undo(self,update_history=True): def undo(self,update_history=True):
""" """
Accesses the last committed transaction, and reverts the data to Accesses the last committed transaction, and reverts the data to
the state before the transaction was committed. the state before the transaction was committed.
""" """
if self.undoindex == -1 or self.readonly: if not self.undo_available():
return False return False
transaction = self.translist[self.undoindex] transaction = self.translist[self.undoindex]
@ -1331,19 +1366,19 @@ class GrampsDbBase(GrampsDBCallback):
self.undo_data(old_data, handle, mapbase[key], _sigbase[key]) self.undo_data(old_data, handle, mapbase[key], _sigbase[key])
if self.undo_callback: if self.undo_callback:
if self.undoindex == -1: if self.undo_available():
self.undo_callback(None)
else:
new_transaction = self.translist[self.undoindex] new_transaction = self.translist[self.undoindex]
self.undo_callback(_("_Undo %s") self.undo_callback(_("_Undo %s")
% new_transaction.get_description()) % new_transaction.get_description())
if self.redo_callback:
if self.undoindex >= _UNDO_SIZE \
or self.translist[self.undoindex+1]==None:
self.redo_callback(None)
else: else:
self.undo_callback(None)
if self.redo_callback:
if self. redo_available():
self.redo_callback(_("_Redo %s") self.redo_callback(_("_Redo %s")
% transaction.get_description()) % transaction.get_description())
else:
self.redo_callback(None)
if update_history and self.undo_history_callback: if update_history and self.undo_history_callback:
self.undo_history_callback() self.undo_history_callback()
@ -1354,14 +1389,12 @@ class GrampsDbBase(GrampsDBCallback):
Accesses the last undone transaction, and reverts the data to Accesses the last undone transaction, and reverts the data to
the state before the transaction was undone. the state before the transaction was undone.
""" """
if self.undoindex >= _UNDO_SIZE or self.readonly:
return False
transaction = self.translist[self.undoindex+1] if not self.redo_available():
if transaction == None:
return False return False
self.undoindex += 1 self.undoindex += 1
transaction = self.translist[self.undoindex]
mapbase = (self.person_map, self.family_map, self.source_map, mapbase = (self.person_map, self.family_map, self.source_map,
self.event_map, self.media_map, self.place_map, self.event_map, self.media_map, self.place_map,
self.repository_map) self.repository_map)
@ -1375,26 +1408,19 @@ class GrampsDbBase(GrampsDBCallback):
self.undo_data(new_data, handle, mapbase[key], _sigbase[key]) self.undo_data(new_data, handle, mapbase[key], _sigbase[key])
if self.undo_callback: if self.undo_callback:
if self.undoindex == -1: if self.undo_available():
self.undo_callback(None)
else:
self.undo_callback(_("_Undo %s") self.undo_callback(_("_Undo %s")
% transaction.get_description()) % transaction.get_description())
if self.redo_callback:
if self.undoindex >= _UNDO_SIZE \
or self.translist[self.undoindex+1]==None:
self.redo_callback(None)
else: else:
self.undo_callback(None)
if self.redo_callback:
if self.redo_available():
new_transaction = self.translist[self.undoindex+1] new_transaction = self.translist[self.undoindex+1]
self.redo_callback(_("_Redo %s") self.redo_callback(_("_Redo %s")
% new_transaction.get_description()) % new_transaction.get_description())
if self.undo_callback:
if self.undoindex == _UNDO_SIZE:
self.undo_callback(None)
else: else:
self.undo_callback(_("_Undo %s") self.redo_callback(None)
% transaction.get_description())
if update_history and self.undo_history_callback: if update_history and self.undo_history_callback:
self.undo_history_callback() self.undo_history_callback()

View File

@ -1,7 +1,7 @@
# #
# Gramps - a GTK+/GNOME based genealogy program # Gramps - a GTK+/GNOME based genealogy program
# #
# Copyright (C) 2000-2004 Donald N. Allingham # Copyright (C) 2000-2006 Donald N. Allingham
# #
# This program is free software; you can redistribute it and/or modify # This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by # it under the terms of the GNU General Public License as published by
@ -61,6 +61,5 @@ class GrampsGEDDB(GrampsInMemDB):
return return
if not self.readonly and len(self.undodb) > 0: if not self.readonly and len(self.undodb) > 0:
writer = WriteGedcom.GedcomWriter(self,self.get_default_person()) writer = WriteGedcom.GedcomWriter(self,self.get_default_person())
writer.export_data(self.filename) writer.export_data(self.full_name)
self.db_is_open = False self.db_is_open = False

View File

@ -30,8 +30,8 @@ must hold all of their data in memory.
# Python modules # Python modules
# #
#------------------------------------------------------------------------- #-------------------------------------------------------------------------
from bsddb import dbshelve, db
import sets import sets
import time
#------------------------------------------------------------------------- #-------------------------------------------------------------------------
# #
@ -99,12 +99,16 @@ class GrampsInMemDB(GrampsDbBase):
self.undodb = [] self.undodb = []
def load(self,name,callback,mode="w"): def load(self,name,callback,mode="w"):
self.undolog = "%s.log" % name self.open_undodb()
self.undodb = db.DB() self.full_name = name
self.undodb.open(self.undolog, db.DB_RECNO, db.DB_CREATE)
self.filename = name
self.readonly = mode == "r" self.readonly = mode == "r"
# Re-set the undo history to a fresh session start
self.undoindex = -1
self.translist = [None] * len(self.state.db.translist)
self.abort_possible = True
self.undo_history_timestamp = time.time()
def get_person_cursor(self): def get_person_cursor(self):
return GrampsInMemCursor(self.person_map) return GrampsInMemCursor(self.person_map)
@ -130,12 +134,7 @@ class GrampsInMemDB(GrampsDbBase):
return GrampsInMemCursor(self.event_map) return GrampsInMemCursor(self.event_map)
def close(self): def close(self):
if not self.readonly: self.close_undodb()
self.undodb.close()
try:
os.remove(self.undolog)
except:
pass
def set_name_group_mapping(self,name,group): def set_name_group_mapping(self,name,group):
if group == None and self.name_group.has_key(name): if group == None and self.name_group.has_key(name):

View File

@ -1,7 +1,7 @@
# #
# Gramps - a GTK+/GNOME based genealogy program # Gramps - a GTK+/GNOME based genealogy program
# #
# Copyright (C) 2000-2004 Donald N. Allingham # Copyright (C) 2000-2006 Donald N. Allingham
# #
# This program is free software; you can redistribute it and/or modify # This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by # it under the terms of the GNU General Public License as published by
@ -62,5 +62,5 @@ class GrampsXMLDB(GrampsInMemDB):
if not self.db_is_open: if not self.db_is_open:
return return
if not self.readonly and len(self.undodb) > 0: if not self.readonly and len(self.undodb) > 0:
WriteXML.quick_write(self,self.filename) WriteXML.quick_write(self,self.full_name)
self.db_is_open = False self.db_is_open = False

View File

@ -62,18 +62,22 @@ class UndoHistory(ManagedWindow.ManagedWindow):
self.title = _("Undo History") self.title = _("Undo History")
ManagedWindow.ManagedWindow.__init__(self,uistate,[],self.__class__) ManagedWindow.ManagedWindow.__init__(self,uistate,[],self.__class__)
self.db = dbstate.db self.db = dbstate.db
self.dbstate = dbstate
self.set_window( window = gtk.Dialog("",uistate.window,
gtk.Dialog("",uistate.window, gtk.DIALOG_DESTROY_WITH_PARENT,None)
gtk.DIALOG_DESTROY_WITH_PARENT,
(gtk.STOCK_UNDO,gtk.RESPONSE_REJECT, self.undo_button = window.add_button(gtk.STOCK_UNDO,
gtk.STOCK_REDO,gtk.RESPONSE_ACCEPT, gtk.RESPONSE_REJECT)
gtk.STOCK_CLEAR,gtk.RESPONSE_APPLY, self.redo_button = window.add_button(gtk.STOCK_REDO,
gtk.STOCK_CLOSE,gtk.RESPONSE_CLOSE, gtk.RESPONSE_ACCEPT)
) self.clear_button = window.add_button(gtk.STOCK_CLEAR,
), gtk.RESPONSE_APPLY)
None, self.title) self.close_button = window.add_button(gtk.STOCK_CLOSE,
self.window.set_size_request(600,400) gtk.RESPONSE_CLOSE)
self.set_window(window, None, self.title)
self.window.set_size_request(400,200)
self.window.connect('response', self._response) self.window.connect('response', self._response)
scrolled_window = gtk.ScrolledWindow() scrolled_window = gtk.ScrolledWindow()
@ -88,7 +92,7 @@ class UndoHistory(ManagedWindow.ManagedWindow):
gtk.TreeViewColumn(_('Original time'), gtk.CellRendererText(), gtk.TreeViewColumn(_('Original time'), gtk.CellRendererText(),
text=0)) text=0))
self.list.append_column( self.list.append_column(
gtk.TreeViewColumn(_('Modification'), gtk.CellRendererText(), gtk.TreeViewColumn(_('Action'), gtk.CellRendererText(),
text=1)) text=1))
scrolled_window.add(self.list) scrolled_window.add(self.list)
@ -96,9 +100,21 @@ class UndoHistory(ManagedWindow.ManagedWindow):
self.window.show_all() self.window.show_all()
self._build_model() self._build_model()
self._update_ui()
self.db_change_key = dbstate.connect('database-changed',self._close)
self.selection.connect('changed',self._selection_changed)
self.show()
self.db.connect('database-changed',self.clear) def _close(self,obj):
self.selection.connect('changed',self._move) self.dbstate.disconnect(self.db_change_key)
self.close()
def _selection_changed(self,obj):
(model,node) = self.selection.get_selected()
if node:
path = self.model.get_path(node)
self._move(path[0]-self.db.undoindex-1)
def _response(self,obj,response_id): def _response(self,obj,response_id):
if response_id == gtk.RESPONSE_CLOSE: if response_id == gtk.RESPONSE_CLOSE:
@ -123,33 +139,50 @@ class UndoHistory(ManagedWindow.ManagedWindow):
def clear(self): def clear(self):
self.db.undoindex = -1 self.db.undoindex = -1
self.db.translist = [None] * len(self.db.translist) self.db.translist = [None] * len(self.db.translist)
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)
if self.db.redo_callback: if self.db.redo_callback:
self.db.redo_callback(None) self.db.redo_callback(None)
def _move(self,obj,steps=-1): def _move(self,steps=-1):
self._update_ui() if steps == 0 :
return
elif steps < 0:
func = self.db.undo
elif steps > 0:
func = self.db.redo
for step in range(abs(steps)):
func(False)
self.update()
def _update_ui(self): def _update_ui(self):
pass self.undo_button.set_sensitive(self.db.undo_available())
self.redo_button.set_sensitive(self.db.redo_available())
self.clear_button.set_sensitive(
self.db.undo_available() or self.db.redo_available() )
def _build_model(self): def _build_model(self):
self.model.clear() self.model.clear()
if self.db.abort_possible:
mod_text = _('Database opened')
else:
mod_text = _('History cleared')
time_text = time.ctime(self.db.undo_history_timestamp)
self.model.append(row=[time_text,mod_text])
# Get the not-None portion of transaction list # Get the not-None portion of transaction list
translist = [item for item in self.db.translist if item] translist = [item for item in self.db.translist if item]
translist.reverse()
for transaction in translist: for transaction in translist:
time_text = time.ctime(transaction.timestamp) time_text = time.ctime(transaction.timestamp)
mod_text = transaction.get_description() mod_text = transaction.get_description()
self.model.append(row=[time_text,mod_text]) self.model.append(row=[time_text,mod_text])
if self.db.undoindex < 0: path = (self.db.undoindex+1,)
self.selection.unselect_all() self.selection.select_path(path)
else:
path = (self.db.undoindex,)
self.selection.select_path(path)
def update(self): def update(self):
self._build_model() self._build_model()
self._update_ui() self._update_ui()

View File

@ -938,6 +938,8 @@ class ViewManager:
self.change_page(None, None) self.change_page(None, None)
self.state.db.undo_callback = self.change_undo_label self.state.db.undo_callback = self.change_undo_label
self.state.db.redo_callback = self.change_redo_label self.state.db.redo_callback = self.change_redo_label
self.change_undo_label(None)
self.change_redo_label(None)
self.state.db.undo_history_callback = self.undo_history_update self.state.db.undo_history_callback = self.undo_history_update
self.actiongroup.set_visible(True) self.actiongroup.set_visible(True)
self.window.window.set_cursor(None) self.window.window.set_cursor(None)