Add new backup preferences
Allow user to specify a backup directory. Add option to backup on exit. Add option to autobackup at regular intervals.
This commit is contained in:
parent
eceeddb1e4
commit
593f5a8f2b
@ -159,7 +159,9 @@ register('behavior.addons-url', "https://raw.githubusercontent.com/gramps-projec
|
||||
|
||||
register('database.backend', 'bsddb')
|
||||
register('database.compress-backup', True)
|
||||
register('database.autobackup', True) ## make backup when exiting, if there are changes
|
||||
register('database.backup-path', USER_HOME)
|
||||
register('database.backup-on-exit', True)
|
||||
register('database.autobackup', 0)
|
||||
register('database.path', os.path.join(HOME_DIR, 'grampsdb'))
|
||||
|
||||
register('export.proxy-order',
|
||||
|
@ -1995,23 +1995,3 @@ class DbWriteBase(DbReadBase):
|
||||
|
||||
person.birth_ref_index = birth_ref_index
|
||||
person.death_ref_index = death_ref_index
|
||||
|
||||
def autobackup(self, user=None):
|
||||
"""
|
||||
Backup the current file as a backup file.
|
||||
"""
|
||||
from gramps.cli.user import User
|
||||
if user is None:
|
||||
user = User()
|
||||
if self.is_open() and self.has_changed:
|
||||
if user.uistate:
|
||||
user.uistate.set_busy_cursor(True)
|
||||
user.uistate.progress.show()
|
||||
user.uistate.push_message(user.dbstate, _("Autobackup..."))
|
||||
try:
|
||||
self.backup(user=user)
|
||||
except DbException as msg:
|
||||
user.notify_error(_("Error saving backup data"), msg)
|
||||
if user.uistate:
|
||||
user.uistate.set_busy_cursor(False)
|
||||
user.uistate.progress.hide()
|
||||
|
@ -646,8 +646,6 @@ class DbGeneric(DbWriteBase, DbReadBase, UpdateCallback, Callback):
|
||||
"""
|
||||
if self._directory:
|
||||
if update:
|
||||
if config.get('database.autobackup'):
|
||||
self.autobackup(user)
|
||||
# This is just a dummy file to indicate last modified time of
|
||||
# the database for gramps.cli.clidbman:
|
||||
filename = os.path.join(self._directory, "meta_data.db")
|
||||
@ -2576,20 +2574,6 @@ class DbGeneric(DbWriteBase, DbReadBase, UpdateCallback, Callback):
|
||||
def redo(self, update_history=True):
|
||||
return self.undodb.redo(update_history)
|
||||
|
||||
def backup(self, user=None):
|
||||
"""
|
||||
If you wish to support an optional backup routine, put it here.
|
||||
"""
|
||||
from gramps.plugins.export.exportxml import XmlWriter
|
||||
from gramps.cli.user import User
|
||||
if user is None:
|
||||
user = User()
|
||||
compress = config.get('database.compress-backup')
|
||||
writer = XmlWriter(self, user, strip_photos=0, compress=compress)
|
||||
timestamp = '{0:%Y-%m-%d-%H-%M-%S}'.format(datetime.datetime.now())
|
||||
filename = os.path.join(self._directory, "backup-%s.gramps" % timestamp)
|
||||
writer.write(filename)
|
||||
|
||||
def get_summary(self):
|
||||
"""
|
||||
Returns dictionary of summary item.
|
||||
|
@ -1239,6 +1239,11 @@ class GrampsPreferences(ConfigureDialog):
|
||||
def date_calendar_changed(self, obj):
|
||||
config.set('preferences.calendar-format-report', obj.get_active())
|
||||
|
||||
def autobackup_changed(self, obj):
|
||||
active = obj.get_active()
|
||||
config.set('database.autobackup', active)
|
||||
self.uistate.set_autobackup_timer()
|
||||
|
||||
def add_date_panel(self, configdialog):
|
||||
grid = Gtk.Grid()
|
||||
grid.set_border_width(12)
|
||||
@ -1464,6 +1469,33 @@ class GrampsPreferences(ConfigureDialog):
|
||||
current_line, 'behavior.autoload')
|
||||
current_line += 1
|
||||
|
||||
self.backup_path_entry = Gtk.Entry()
|
||||
self.add_path_box(grid,
|
||||
_('Backup path'),
|
||||
current_line, self.backup_path_entry,
|
||||
config.get('database.backup-path'),
|
||||
self.set_backup_path, self.select_backup_path)
|
||||
current_line += 1
|
||||
|
||||
self.add_checkbox(grid,
|
||||
_('Backup on exit'),
|
||||
current_line, 'database.backup-on-exit')
|
||||
current_line += 1
|
||||
|
||||
# Check for updates:
|
||||
obox = Gtk.ComboBoxText()
|
||||
formats = [_("Never"),
|
||||
_("Every 15 minutes"),
|
||||
_("Every 30 minutes"),
|
||||
_("Every hour")]
|
||||
list(map(obox.append_text, formats))
|
||||
active = config.get('database.autobackup')
|
||||
obox.set_active(active)
|
||||
obox.connect('changed', self.autobackup_changed)
|
||||
lwidget = BasicLabel("%s: " % _('Autobackup'))
|
||||
grid.attach(lwidget, 1, current_line, 1, 1)
|
||||
grid.attach(obox, 2, current_line, 1, 1)
|
||||
|
||||
return _('Family Tree'), grid
|
||||
|
||||
def __create_backend_combo(self):
|
||||
@ -1543,6 +1575,31 @@ class GrampsPreferences(ConfigureDialog):
|
||||
self.dbpath_entry.set_text(val)
|
||||
f.destroy()
|
||||
|
||||
def set_backup_path(self, *obj):
|
||||
path = self.backup_path_entry.get_text().strip()
|
||||
config.set('database.backup-path', path)
|
||||
|
||||
def select_backup_path(self, *obj):
|
||||
f = Gtk.FileChooserDialog(title=_("Select backup directory"),
|
||||
parent=self.window,
|
||||
action=Gtk.FileChooserAction.SELECT_FOLDER,
|
||||
buttons=(_('_Cancel'),
|
||||
Gtk.ResponseType.CANCEL,
|
||||
_('_Apply'),
|
||||
Gtk.ResponseType.OK)
|
||||
)
|
||||
backup_path = config.get('database.backup-path')
|
||||
if not backup_path:
|
||||
backup_path = config.get('database.path')
|
||||
f.set_current_folder(os.path.dirname(backup_path))
|
||||
|
||||
status = f.run()
|
||||
if status == Gtk.ResponseType.OK:
|
||||
val = f.get_filename()
|
||||
if val:
|
||||
self.backup_path_entry.set_text(val)
|
||||
f.destroy()
|
||||
|
||||
def update_idformat_entry(self, obj, constant):
|
||||
config.set(constant, obj.get_text())
|
||||
self.dbstate.db.set_prefixes(
|
||||
|
@ -371,6 +371,7 @@ class DisplayState(Callback):
|
||||
'nameformat-changed' : None,
|
||||
'grampletbar-close-changed' : None,
|
||||
'update-available' : (list, ),
|
||||
'autobackup' : None,
|
||||
}
|
||||
|
||||
#nav_type to message
|
||||
@ -409,6 +410,7 @@ class DisplayState(Callback):
|
||||
self.disprel_active = None
|
||||
self.set_relationship_class()
|
||||
self.export = False
|
||||
self.backup_timer = None
|
||||
|
||||
formatter = logging.Formatter('%(levelname)s %(name)s: %(message)s')
|
||||
warnbtn = status.get_warning_button()
|
||||
@ -421,6 +423,31 @@ class DisplayState(Callback):
|
||||
# but this connection is still made!
|
||||
# self.dbstate.connect('database-changed', self.db_changed)
|
||||
|
||||
def set_backup_timer(self):
|
||||
"""
|
||||
Set the backup timer.
|
||||
"""
|
||||
interval = config.get('database.autobackup')
|
||||
if self.backup_timer is not None:
|
||||
GLib.source_remove(self.backup_timer)
|
||||
self.backup_timer = None
|
||||
if interval == 1:
|
||||
minutes = 15
|
||||
elif interval == 2:
|
||||
minutes = 30
|
||||
elif interval == 3:
|
||||
minutes = 60
|
||||
if interval > 0:
|
||||
self.backup_timer = GLib.timeout_add_seconds(
|
||||
minutes*60, self.__emit_autobackup)
|
||||
|
||||
def __emit_autobackup(self):
|
||||
"""
|
||||
Emit an 'autobackup' signal.
|
||||
"""
|
||||
self.emit('autobackup')
|
||||
return True
|
||||
|
||||
def screen_width(self):
|
||||
"""
|
||||
Return the width of the current screen.
|
||||
|
@ -91,6 +91,7 @@ from .aboutdialog import GrampsAboutDialog
|
||||
from .navigator import Navigator
|
||||
from .views.tags import Tags
|
||||
from .actiongroup import ActionGroup
|
||||
from gramps.gen.db.exceptions import DbWriteFailure
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
#
|
||||
@ -311,6 +312,9 @@ class ViewManager(CLIManager):
|
||||
# Need to call after plugins have been registered
|
||||
self.uistate.connect('update-available', self.process_updates)
|
||||
self.check_for_updates()
|
||||
# Set autobackup
|
||||
self.uistate.connect('autobackup', self.autobackup)
|
||||
self.uistate.set_backup_timer()
|
||||
|
||||
def check_for_updates(self):
|
||||
"""
|
||||
@ -750,7 +754,11 @@ class ViewManager(CLIManager):
|
||||
# mark interface insenstitive to prevent unexpected events
|
||||
self.uistate.set_sensitive(False)
|
||||
|
||||
# backup data, and close the database
|
||||
# backup data
|
||||
if config.get('database.backup-on-exit'):
|
||||
self.autobackup()
|
||||
|
||||
# close the database
|
||||
if self.dbstate.is_open():
|
||||
self.dbstate.db.close(user=self.user)
|
||||
|
||||
@ -1400,6 +1408,37 @@ class ViewManager(CLIManager):
|
||||
self.uistate.push_message(self.dbstate, _("Backup aborted"))
|
||||
window.destroy()
|
||||
|
||||
def autobackup(self):
|
||||
"""
|
||||
Backup the current family tree.
|
||||
"""
|
||||
if self.dbstate.db.is_open() and self.dbstate.db.has_changed:
|
||||
self.uistate.set_busy_cursor(True)
|
||||
self.uistate.progress.show()
|
||||
self.uistate.push_message(self.dbstate, _("Autobackup..."))
|
||||
try:
|
||||
self.__backup()
|
||||
except DbWriteFailure as msg:
|
||||
self.uistate.push_message(self.dbstate,
|
||||
_("Error saving backup data"))
|
||||
self.uistate.set_busy_cursor(False)
|
||||
self.uistate.progress.hide()
|
||||
|
||||
def __backup(self):
|
||||
"""
|
||||
Backup database to a Gramps XML file.
|
||||
"""
|
||||
from gramps.plugins.export.exportxml import XmlWriter
|
||||
backup_path = config.get('database.backup-path')
|
||||
compress = config.get('database.compress-backup')
|
||||
writer = XmlWriter(self.dbstate.db, self.user, strip_photos=0,
|
||||
compress=compress)
|
||||
timestamp = '{0:%Y-%m-%d-%H-%M-%S}'.format(datetime.datetime.now())
|
||||
backup_name = "%s-%s.gramps" % (self.dbstate.db.get_dbname(),
|
||||
timestamp)
|
||||
filename = os.path.join(backup_path, backup_name)
|
||||
writer.write(filename)
|
||||
|
||||
def select_backup_path(self, widget, path_entry):
|
||||
"""
|
||||
Choose a backup folder. Make sure there is one highlighted in
|
||||
|
@ -1507,7 +1507,6 @@ class DbBsddb(DbBsddbRead, DbWriteBase, UpdateCallback):
|
||||
"""
|
||||
if not self.db_is_open:
|
||||
return
|
||||
self.autobackup(user)
|
||||
if self.txn:
|
||||
self.transaction_abort(self.transaction)
|
||||
self.env.txn_checkpoint()
|
||||
|
@ -54,13 +54,6 @@ class InMemoryDB(DBAPI):
|
||||
with open(versionpath, "w") as version_file:
|
||||
version_file.write(str(self.VERSION))
|
||||
|
||||
def autobackup(self, user=None):
|
||||
"""
|
||||
Nothing to do, as we write it out anyway.
|
||||
No backups for inmemory databases.
|
||||
"""
|
||||
pass
|
||||
|
||||
def load(self, directory, callback=None, mode=None,
|
||||
force_schema_upgrade=False,
|
||||
force_bsddb_upgrade=False,
|
||||
|
Loading…
Reference in New Issue
Block a user