2007-03-27 08:48:49 +05:30
|
|
|
#
|
|
|
|
# Gramps - a GTK+/GNOME based genealogy program
|
|
|
|
#
|
2007-06-20 12:07:09 +05:30
|
|
|
# Copyright (C) 2000-2007 Donald N. Allingham
|
2009-02-09 10:40:58 +05:30
|
|
|
# Copyright (C) 2009 Brian G. Matherly
|
2009-02-22 02:34:09 +05:30
|
|
|
# Copyright (C) 2009 Gary Burton
|
2007-03-27 08:48:49 +05:30
|
|
|
#
|
|
|
|
# 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
|
|
|
|
# the Free Software Foundation; either version 2 of the License, or
|
|
|
|
# (at your option) any later version.
|
|
|
|
#
|
|
|
|
# This program 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 this program; if not, write to the Free Software
|
|
|
|
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
|
|
#
|
|
|
|
|
2008-04-06 04:05:22 +05:30
|
|
|
# $Id$
|
|
|
|
|
2007-04-02 09:26:30 +05:30
|
|
|
"""
|
2008-02-24 19:25:55 +05:30
|
|
|
Provide the management of databases. This includes opening, renaming,
|
2007-04-02 09:26:30 +05:30
|
|
|
creating, and deleting of databases.
|
|
|
|
"""
|
2007-03-27 08:48:49 +05:30
|
|
|
|
|
|
|
#-------------------------------------------------------------------------
|
|
|
|
#
|
|
|
|
# Standard python modules
|
|
|
|
#
|
|
|
|
#-------------------------------------------------------------------------
|
|
|
|
import os
|
|
|
|
import time
|
2007-12-20 15:33:05 +05:30
|
|
|
import copy
|
2007-06-19 09:29:10 +05:30
|
|
|
import subprocess
|
2011-12-09 19:55:39 +05:30
|
|
|
import urlparse
|
2012-06-18 02:55:37 +05:30
|
|
|
|
2007-03-27 08:48:49 +05:30
|
|
|
#-------------------------------------------------------------------------
|
|
|
|
#
|
|
|
|
# set up logging
|
|
|
|
#
|
|
|
|
#-------------------------------------------------------------------------
|
|
|
|
import logging
|
2007-04-02 09:26:30 +05:30
|
|
|
LOG = logging.getLogger(".DbManager")
|
2007-03-27 08:48:49 +05:30
|
|
|
|
2012-06-10 02:26:43 +05:30
|
|
|
from gen.constfunc import win
|
|
|
|
if win():
|
2008-06-02 02:27:11 +05:30
|
|
|
_RCS_FOUND = os.system("rcs -V >nul 2>nul") == 0
|
2008-07-17 23:40:32 +05:30
|
|
|
if _RCS_FOUND and "TZ" not in os.environ:
|
2008-06-02 02:07:56 +05:30
|
|
|
# RCS requires the "TZ" variable be set.
|
|
|
|
os.environ["TZ"] = str(time.timezone)
|
2007-06-19 01:03:52 +05:30
|
|
|
else:
|
2008-06-02 02:27:11 +05:30
|
|
|
_RCS_FOUND = os.system("rcs -V >/dev/null 2>/dev/null") == 0
|
2007-06-19 01:03:52 +05:30
|
|
|
|
2007-03-27 08:48:49 +05:30
|
|
|
#-------------------------------------------------------------------------
|
|
|
|
#
|
|
|
|
# GTK/Gnome modules
|
|
|
|
#
|
|
|
|
#-------------------------------------------------------------------------
|
2012-06-18 02:55:37 +05:30
|
|
|
from gi.repository import Gdk
|
|
|
|
from gi.repository import Gtk
|
|
|
|
from gi.repository import Pango
|
2007-03-27 08:48:49 +05:30
|
|
|
|
|
|
|
#-------------------------------------------------------------------------
|
|
|
|
#
|
|
|
|
# gramps modules
|
|
|
|
#
|
|
|
|
#-------------------------------------------------------------------------
|
2012-06-18 02:55:37 +05:30
|
|
|
from gen.ggettext import gettext as _
|
|
|
|
from gui.user import User
|
2012-06-06 05:19:12 +05:30
|
|
|
from gui.dialog import ErrorDialog, QuestionDialog, QuestionDialog2
|
2009-12-23 21:25:58 +05:30
|
|
|
from gen.db import DbBsddb
|
2009-10-25 19:22:29 +05:30
|
|
|
from gui.pluginmanager import GuiPluginManager
|
2009-08-12 15:26:07 +05:30
|
|
|
from cli.clidbman import CLIDbManager, NAME_FILE, time_val
|
2012-06-06 21:30:54 +05:30
|
|
|
from gui.ddtargets import DdTargets
|
2012-06-08 01:47:11 +05:30
|
|
|
from gen.recentfiles import rename_filename, remove_filename
|
2012-06-06 02:53:06 +05:30
|
|
|
from gui.glade import Glade
|
2009-12-20 10:00:28 +05:30
|
|
|
from gen.db.backup import restore
|
2009-12-23 21:25:58 +05:30
|
|
|
from gen.db.exceptions import DbException
|
2012-06-24 03:43:23 +05:30
|
|
|
from gen.utils.file import get_unicode_path_from_env_var
|
2007-03-27 08:48:49 +05:30
|
|
|
|
2010-02-08 22:49:15 +05:30
|
|
|
|
2012-06-18 02:55:37 +05:30
|
|
|
_RETURN = Gdk.keyval_from_name("Return")
|
|
|
|
_KP_ENTER = Gdk.keyval_from_name("KP_Enter")
|
2008-02-20 03:24:34 +05:30
|
|
|
|
2009-05-15 01:45:59 +05:30
|
|
|
|
2007-04-02 04:07:10 +05:30
|
|
|
#-------------------------------------------------------------------------
|
|
|
|
#
|
|
|
|
# constants
|
|
|
|
#
|
|
|
|
#-------------------------------------------------------------------------
|
2009-06-19 03:26:37 +05:30
|
|
|
|
2007-06-21 05:06:09 +05:30
|
|
|
ARCHIVE = "rev.gramps"
|
|
|
|
ARCHIVE_V = "rev.gramps,v"
|
2007-03-27 08:48:49 +05:30
|
|
|
|
2008-04-10 07:11:47 +05:30
|
|
|
NAME_COL = 0
|
|
|
|
PATH_COL = 1
|
|
|
|
FILE_COL = 2
|
|
|
|
DATE_COL = 3
|
|
|
|
DSORT_COL = 4
|
|
|
|
OPEN_COL = 5
|
|
|
|
STOCK_COL = 6
|
2007-03-27 08:48:49 +05:30
|
|
|
|
2008-08-13 02:35:11 +05:30
|
|
|
RCS_BUTTON = { True : _('_Extract'), False : _('_Archive') }
|
2007-06-23 10:01:05 +05:30
|
|
|
|
2007-12-28 Benny Malengier <benny.malengier@gramps-project.org>
* src/ViewManager.py: remove unused functions, add alt actions left/right
* src/GrampsDb: deleted with _GrampsDbWriteXML.py,
_GrampsDbFactories.py, _GrampsGEDDB.py, _GrampsXMLDB.py,
__init__.py, Makefile.am, _GrampsInMemDB.py, _GrampsBSDDB.py.
No more inmemory databases
* src/GrampsDbUtils: moved here _GrampsDbWriteXML.py and _GrampsBSDDB.py
* src/plugins/ReadGrdb.py:
* src/plugins/Checkpoint.py:
* src/ObjectSelector/_ObjectSelectorWindow.py:
* src/DbManager.py:
* src/GrampsDbUtils/_WriteGrdb.py:
* src/GrampsDbUtils/__init__.py:
* src/GrampsDbUtils/_GrampsDbWRFactories.py:
* src/GrampsDbUtils/_WriteXML.py:
* src/GrampsDbUtils/Makefile.am:
* src/gramps_main.py:
* src/RecentFiles.py: recent-files-gramps.xml, don't overwrite 2.2.x data
* src/ArgHandler.py:
* src/DbLoader.py: remove unused functions
* src/Makefile.am:
* po/POTFILES.in:
* src/GrampsDbUtils/importdbdir.py: allow import of new database via cli
Remove inMem Editing, move remaining to DbUtils, fix ArgHandler
svn: r9613
2007-12-28 20:39:01 +05:30
|
|
|
class DbManager(CLIDbManager):
|
2007-04-02 04:07:10 +05:30
|
|
|
"""
|
|
|
|
Database Manager. Opens a database manager window that allows users to
|
|
|
|
create, rename, delete and open databases.
|
|
|
|
"""
|
2009-06-19 14:16:17 +05:30
|
|
|
ICON_MAP = {
|
2012-08-16 02:21:24 +05:30
|
|
|
CLIDbManager.ICON_NONE : None,
|
2012-06-18 02:55:37 +05:30
|
|
|
CLIDbManager.ICON_RECOVERY : Gtk.STOCK_DIALOG_ERROR,
|
2009-06-19 14:16:17 +05:30
|
|
|
CLIDbManager.ICON_LOCK : 'gramps-lock',
|
2012-06-18 02:55:37 +05:30
|
|
|
CLIDbManager.ICON_OPEN : Gtk.STOCK_OPEN,
|
2009-06-19 14:16:17 +05:30
|
|
|
}
|
2007-04-02 04:07:10 +05:30
|
|
|
|
2011-01-30 21:58:54 +05:30
|
|
|
ERROR = ErrorDialog
|
|
|
|
|
2007-03-29 07:12:21 +05:30
|
|
|
def __init__(self, dbstate, parent=None):
|
2007-04-02 04:07:10 +05:30
|
|
|
"""
|
2008-02-24 19:25:55 +05:30
|
|
|
Create the top level window from the glade description, and extracts
|
2007-04-02 04:07:10 +05:30
|
|
|
the GTK widgets that are needed.
|
|
|
|
"""
|
2007-12-28 Benny Malengier <benny.malengier@gramps-project.org>
* src/ViewManager.py: remove unused functions, add alt actions left/right
* src/GrampsDb: deleted with _GrampsDbWriteXML.py,
_GrampsDbFactories.py, _GrampsGEDDB.py, _GrampsXMLDB.py,
__init__.py, Makefile.am, _GrampsInMemDB.py, _GrampsBSDDB.py.
No more inmemory databases
* src/GrampsDbUtils: moved here _GrampsDbWriteXML.py and _GrampsBSDDB.py
* src/plugins/ReadGrdb.py:
* src/plugins/Checkpoint.py:
* src/ObjectSelector/_ObjectSelectorWindow.py:
* src/DbManager.py:
* src/GrampsDbUtils/_WriteGrdb.py:
* src/GrampsDbUtils/__init__.py:
* src/GrampsDbUtils/_GrampsDbWRFactories.py:
* src/GrampsDbUtils/_WriteXML.py:
* src/GrampsDbUtils/Makefile.am:
* src/gramps_main.py:
* src/RecentFiles.py: recent-files-gramps.xml, don't overwrite 2.2.x data
* src/ArgHandler.py:
* src/DbLoader.py: remove unused functions
* src/Makefile.am:
* po/POTFILES.in:
* src/GrampsDbUtils/importdbdir.py: allow import of new database via cli
Remove inMem Editing, move remaining to DbUtils, fix ArgHandler
svn: r9613
2007-12-28 20:39:01 +05:30
|
|
|
CLIDbManager.__init__(self, dbstate)
|
2009-05-15 01:45:59 +05:30
|
|
|
self.glade = Glade()
|
|
|
|
self.top = self.glade.toplevel
|
|
|
|
|
2007-03-29 07:12:21 +05:30
|
|
|
if parent:
|
|
|
|
self.top.set_transient_for(parent)
|
2007-03-27 08:48:49 +05:30
|
|
|
|
2009-05-06 20:14:22 +05:30
|
|
|
for attr in ['connect', 'cancel', 'new', 'remove',
|
|
|
|
'dblist', 'rename', 'repair', 'rcs', 'msg']:
|
|
|
|
setattr(self, attr, self.glade.get_object(attr))
|
|
|
|
|
|
|
|
self.model = None
|
2007-04-02 09:26:30 +05:30
|
|
|
self.column = None
|
2007-06-23 10:01:05 +05:30
|
|
|
self.lock_file = None
|
2007-04-02 09:26:30 +05:30
|
|
|
self.data_to_delete = None
|
|
|
|
|
2007-03-28 09:03:11 +05:30
|
|
|
self.selection = self.dblist.get_selection()
|
2007-07-18 09:47:30 +05:30
|
|
|
self.dblist.set_rules_hint(True)
|
2007-03-27 08:48:49 +05:30
|
|
|
|
2007-06-17 04:47:29 +05:30
|
|
|
self.__connect_signals()
|
|
|
|
self.__build_interface()
|
2007-12-28 Benny Malengier <benny.malengier@gramps-project.org>
* src/ViewManager.py: remove unused functions, add alt actions left/right
* src/GrampsDb: deleted with _GrampsDbWriteXML.py,
_GrampsDbFactories.py, _GrampsGEDDB.py, _GrampsXMLDB.py,
__init__.py, Makefile.am, _GrampsInMemDB.py, _GrampsBSDDB.py.
No more inmemory databases
* src/GrampsDbUtils: moved here _GrampsDbWriteXML.py and _GrampsBSDDB.py
* src/plugins/ReadGrdb.py:
* src/plugins/Checkpoint.py:
* src/ObjectSelector/_ObjectSelectorWindow.py:
* src/DbManager.py:
* src/GrampsDbUtils/_WriteGrdb.py:
* src/GrampsDbUtils/__init__.py:
* src/GrampsDbUtils/_GrampsDbWRFactories.py:
* src/GrampsDbUtils/_WriteXML.py:
* src/GrampsDbUtils/Makefile.am:
* src/gramps_main.py:
* src/RecentFiles.py: recent-files-gramps.xml, don't overwrite 2.2.x data
* src/ArgHandler.py:
* src/DbLoader.py: remove unused functions
* src/Makefile.am:
* po/POTFILES.in:
* src/GrampsDbUtils/importdbdir.py: allow import of new database via cli
Remove inMem Editing, move remaining to DbUtils, fix ArgHandler
svn: r9613
2007-12-28 20:39:01 +05:30
|
|
|
self._populate_model()
|
2008-04-11 18:42:11 +05:30
|
|
|
|
2007-06-17 04:47:29 +05:30
|
|
|
def __connect_signals(self):
|
2007-04-02 04:07:10 +05:30
|
|
|
"""
|
|
|
|
Connects the signals to the buttons on the interface.
|
|
|
|
"""
|
2012-07-27 20:35:46 +05:30
|
|
|
ddtarget = DdTargets.URI_LIST
|
|
|
|
self.top.drag_dest_set(Gtk.DestDefaults.ALL, [], Gdk.DragAction.COPY)
|
|
|
|
tglist = Gtk.TargetList.new([])
|
|
|
|
tglist.add(ddtarget.atom_drag_type, ddtarget.target_flags,
|
|
|
|
ddtarget.app_id)
|
|
|
|
self.top.drag_dest_set_target_list(tglist)
|
2007-07-12 09:54:44 +05:30
|
|
|
|
2007-06-17 04:47:29 +05:30
|
|
|
self.remove.connect('clicked', self.__remove_db)
|
|
|
|
self.new.connect('clicked', self.__new_db)
|
|
|
|
self.rename.connect('clicked', self.__rename_db)
|
|
|
|
self.repair.connect('clicked', self.__repair_db)
|
|
|
|
self.selection.connect('changed', self.__selection_changed)
|
|
|
|
self.dblist.connect('button-press-event', self.__button_press)
|
2008-02-20 03:24:34 +05:30
|
|
|
self.dblist.connect('key-press-event', self.__key_press)
|
2007-07-09 06:48:04 +05:30
|
|
|
self.top.connect('drag_data_received', self.__drag_data_received)
|
2007-09-11 03:44:33 +05:30
|
|
|
self.top.connect('drag_motion', drag_motion)
|
|
|
|
self.top.connect('drag_drop', drop_cb)
|
2007-07-09 03:50:10 +05:30
|
|
|
|
2008-06-02 02:27:11 +05:30
|
|
|
if _RCS_FOUND:
|
2007-07-12 09:54:44 +05:30
|
|
|
self.rcs.connect('clicked', self.__rcs)
|
|
|
|
|
2007-06-17 04:47:29 +05:30
|
|
|
def __button_press(self, obj, event):
|
2007-04-02 09:26:30 +05:30
|
|
|
"""
|
|
|
|
Checks for a double click event. In the tree view, we want to
|
|
|
|
treat a double click as if it was OK button press. However, we have
|
|
|
|
to make sure that an item was selected first.
|
|
|
|
"""
|
2012-06-18 02:55:37 +05:30
|
|
|
if event.type == Gdk.EventType._2BUTTON_PRESS and event.button == 1:
|
2008-02-20 13:43:35 +05:30
|
|
|
if self.connect.get_property('sensitive'):
|
2012-06-18 02:55:37 +05:30
|
|
|
self.top.response(Gtk.ResponseType.OK)
|
2008-04-01 02:22:58 +05:30
|
|
|
return True
|
2008-02-20 03:24:34 +05:30
|
|
|
return False
|
|
|
|
|
|
|
|
def __key_press(self, obj, event):
|
|
|
|
"""
|
|
|
|
Grab ENTER so it does not start editing the cell, but behaves
|
|
|
|
like double click instead
|
|
|
|
"""
|
2011-12-13 00:07:53 +05:30
|
|
|
if event.keyval in (_RETURN, _KP_ENTER):
|
|
|
|
if self.connect.get_property('sensitive'):
|
2012-06-18 02:55:37 +05:30
|
|
|
self.top.response(Gtk.ResponseType.OK)
|
2011-12-13 00:07:53 +05:30
|
|
|
return True
|
2007-03-29 07:12:21 +05:30
|
|
|
return False
|
2007-03-28 09:03:11 +05:30
|
|
|
|
2007-06-17 04:47:29 +05:30
|
|
|
def __selection_changed(self, selection):
|
2008-04-11 18:42:11 +05:30
|
|
|
"""
|
|
|
|
Called when the selection is changed in the TreeView.
|
|
|
|
"""
|
2008-01-10 02:49:36 +05:30
|
|
|
self.__update_buttons(selection)
|
|
|
|
|
|
|
|
def __update_buttons(self, selection):
|
|
|
|
"""
|
|
|
|
What we are trying to detect is the selection or unselection of a row.
|
2007-04-02 09:26:30 +05:30
|
|
|
When a row is unselected, the Open, Rename, and Remove buttons
|
|
|
|
are set insensitive. If a row is selected, the rename and remove
|
|
|
|
buttons are disabled, and the Open button is disabled if the
|
|
|
|
row represents a open database.
|
|
|
|
"""
|
2008-04-12 02:30:36 +05:30
|
|
|
|
2007-04-02 09:26:30 +05:30
|
|
|
# Get the current selection
|
|
|
|
store, node = selection.get_selected()
|
2008-04-12 02:30:36 +05:30
|
|
|
|
|
|
|
# if nothing is selected
|
2007-04-02 09:26:30 +05:30
|
|
|
if not node:
|
2007-03-28 09:03:11 +05:30
|
|
|
self.connect.set_sensitive(False)
|
2007-03-29 08:51:54 +05:30
|
|
|
self.rename.set_sensitive(False)
|
2008-04-12 02:30:36 +05:30
|
|
|
self.rcs.set_sensitive(False)
|
|
|
|
self.repair.set_sensitive(False)
|
2007-04-02 09:26:30 +05:30
|
|
|
self.remove.set_sensitive(False)
|
2008-04-12 02:30:36 +05:30
|
|
|
return
|
|
|
|
|
|
|
|
path = self.model.get_path(node)
|
|
|
|
if path is None:
|
|
|
|
return
|
|
|
|
|
2012-06-18 02:55:37 +05:30
|
|
|
is_rev = len(path.get_indices()) > 1
|
2008-08-13 02:35:11 +05:30
|
|
|
self.rcs.set_label(RCS_BUTTON[is_rev])
|
2008-04-12 02:30:36 +05:30
|
|
|
|
2012-06-18 02:55:37 +05:30
|
|
|
if store.get_value(node, STOCK_COL) == Gtk.STOCK_OPEN:
|
2008-06-02 02:27:11 +05:30
|
|
|
self.connect.set_sensitive(False)
|
|
|
|
if _RCS_FOUND:
|
2008-08-13 02:35:11 +05:30
|
|
|
self.rcs.set_sensitive(True)
|
2008-06-02 02:27:11 +05:30
|
|
|
else:
|
|
|
|
self.connect.set_sensitive(not is_rev)
|
|
|
|
if _RCS_FOUND and is_rev:
|
2008-08-13 02:35:11 +05:30
|
|
|
self.rcs.set_sensitive(True)
|
2008-06-02 02:27:11 +05:30
|
|
|
else:
|
2008-08-13 02:35:11 +05:30
|
|
|
self.rcs.set_sensitive(False)
|
2007-06-21 10:25:26 +05:30
|
|
|
|
2012-06-18 02:55:37 +05:30
|
|
|
if store.get_value(node, STOCK_COL) == Gtk.STOCK_DIALOG_ERROR:
|
2010-10-09 18:03:47 +05:30
|
|
|
path = get_unicode_path_from_env_var(store.get_value(node, PATH_COL))
|
2008-04-12 02:30:36 +05:30
|
|
|
backup = os.path.join(path, "person.gbkp")
|
|
|
|
self.repair.set_sensitive(os.path.isfile(backup))
|
|
|
|
else:
|
|
|
|
self.repair.set_sensitive(False)
|
|
|
|
|
2008-07-10 02:38:36 +05:30
|
|
|
self.rename.set_sensitive(True)
|
2008-04-12 02:30:36 +05:30
|
|
|
self.remove.set_sensitive(True)
|
2007-03-27 08:48:49 +05:30
|
|
|
|
2007-06-17 04:47:29 +05:30
|
|
|
def __build_interface(self):
|
2007-04-02 09:26:30 +05:30
|
|
|
"""
|
|
|
|
Builds the columns for the TreeView. The columns are:
|
|
|
|
|
|
|
|
Icon, Database Name, Last Modified
|
|
|
|
|
|
|
|
The Icon column gets its data from column 6 of the database model.
|
|
|
|
It is expecting either None, or a GTK stock icon name
|
|
|
|
|
|
|
|
The Database Name column is an editable column. We connect to the
|
|
|
|
'edited' signal, so that we can change the name when the user changes
|
|
|
|
the column.
|
|
|
|
|
2010-03-21 15:07:10 +05:30
|
|
|
The last accessed column simply displays the last time famtree was
|
|
|
|
opened.
|
2007-04-02 09:26:30 +05:30
|
|
|
"""
|
|
|
|
|
|
|
|
# build the database name column
|
2012-06-18 02:55:37 +05:30
|
|
|
render = Gtk.CellRendererText()
|
|
|
|
render.set_property('ellipsize', Pango.EllipsizeMode.END)
|
2007-06-17 04:47:29 +05:30
|
|
|
render.connect('edited', self.__change_name)
|
2008-01-10 02:49:36 +05:30
|
|
|
render.connect('editing-canceled', self.__stop_edit)
|
|
|
|
render.connect('editing-started', self.__start_edit)
|
2012-06-18 02:55:37 +05:30
|
|
|
self.column = Gtk.TreeViewColumn(_('Family tree name'), render,
|
2007-03-28 09:03:11 +05:30
|
|
|
text=NAME_COL)
|
2007-06-17 08:39:26 +05:30
|
|
|
self.column.set_sort_column_id(NAME_COL)
|
2007-06-23 10:01:05 +05:30
|
|
|
self.column.set_resizable(True)
|
|
|
|
self.column.set_min_width(275)
|
2007-03-28 09:03:11 +05:30
|
|
|
self.dblist.append_column(self.column)
|
2008-04-12 00:58:00 +05:30
|
|
|
self.name_renderer = render
|
2008-04-11 18:42:11 +05:30
|
|
|
|
2007-06-19 09:29:10 +05:30
|
|
|
# build the icon column
|
2012-06-18 02:55:37 +05:30
|
|
|
render = Gtk.CellRendererPixbuf()
|
|
|
|
icon_column = Gtk.TreeViewColumn(_('Status'), render,
|
2007-06-19 09:29:10 +05:30
|
|
|
stock_id=STOCK_COL)
|
|
|
|
self.dblist.append_column(icon_column)
|
|
|
|
|
2010-03-21 15:07:10 +05:30
|
|
|
# build the last accessed column
|
2012-06-18 02:55:37 +05:30
|
|
|
render = Gtk.CellRendererText()
|
|
|
|
column = Gtk.TreeViewColumn(_('Last accessed'), render, text=DATE_COL)
|
2007-06-17 08:39:26 +05:30
|
|
|
column.set_sort_column_id(DSORT_COL)
|
2007-03-27 08:48:49 +05:30
|
|
|
self.dblist.append_column(column)
|
2007-04-02 09:26:30 +05:30
|
|
|
|
|
|
|
# set the rules hit
|
2007-03-27 08:48:49 +05:30
|
|
|
self.dblist.set_rules_hint(True)
|
|
|
|
|
2007-06-17 04:47:29 +05:30
|
|
|
def __populate(self):
|
2007-12-28 Benny Malengier <benny.malengier@gramps-project.org>
* src/ViewManager.py: remove unused functions, add alt actions left/right
* src/GrampsDb: deleted with _GrampsDbWriteXML.py,
_GrampsDbFactories.py, _GrampsGEDDB.py, _GrampsXMLDB.py,
__init__.py, Makefile.am, _GrampsInMemDB.py, _GrampsBSDDB.py.
No more inmemory databases
* src/GrampsDbUtils: moved here _GrampsDbWriteXML.py and _GrampsBSDDB.py
* src/plugins/ReadGrdb.py:
* src/plugins/Checkpoint.py:
* src/ObjectSelector/_ObjectSelectorWindow.py:
* src/DbManager.py:
* src/GrampsDbUtils/_WriteGrdb.py:
* src/GrampsDbUtils/__init__.py:
* src/GrampsDbUtils/_GrampsDbWRFactories.py:
* src/GrampsDbUtils/_WriteXML.py:
* src/GrampsDbUtils/Makefile.am:
* src/gramps_main.py:
* src/RecentFiles.py: recent-files-gramps.xml, don't overwrite 2.2.x data
* src/ArgHandler.py:
* src/DbLoader.py: remove unused functions
* src/Makefile.am:
* po/POTFILES.in:
* src/GrampsDbUtils/importdbdir.py: allow import of new database via cli
Remove inMem Editing, move remaining to DbUtils, fix ArgHandler
svn: r9613
2007-12-28 20:39:01 +05:30
|
|
|
"""
|
|
|
|
Builds the data and the display model.
|
|
|
|
"""
|
|
|
|
self._populate_cli()
|
|
|
|
self._populate_model()
|
|
|
|
|
|
|
|
def _populate_model(self):
|
2007-04-02 09:26:30 +05:30
|
|
|
"""
|
|
|
|
Builds the display model.
|
|
|
|
"""
|
2012-06-18 02:55:37 +05:30
|
|
|
self.model = Gtk.TreeStore(str, str, str, str, int, bool, str)
|
2007-03-27 08:48:49 +05:30
|
|
|
|
2007-12-28 Benny Malengier <benny.malengier@gramps-project.org>
* src/ViewManager.py: remove unused functions, add alt actions left/right
* src/GrampsDb: deleted with _GrampsDbWriteXML.py,
_GrampsDbFactories.py, _GrampsGEDDB.py, _GrampsXMLDB.py,
__init__.py, Makefile.am, _GrampsInMemDB.py, _GrampsBSDDB.py.
No more inmemory databases
* src/GrampsDbUtils: moved here _GrampsDbWriteXML.py and _GrampsBSDDB.py
* src/plugins/ReadGrdb.py:
* src/plugins/Checkpoint.py:
* src/ObjectSelector/_ObjectSelectorWindow.py:
* src/DbManager.py:
* src/GrampsDbUtils/_WriteGrdb.py:
* src/GrampsDbUtils/__init__.py:
* src/GrampsDbUtils/_GrampsDbWRFactories.py:
* src/GrampsDbUtils/_WriteXML.py:
* src/GrampsDbUtils/Makefile.am:
* src/gramps_main.py:
* src/RecentFiles.py: recent-files-gramps.xml, don't overwrite 2.2.x data
* src/ArgHandler.py:
* src/DbLoader.py: remove unused functions
* src/Makefile.am:
* po/POTFILES.in:
* src/GrampsDbUtils/importdbdir.py: allow import of new database via cli
Remove inMem Editing, move remaining to DbUtils, fix ArgHandler
svn: r9613
2007-12-28 20:39:01 +05:30
|
|
|
#use current names to set up the model
|
2007-03-28 09:35:16 +05:30
|
|
|
for items in self.current_names:
|
2009-05-06 20:14:22 +05:30
|
|
|
data = list(items[:7])
|
2008-04-10 07:11:47 +05:30
|
|
|
node = self.model.append(None, data)
|
|
|
|
for rdata in find_revisions(os.path.join(items[1], ARCHIVE_V)):
|
|
|
|
data = [ rdata[2], rdata[0], items[1], rdata[1], 0, False, "" ]
|
2007-06-21 05:06:09 +05:30
|
|
|
self.model.append(node, data)
|
2007-03-27 08:48:49 +05:30
|
|
|
self.dblist.set_model(self.model)
|
|
|
|
|
2008-01-10 02:49:36 +05:30
|
|
|
def existing_name(self, name, skippath=None):
|
|
|
|
"""
|
2008-02-24 19:25:55 +05:30
|
|
|
Return true if a name is present in the model already.
|
2008-01-10 02:49:36 +05:30
|
|
|
If skippath given, the name of skippath is not considered
|
|
|
|
"""
|
|
|
|
iter = self.model.get_iter_first()
|
|
|
|
while (iter):
|
|
|
|
path = self.model.get_path(iter)
|
2012-06-18 02:55:37 +05:30
|
|
|
iter = self.model.iter_next(iter)
|
2008-01-10 02:49:36 +05:30
|
|
|
if path == skippath:
|
|
|
|
continue
|
|
|
|
itername = self.model.get_value(iter, NAME_COL)
|
|
|
|
if itername.strip() == name.strip():
|
|
|
|
return True
|
|
|
|
return False
|
|
|
|
|
2007-03-27 08:48:49 +05:30
|
|
|
def run(self):
|
2007-04-02 09:26:30 +05:30
|
|
|
"""
|
|
|
|
Runs the dialog, returning None if nothing has been chosen,
|
|
|
|
or the path and name if something has been selected
|
|
|
|
"""
|
2008-04-01 02:22:58 +05:30
|
|
|
while True:
|
|
|
|
value = self.top.run()
|
2012-06-18 02:55:37 +05:30
|
|
|
if value == Gtk.ResponseType.OK:
|
2008-04-01 02:22:58 +05:30
|
|
|
store, node = self.selection.get_selected()
|
|
|
|
# don't open a locked file
|
|
|
|
if store.get_value(node, STOCK_COL) == 'gramps-lock':
|
|
|
|
self.__ask_to_break_lock(store, node)
|
|
|
|
continue
|
|
|
|
# don't open a version
|
2012-06-18 02:55:37 +05:30
|
|
|
if len(store.get_path(node).get_indices()) > 1:
|
2008-04-01 02:22:58 +05:30
|
|
|
continue
|
|
|
|
if node:
|
|
|
|
self.top.destroy()
|
2009-02-22 02:34:09 +05:30
|
|
|
del self.selection
|
|
|
|
del self.name_renderer
|
2010-10-09 18:03:47 +05:30
|
|
|
path = get_unicode_path_from_env_var(store.get_value(node, PATH_COL))
|
|
|
|
return (path, store.get_value(node, NAME_COL))
|
2008-04-01 02:22:58 +05:30
|
|
|
else:
|
2007-03-27 08:48:49 +05:30
|
|
|
self.top.destroy()
|
2009-02-22 02:34:09 +05:30
|
|
|
del self.selection
|
|
|
|
del self.name_renderer
|
2008-04-01 02:22:58 +05:30
|
|
|
return None
|
2007-03-27 08:48:49 +05:30
|
|
|
|
2007-06-21 05:06:09 +05:30
|
|
|
def __ask_to_break_lock(self, store, node):
|
2007-06-23 10:01:05 +05:30
|
|
|
"""
|
|
|
|
Prompts the user for permission to break the lock file that another
|
|
|
|
process has set on the file.
|
|
|
|
"""
|
2007-06-21 05:06:09 +05:30
|
|
|
path = store.get_path(node)
|
|
|
|
self.lock_file = store[path][PATH_COL]
|
|
|
|
|
2008-02-18 15:39:50 +05:30
|
|
|
QuestionDialog(
|
2007-06-21 05:06:09 +05:30
|
|
|
_("Break the lock on the '%s' database?") % store[path][0],
|
2009-11-18 01:44:53 +05:30
|
|
|
_("Gramps believes that someone else is actively editing "
|
2007-06-21 05:06:09 +05:30
|
|
|
"this database. You cannot edit this database while it "
|
|
|
|
"is locked. If no one is editing the database you may "
|
|
|
|
"safely break the lock. However, if someone else is editing "
|
|
|
|
"the database and you break the lock, you may corrupt the "
|
|
|
|
"database."),
|
|
|
|
_("Break lock"),
|
2012-07-04 17:42:18 +05:30
|
|
|
self.__really_break_lock, self.top)
|
2007-06-21 05:06:09 +05:30
|
|
|
|
|
|
|
def __really_break_lock(self):
|
2007-06-23 10:01:05 +05:30
|
|
|
"""
|
|
|
|
Deletes the lock file associated with the selected database, then updates
|
|
|
|
the display appropriately.
|
|
|
|
"""
|
2007-06-21 05:06:09 +05:30
|
|
|
try:
|
2008-01-28 16:46:54 +05:30
|
|
|
self.break_lock(self.lock_file)
|
2007-06-21 05:06:09 +05:30
|
|
|
store, node = self.selection.get_selected()
|
2010-10-09 18:03:47 +05:30
|
|
|
dbpath = get_unicode_path_from_env_var(store.get_value(node, PATH_COL))
|
2007-06-21 05:06:09 +05:30
|
|
|
(tval, last) = time_val(dbpath)
|
|
|
|
store.set_value(node, OPEN_COL, 0)
|
|
|
|
store.set_value(node, STOCK_COL, "")
|
|
|
|
store.set_value(node, DATE_COL, last)
|
|
|
|
store.set_value(node, DSORT_COL, tval)
|
2007-09-11 03:44:33 +05:30
|
|
|
except IOError:
|
2007-06-23 10:01:05 +05:30
|
|
|
return
|
2007-06-21 05:06:09 +05:30
|
|
|
|
2008-01-10 02:49:36 +05:30
|
|
|
def __stop_edit(self, *args):
|
2008-04-12 00:58:00 +05:30
|
|
|
self.name_renderer.set_property('editable', False)
|
2008-01-10 02:49:36 +05:30
|
|
|
self.__update_buttons(self.selection)
|
|
|
|
|
|
|
|
def __start_edit(self, *args):
|
|
|
|
"""
|
|
|
|
Do no allow to click Load while changing name, to force users to finish
|
|
|
|
the action of renaming. Hack around the fact that clicking button
|
|
|
|
sends a 'editing-canceled' signal loosing the new name
|
|
|
|
"""
|
|
|
|
self.connect.set_sensitive(False)
|
2008-04-12 02:30:36 +05:30
|
|
|
self.rename.set_sensitive(False)
|
2008-01-10 02:49:36 +05:30
|
|
|
|
|
|
|
def __change_name(self, renderer_sel, path, new_text):
|
2007-04-02 09:26:30 +05:30
|
|
|
"""
|
2008-02-24 19:25:55 +05:30
|
|
|
Change the name of the database. This is a callback from the
|
2007-04-02 09:26:30 +05:30
|
|
|
column, which has been marked as editable.
|
|
|
|
|
2007-12-19 22:09:36 +05:30
|
|
|
If the new string is empty, do nothing. Otherwise, renaming the
|
2007-04-02 09:26:30 +05:30
|
|
|
database is simply changing the contents of the name file.
|
|
|
|
"""
|
2012-06-18 02:55:37 +05:30
|
|
|
#path is a string, convert to TreePath first
|
|
|
|
path = Gtk.TreePath(path=path)
|
2008-01-10 02:49:36 +05:30
|
|
|
if len(new_text) > 0:
|
|
|
|
node = self.model.get_iter(path)
|
|
|
|
old_text = self.model.get_value(node, NAME_COL)
|
|
|
|
if not old_text.strip() == new_text.strip():
|
2012-06-18 02:55:37 +05:30
|
|
|
if len(path.get_indices()) > 1 :
|
2008-01-10 02:49:36 +05:30
|
|
|
self.__rename_revision(path, new_text)
|
2007-12-19 22:09:36 +05:30
|
|
|
else:
|
|
|
|
self.__rename_database(path, new_text)
|
2008-04-12 00:58:00 +05:30
|
|
|
|
|
|
|
self.name_renderer.set_property('editable', False)
|
2008-01-10 02:49:36 +05:30
|
|
|
self.__update_buttons(self.selection)
|
2007-06-21 05:06:09 +05:30
|
|
|
|
|
|
|
def __rename_revision(self, path, new_text):
|
2007-06-23 10:01:05 +05:30
|
|
|
"""
|
|
|
|
Renames the RCS revision using the rcs command. The rcs command
|
|
|
|
is in the format of:
|
|
|
|
|
|
|
|
rcs -mREV:NEW_NAME archive
|
|
|
|
|
|
|
|
"""
|
2007-06-21 05:06:09 +05:30
|
|
|
node = self.model.get_iter(path)
|
|
|
|
db_dir = self.model.get_value(node, FILE_COL)
|
|
|
|
rev = self.model.get_value(node, PATH_COL)
|
|
|
|
archive = os.path.join(db_dir, ARCHIVE_V)
|
|
|
|
|
2008-06-02 02:07:56 +05:30
|
|
|
cmd = [ "rcs", "-x,v", "-m%s:%s" % (rev, new_text), archive ]
|
2007-06-21 05:06:09 +05:30
|
|
|
|
|
|
|
proc = subprocess.Popen(cmd, stderr = subprocess.PIPE)
|
|
|
|
status = proc.wait()
|
|
|
|
message = "\n".join(proc.stderr.readlines())
|
|
|
|
proc.stderr.close()
|
|
|
|
del proc
|
|
|
|
|
|
|
|
if status != 0:
|
2011-02-17 00:08:01 +05:30
|
|
|
DbManager.ERROR(
|
2007-06-21 05:06:09 +05:30
|
|
|
_("Rename failed"),
|
|
|
|
_("An attempt to rename a version failed "
|
|
|
|
"with the following message:\n\n%s") % message
|
|
|
|
)
|
|
|
|
else:
|
|
|
|
self.model.set_value(node, NAME_COL, new_text)
|
|
|
|
|
|
|
|
def __rename_database(self, path, new_text):
|
2007-06-23 10:01:05 +05:30
|
|
|
"""
|
|
|
|
Renames the database by writing the new value to the name.txt file
|
|
|
|
"""
|
2008-01-10 02:49:36 +05:30
|
|
|
new_text = new_text.strip()
|
2007-06-21 05:06:09 +05:30
|
|
|
node = self.model.get_iter(path)
|
|
|
|
filename = self.model.get_value(node, FILE_COL)
|
2008-01-10 02:49:36 +05:30
|
|
|
if self.existing_name(new_text, skippath=path):
|
2011-02-17 00:08:01 +05:30
|
|
|
DbManager.ERROR(_("Could not rename the Family Tree."),
|
2011-01-30 21:58:54 +05:30
|
|
|
_("Family Tree already exists, choose a unique name."))
|
2008-01-10 02:49:36 +05:30
|
|
|
return
|
2011-01-30 21:58:54 +05:30
|
|
|
old_text, new_text = self.rename_database(filename, new_text)
|
|
|
|
if not (old_text is None):
|
2012-06-08 01:47:11 +05:30
|
|
|
rename_filename(old_text, new_text)
|
2007-06-21 05:06:09 +05:30
|
|
|
self.model.set_value(node, NAME_COL, new_text)
|
2007-03-27 08:48:49 +05:30
|
|
|
|
2007-06-19 09:29:10 +05:30
|
|
|
def __rcs(self, obj):
|
2007-06-23 10:01:05 +05:30
|
|
|
"""
|
|
|
|
Callback for the RCS button. If the tree path is > 1, then we are
|
|
|
|
on an RCS revision, in which case we can check out. If not, then
|
|
|
|
we can only check in.
|
|
|
|
"""
|
2007-06-19 09:29:10 +05:30
|
|
|
store, node = self.selection.get_selected()
|
2007-06-21 05:06:09 +05:30
|
|
|
tree_path = store.get_path(node)
|
2012-06-18 02:55:37 +05:30
|
|
|
if len(tree_path.get_indices()) > 1:
|
2007-06-21 05:06:09 +05:30
|
|
|
parent_node = store.get_iter((tree_path[0],))
|
|
|
|
parent_name = store.get_value(parent_node, NAME_COL)
|
|
|
|
name = store.get_value(node, NAME_COL)
|
|
|
|
revision = store.get_value(node, PATH_COL)
|
|
|
|
db_path = store.get_value(node, FILE_COL)
|
|
|
|
|
2007-06-23 10:01:05 +05:30
|
|
|
self.__checkout_copy(parent_name, name, revision, db_path)
|
2007-06-21 05:06:09 +05:30
|
|
|
else:
|
|
|
|
base_path = self.dbstate.db.get_save_path()
|
|
|
|
archive = os.path.join(base_path, ARCHIVE)
|
2012-05-18 06:51:30 +05:30
|
|
|
check_in(self.dbstate.db, archive, User(), self.__start_cursor)
|
2007-06-21 05:06:09 +05:30
|
|
|
self.__end_cursor()
|
2007-06-23 10:01:05 +05:30
|
|
|
|
|
|
|
self.__populate()
|
|
|
|
|
|
|
|
def __checkout_copy(self, parent_name, name, revision, db_path):
|
|
|
|
"""
|
2008-02-24 19:25:55 +05:30
|
|
|
Create a new database, then extracts a revision from RCS and
|
2007-06-23 10:01:05 +05:30
|
|
|
imports it into the db
|
|
|
|
"""
|
2008-01-08 03:33:57 +05:30
|
|
|
new_path, newname = self._create_new_db("%s : %s" % (parent_name, name))
|
2007-06-19 09:29:10 +05:30
|
|
|
|
2007-06-23 10:01:05 +05:30
|
|
|
self.__start_cursor(_("Extracting archive..."))
|
2009-12-23 21:25:58 +05:30
|
|
|
dbclass = DbBsddb
|
2008-03-03 03:04:51 +05:30
|
|
|
dbase = dbclass()
|
2007-06-23 10:01:05 +05:30
|
|
|
dbase.load(new_path, None)
|
|
|
|
|
|
|
|
self.__start_cursor(_("Importing archive..."))
|
2012-05-18 02:27:23 +05:30
|
|
|
check_out(dbase, revision, db_path, User())
|
2007-06-23 10:01:05 +05:30
|
|
|
self.__end_cursor()
|
|
|
|
dbase.close()
|
|
|
|
|
2007-06-17 04:47:29 +05:30
|
|
|
def __remove_db(self, obj):
|
2007-04-02 09:26:30 +05:30
|
|
|
"""
|
|
|
|
Callback associated with the Remove button. Get the selected
|
|
|
|
row and data, then call the verification dialog.
|
|
|
|
"""
|
|
|
|
store, node = self.selection.get_selected()
|
2007-06-21 05:06:09 +05:30
|
|
|
path = store.get_path(node)
|
|
|
|
self.data_to_delete = store[path]
|
|
|
|
|
2012-06-18 02:55:37 +05:30
|
|
|
if len(path.get_indices()) == 1:
|
2008-02-18 15:39:50 +05:30
|
|
|
QuestionDialog(
|
2008-02-29 04:02:40 +05:30
|
|
|
_("Remove the '%s' family tree?") % self.data_to_delete[0],
|
|
|
|
_("Removing this family tree will permanently destroy the data."),
|
|
|
|
_("Remove family tree"),
|
2007-06-21 05:06:09 +05:30
|
|
|
self.__really_delete_db)
|
|
|
|
else:
|
|
|
|
rev = self.data_to_delete[0]
|
|
|
|
parent = store[(path[0],)][0]
|
2008-02-18 15:39:50 +05:30
|
|
|
QuestionDialog(
|
2007-12-20 15:33:05 +05:30
|
|
|
_("Remove the '%(revision)s' version of '%(database)s'") % {
|
2007-06-25 10:27:53 +05:30
|
|
|
'revision' : rev,
|
|
|
|
'database' : parent
|
|
|
|
},
|
2007-06-21 05:06:09 +05:30
|
|
|
_("Removing this version will prevent you from "
|
2007-06-21 11:29:19 +05:30
|
|
|
"extracting it in the future."),
|
2007-06-21 05:06:09 +05:30
|
|
|
_("Remove version"),
|
|
|
|
self.__really_delete_version)
|
2007-03-27 08:48:49 +05:30
|
|
|
|
2007-06-17 04:47:29 +05:30
|
|
|
def __really_delete_db(self):
|
2007-04-02 09:26:30 +05:30
|
|
|
"""
|
2009-08-09 22:39:32 +05:30
|
|
|
Delete the selected database. If the database is open, close it first.
|
2007-04-02 09:26:30 +05:30
|
|
|
Then scan the database directory, deleting the files, and finally
|
|
|
|
removing the directory.
|
|
|
|
"""
|
2007-03-27 08:48:49 +05:30
|
|
|
|
2007-04-02 09:26:30 +05:30
|
|
|
# close the database if the user has requested to delete the
|
|
|
|
# active database
|
2012-01-09 23:35:25 +05:30
|
|
|
if self.data_to_delete[PATH_COL] == self.active:
|
2007-04-02 09:26:30 +05:30
|
|
|
self.dbstate.no_database()
|
|
|
|
|
2007-12-19 22:09:36 +05:30
|
|
|
store, node = self.selection.get_selected()
|
|
|
|
path = store.get_path(node)
|
|
|
|
node = self.model.get_iter(path)
|
|
|
|
filename = self.model.get_value(node, FILE_COL)
|
2007-04-02 09:26:30 +05:30
|
|
|
try:
|
2007-12-19 22:09:36 +05:30
|
|
|
name_file = open(filename, "r")
|
|
|
|
file_name_to_delete=name_file.read()
|
|
|
|
name_file.close()
|
2012-06-08 01:47:11 +05:30
|
|
|
remove_filename(file_name_to_delete)
|
2007-04-02 09:26:30 +05:30
|
|
|
for (top, dirs, files) in os.walk(self.data_to_delete[1]):
|
|
|
|
for filename in files:
|
|
|
|
os.unlink(os.path.join(top, filename))
|
|
|
|
os.rmdir(self.data_to_delete[1])
|
|
|
|
except (IOError, OSError), msg:
|
2011-02-17 00:08:01 +05:30
|
|
|
DbManager.ERROR(_("Could not delete family tree"),
|
2007-04-02 09:26:30 +05:30
|
|
|
str(msg))
|
2007-06-21 05:06:09 +05:30
|
|
|
# rebuild the display
|
|
|
|
self.__populate()
|
|
|
|
|
|
|
|
def __really_delete_version(self):
|
|
|
|
"""
|
2009-08-09 22:39:32 +05:30
|
|
|
Delete the selected database. If the database is open, close it first.
|
2007-06-21 05:06:09 +05:30
|
|
|
Then scan the database directory, deleting the files, and finally
|
|
|
|
removing the directory.
|
|
|
|
"""
|
|
|
|
db_dir = self.data_to_delete[FILE_COL]
|
|
|
|
rev = self.data_to_delete[PATH_COL]
|
|
|
|
archive = os.path.join(db_dir, ARCHIVE_V)
|
|
|
|
|
2008-06-02 02:07:56 +05:30
|
|
|
cmd = [ "rcs", "-x,v", "-o%s" % rev, "-q", archive ]
|
2007-06-21 05:06:09 +05:30
|
|
|
|
|
|
|
proc = subprocess.Popen(cmd, stderr = subprocess.PIPE)
|
|
|
|
status = proc.wait()
|
|
|
|
message = "\n".join(proc.stderr.readlines())
|
|
|
|
proc.stderr.close()
|
|
|
|
del proc
|
|
|
|
|
|
|
|
if status != 0:
|
2011-02-17 00:08:01 +05:30
|
|
|
DbManager.ERROR(
|
2007-06-21 05:06:09 +05:30
|
|
|
_("Deletion failed"),
|
|
|
|
_("An attempt to delete a version failed "
|
|
|
|
"with the following message:\n\n%s") % message
|
|
|
|
)
|
|
|
|
|
|
|
|
# rebuild the display
|
|
|
|
self.__populate()
|
2007-04-02 09:26:30 +05:30
|
|
|
|
2007-06-17 04:47:29 +05:30
|
|
|
def __rename_db(self, obj):
|
2007-04-02 09:26:30 +05:30
|
|
|
"""
|
|
|
|
Start the rename process by calling the start_editing option on
|
|
|
|
the line with the cursor.
|
|
|
|
"""
|
2007-03-29 08:51:54 +05:30
|
|
|
store, node = self.selection.get_selected()
|
|
|
|
path = self.model.get_path(node)
|
2008-04-12 00:58:00 +05:30
|
|
|
self.name_renderer.set_property('editable', True)
|
2012-07-04 17:42:18 +05:30
|
|
|
self.dblist.set_cursor(path, self.column, True)
|
2007-03-29 08:51:54 +05:30
|
|
|
|
2007-06-17 04:47:29 +05:30
|
|
|
def __repair_db(self, obj):
|
2007-06-12 09:59:15 +05:30
|
|
|
"""
|
2007-12-19 22:09:36 +05:30
|
|
|
Start the repair process by calling the start_editing option on
|
2007-06-12 09:59:15 +05:30
|
|
|
the line with the cursor.
|
|
|
|
"""
|
|
|
|
store, node = self.selection.get_selected()
|
|
|
|
dirname = store[node][1]
|
2010-11-05 01:13:35 +05:30
|
|
|
|
|
|
|
#First ask user if he is really sure :-)
|
|
|
|
yes_no = QuestionDialog2(
|
|
|
|
_("Repair family tree?"),
|
|
|
|
_(
|
2010-11-06 14:00:51 +05:30
|
|
|
"If you click <b>Proceed</b>, Gramps will attempt to recover your family tree"
|
2010-11-05 01:13:35 +05:30
|
|
|
" from the last good backup. There are several ways this can cause unwanted"
|
2010-11-06 14:00:51 +05:30
|
|
|
" effects, so <b>backup</b> the family tree first.\n"
|
2010-11-05 01:13:35 +05:30
|
|
|
"The Family tree you have selected is stored in %s.\n\n"
|
2010-11-06 14:00:51 +05:30
|
|
|
"Before doing a repair, verify that the Family Tree can really no longer be "
|
|
|
|
" opened, as the database back-end can recover from some errors automatically.\n\n"
|
|
|
|
"<b>Details:</b> Repairing a Family Tree actually uses the last backup of"
|
|
|
|
" the Family Tree, which Gramps stored on last use. If you have worked for"
|
2010-11-05 01:13:35 +05:30
|
|
|
" several hours/days without closing Gramps, then all this information will"
|
2010-11-06 14:00:51 +05:30
|
|
|
" be lost! If the repair fails, then the original family tree will be lost"
|
|
|
|
" forever, hence a backup is needed. If the repair fails, or too much"
|
|
|
|
" information is lost, you can fix the original family tree manually."
|
|
|
|
" For details, see the webpage\n"
|
2010-11-05 01:13:35 +05:30
|
|
|
"http://gramps-project.org/wiki/index.php?title=Recover_corrupted_family_tree\n"
|
2010-11-06 14:00:51 +05:30
|
|
|
"Before doing a repair, try to open the family tree in the normal manner."
|
|
|
|
" Several errors that trigger the repair button can be fixed automatically."
|
|
|
|
" If this is the case, you can disable the repair button by removing the"
|
|
|
|
" file <i>need_recover</i> in the family tree directory."
|
2010-11-05 01:13:35 +05:30
|
|
|
) % dirname,
|
2010-11-06 14:00:51 +05:30
|
|
|
_("Proceed, I have taken a backup"),
|
2010-11-05 01:13:35 +05:30
|
|
|
_("Stop"))
|
|
|
|
prompt = yes_no.run()
|
|
|
|
if not prompt:
|
|
|
|
return
|
|
|
|
|
2012-01-16 02:33:51 +05:30
|
|
|
opened = store[node][OPEN_COL]
|
2007-06-12 09:59:15 +05:30
|
|
|
if opened:
|
|
|
|
self.dbstate.no_database()
|
|
|
|
|
|
|
|
# delete files that are not backup files or the .txt file
|
|
|
|
for filename in os.listdir(dirname):
|
|
|
|
if os.path.splitext(filename)[1] not in (".gbkp", ".txt"):
|
2007-06-23 10:01:05 +05:30
|
|
|
fname = os.path.join(dirname, filename)
|
2007-06-14 09:56:46 +05:30
|
|
|
os.unlink(fname)
|
2007-06-12 09:59:15 +05:30
|
|
|
|
2009-12-23 21:25:58 +05:30
|
|
|
newdb = DbBsddb()
|
2008-04-21 02:29:29 +05:30
|
|
|
newdb.write_version(dirname)
|
|
|
|
|
2009-12-23 21:25:58 +05:30
|
|
|
dbclass = DbBsddb
|
2008-03-03 03:04:51 +05:30
|
|
|
dbase = dbclass()
|
2007-06-23 10:01:05 +05:30
|
|
|
dbase.set_save_path(dirname)
|
|
|
|
dbase.load(dirname, None)
|
2007-06-21 05:06:09 +05:30
|
|
|
|
|
|
|
self.__start_cursor(_("Rebuilding database from backup files"))
|
2009-12-20 10:00:28 +05:30
|
|
|
|
|
|
|
try:
|
|
|
|
restore(dbase)
|
2009-12-23 21:25:58 +05:30
|
|
|
except DbException, msg:
|
2011-02-17 00:08:01 +05:30
|
|
|
DbManager.ERROR(_("Error restoring backup data"), msg)
|
2009-12-20 10:00:28 +05:30
|
|
|
|
2007-06-21 05:06:09 +05:30
|
|
|
self.__end_cursor()
|
2007-06-14 09:50:44 +05:30
|
|
|
|
2007-06-23 10:01:05 +05:30
|
|
|
dbase.close()
|
2007-06-13 05:01:40 +05:30
|
|
|
self.dbstate.no_database()
|
2007-06-17 04:47:29 +05:30
|
|
|
self.__populate()
|
2007-06-12 09:59:15 +05:30
|
|
|
|
2007-06-21 05:06:09 +05:30
|
|
|
def __start_cursor(self, msg):
|
|
|
|
"""
|
2008-02-24 19:25:55 +05:30
|
|
|
Set the cursor to the busy state, and displays the associated
|
2007-06-21 05:06:09 +05:30
|
|
|
message
|
|
|
|
"""
|
|
|
|
self.msg.set_label(msg)
|
2012-06-18 02:55:37 +05:30
|
|
|
self.top.window.set_cursor(Gdk.Cursor.new(Gdk.CursorType.WATCH))
|
|
|
|
while (Gtk.events_pending()):
|
|
|
|
Gtk.main_iteration()
|
2007-06-21 05:06:09 +05:30
|
|
|
|
|
|
|
def __end_cursor(self):
|
|
|
|
"""
|
2008-02-24 19:25:55 +05:30
|
|
|
Set the cursor back to normal and clears the message
|
2007-06-21 05:06:09 +05:30
|
|
|
"""
|
|
|
|
self.top.window.set_cursor(None)
|
|
|
|
self.msg.set_label("")
|
|
|
|
|
2007-06-17 04:47:29 +05:30
|
|
|
def __new_db(self, obj):
|
2007-04-02 09:26:30 +05:30
|
|
|
"""
|
|
|
|
Callback wrapper around the actual routine that creates the
|
|
|
|
new database. Catch OSError and IOError and display a warning
|
|
|
|
message.
|
|
|
|
"""
|
2008-01-10 02:49:36 +05:30
|
|
|
self.new.set_sensitive(False)
|
2007-04-02 09:26:30 +05:30
|
|
|
try:
|
2008-01-08 03:33:57 +05:30
|
|
|
self._create_new_db()
|
2007-04-02 09:26:30 +05:30
|
|
|
except (OSError, IOError), msg:
|
2011-02-17 00:08:01 +05:30
|
|
|
DbManager.ERROR(_("Could not create family tree"),
|
2007-04-02 09:26:30 +05:30
|
|
|
str(msg))
|
2008-01-10 02:49:36 +05:30
|
|
|
self.new.set_sensitive(True)
|
2007-04-02 09:26:30 +05:30
|
|
|
|
2008-01-08 03:33:57 +05:30
|
|
|
def _create_new_db(self, title=None):
|
2007-04-02 09:26:30 +05:30
|
|
|
"""
|
2007-12-28 Benny Malengier <benny.malengier@gramps-project.org>
* src/ViewManager.py: remove unused functions, add alt actions left/right
* src/GrampsDb: deleted with _GrampsDbWriteXML.py,
_GrampsDbFactories.py, _GrampsGEDDB.py, _GrampsXMLDB.py,
__init__.py, Makefile.am, _GrampsInMemDB.py, _GrampsBSDDB.py.
No more inmemory databases
* src/GrampsDbUtils: moved here _GrampsDbWriteXML.py and _GrampsBSDDB.py
* src/plugins/ReadGrdb.py:
* src/plugins/Checkpoint.py:
* src/ObjectSelector/_ObjectSelectorWindow.py:
* src/DbManager.py:
* src/GrampsDbUtils/_WriteGrdb.py:
* src/GrampsDbUtils/__init__.py:
* src/GrampsDbUtils/_GrampsDbWRFactories.py:
* src/GrampsDbUtils/_WriteXML.py:
* src/GrampsDbUtils/Makefile.am:
* src/gramps_main.py:
* src/RecentFiles.py: recent-files-gramps.xml, don't overwrite 2.2.x data
* src/ArgHandler.py:
* src/DbLoader.py: remove unused functions
* src/Makefile.am:
* po/POTFILES.in:
* src/GrampsDbUtils/importdbdir.py: allow import of new database via cli
Remove inMem Editing, move remaining to DbUtils, fix ArgHandler
svn: r9613
2007-12-28 20:39:01 +05:30
|
|
|
Create a new database, append to model
|
2007-04-02 09:26:30 +05:30
|
|
|
"""
|
2009-06-19 14:16:17 +05:30
|
|
|
new_path, title = self.create_new_db_cli(title)
|
2007-03-27 08:48:49 +05:30
|
|
|
path_name = os.path.join(new_path, NAME_FILE)
|
2008-04-06 04:00:17 +05:30
|
|
|
(tval, last) = time_val(new_path)
|
2007-06-19 09:29:10 +05:30
|
|
|
node = self.model.append(None, [title, new_path, path_name,
|
2008-04-10 07:11:47 +05:30
|
|
|
last, tval, False, ''])
|
2007-03-28 09:03:11 +05:30
|
|
|
self.selection.select_iter(node)
|
|
|
|
path = self.model.get_path(node)
|
2008-04-12 02:30:36 +05:30
|
|
|
self.name_renderer.set_property('editable', True)
|
2012-07-04 17:42:18 +05:30
|
|
|
self.dblist.set_cursor(path, self.column, True)
|
2008-01-08 03:33:57 +05:30
|
|
|
return new_path, title
|
2007-04-02 09:26:30 +05:30
|
|
|
|
2007-07-09 06:48:04 +05:30
|
|
|
def __drag_data_received(self, widget, context, xpos, ypos, selection,
|
|
|
|
info, rtime):
|
|
|
|
"""
|
|
|
|
Handle the reception of drag data
|
|
|
|
"""
|
2012-07-27 20:35:46 +05:30
|
|
|
drag_value = selection.get_data()
|
2007-12-28 Benny Malengier <benny.malengier@gramps-project.org>
* src/ViewManager.py: remove unused functions, add alt actions left/right
* src/GrampsDb: deleted with _GrampsDbWriteXML.py,
_GrampsDbFactories.py, _GrampsGEDDB.py, _GrampsXMLDB.py,
__init__.py, Makefile.am, _GrampsInMemDB.py, _GrampsBSDDB.py.
No more inmemory databases
* src/GrampsDbUtils: moved here _GrampsDbWriteXML.py and _GrampsBSDDB.py
* src/plugins/ReadGrdb.py:
* src/plugins/Checkpoint.py:
* src/ObjectSelector/_ObjectSelectorWindow.py:
* src/DbManager.py:
* src/GrampsDbUtils/_WriteGrdb.py:
* src/GrampsDbUtils/__init__.py:
* src/GrampsDbUtils/_GrampsDbWRFactories.py:
* src/GrampsDbUtils/_WriteXML.py:
* src/GrampsDbUtils/Makefile.am:
* src/gramps_main.py:
* src/RecentFiles.py: recent-files-gramps.xml, don't overwrite 2.2.x data
* src/ArgHandler.py:
* src/DbLoader.py: remove unused functions
* src/Makefile.am:
* po/POTFILES.in:
* src/GrampsDbUtils/importdbdir.py: allow import of new database via cli
Remove inMem Editing, move remaining to DbUtils, fix ArgHandler
svn: r9613
2007-12-28 20:39:01 +05:30
|
|
|
fname = None
|
|
|
|
type = None
|
|
|
|
title = None
|
2011-12-09 19:55:39 +05:30
|
|
|
# Allow any type of URL ("file://", "http://", etc):
|
|
|
|
if drag_value and urlparse.urlparse(drag_value).scheme != "":
|
|
|
|
fname, title = [], []
|
|
|
|
for treename in [v.strip() for v in drag_value.split("\n") if v.strip() != '']:
|
2012-07-27 21:01:24 +05:30
|
|
|
f, t = self.import_new_db(treename, User())
|
2011-12-09 19:55:39 +05:30
|
|
|
fname.append(f)
|
|
|
|
title.append(t)
|
2008-11-04 09:42:51 +05:30
|
|
|
return fname, title
|
2007-07-09 03:50:10 +05:30
|
|
|
|
2007-09-11 03:44:33 +05:30
|
|
|
def drag_motion(wid, context, xpos, ypos, time_stamp):
|
|
|
|
"""
|
|
|
|
DND callback that is called on a DND drag motion begin
|
|
|
|
"""
|
2012-07-27 20:35:46 +05:30
|
|
|
Gdk.drag_status(context, Gdk.DragAction.COPY, time_stamp)
|
2007-09-11 03:44:33 +05:30
|
|
|
return True
|
|
|
|
|
|
|
|
def drop_cb(wid, context, xpos, ypos, time_stamp):
|
|
|
|
"""
|
|
|
|
DND callback that finishes the DND operation
|
|
|
|
"""
|
2012-07-27 20:35:46 +05:30
|
|
|
Gtk.drag_finish(context, True, False, time_stamp)
|
2007-09-11 03:44:33 +05:30
|
|
|
return True
|
|
|
|
|
2007-06-19 04:34:05 +05:30
|
|
|
def find_revisions(name):
|
2007-06-21 05:06:09 +05:30
|
|
|
"""
|
2009-08-09 22:39:32 +05:30
|
|
|
Finds all the revisions of the specified RCS archive.
|
2007-06-21 05:06:09 +05:30
|
|
|
"""
|
2007-06-19 04:34:05 +05:30
|
|
|
import re
|
|
|
|
|
|
|
|
rev = re.compile("\s*revision\s+([\d\.]+)")
|
2008-01-20 05:15:09 +05:30
|
|
|
date = re.compile("date:\s+(\d\d\d\d-\d\d-\d\d \d\d:\d\d:\d\d)[-+]\d\d;")
|
2007-06-19 09:29:10 +05:30
|
|
|
|
2008-06-02 02:27:11 +05:30
|
|
|
if not os.path.isfile(name) or not _RCS_FOUND:
|
2007-06-19 09:29:10 +05:30
|
|
|
return []
|
|
|
|
|
2008-06-02 02:07:56 +05:30
|
|
|
rlog = [ "rlog", "-x,v", "-zLT" , name ]
|
2007-06-19 04:34:05 +05:30
|
|
|
|
|
|
|
proc = subprocess.Popen(rlog, stdout = subprocess.PIPE)
|
|
|
|
proc.wait()
|
|
|
|
|
|
|
|
revlist = []
|
|
|
|
date_str = ""
|
|
|
|
rev_str = ""
|
2007-06-20 12:07:09 +05:30
|
|
|
com_str = ""
|
2007-06-19 04:34:05 +05:30
|
|
|
|
2007-06-20 12:07:09 +05:30
|
|
|
get_next = False
|
2007-06-19 04:34:05 +05:30
|
|
|
if os.path.isfile(name):
|
2007-06-20 12:07:09 +05:30
|
|
|
for line in proc.stdout:
|
|
|
|
match = rev.match(line)
|
2007-06-19 04:34:05 +05:30
|
|
|
if match:
|
2007-12-20 15:33:05 +05:30
|
|
|
rev_str = copy.copy(match.groups()[0])
|
2007-06-20 12:07:09 +05:30
|
|
|
continue
|
|
|
|
match = date.match(line)
|
|
|
|
if match:
|
2008-01-22 03:09:23 +05:30
|
|
|
date_str = time.strftime('%x %X',
|
|
|
|
time.strptime(match.groups()[0], '%Y-%m-%d %H:%M:%S'))
|
2007-06-20 12:07:09 +05:30
|
|
|
|
|
|
|
get_next = True
|
|
|
|
continue
|
|
|
|
if get_next:
|
|
|
|
get_next = False
|
|
|
|
com_str = line.strip()
|
|
|
|
revlist.append((rev_str, date_str, com_str))
|
2007-12-20 15:33:05 +05:30
|
|
|
proc.stdout.close()
|
|
|
|
del proc
|
2007-06-19 04:34:05 +05:30
|
|
|
return revlist
|
2007-06-19 09:29:10 +05:30
|
|
|
|
2009-06-19 03:26:37 +05:30
|
|
|
|
2007-06-23 10:01:05 +05:30
|
|
|
|
2012-05-18 02:27:23 +05:30
|
|
|
def check_out(dbase, rev, path, user):
|
2007-06-23 10:01:05 +05:30
|
|
|
"""
|
|
|
|
Checks out the revision from rcs, and loads the resulting XML file
|
|
|
|
into the database.
|
|
|
|
"""
|
2008-06-02 02:07:56 +05:30
|
|
|
co_cmd = [ "co", "-x,v", "-q%s" % rev] + [ os.path.join(path, ARCHIVE),
|
|
|
|
os.path.join(path, ARCHIVE_V)]
|
2007-06-21 05:06:09 +05:30
|
|
|
|
2007-06-23 10:01:05 +05:30
|
|
|
proc = subprocess.Popen(co_cmd, stderr = subprocess.PIPE)
|
2007-06-21 05:06:09 +05:30
|
|
|
status = proc.wait()
|
|
|
|
message = "\n".join(proc.stderr.readlines())
|
|
|
|
proc.stderr.close()
|
|
|
|
del proc
|
|
|
|
|
|
|
|
if status != 0:
|
2012-05-18 02:27:23 +05:30
|
|
|
user.notify_error(
|
2007-06-21 05:06:09 +05:30
|
|
|
_("Retrieve failed"),
|
|
|
|
_("An attempt to retrieve the data failed "
|
|
|
|
"with the following message:\n\n%s") % message
|
|
|
|
)
|
|
|
|
return
|
|
|
|
|
2009-10-25 19:22:29 +05:30
|
|
|
pmgr = GuiPluginManager.get_instance()
|
2008-11-04 09:42:51 +05:30
|
|
|
for plugin in pmgr.get_import_plugins():
|
|
|
|
if plugin.get_extension() == "gramps":
|
|
|
|
rdr = plugin.get_import_function()
|
|
|
|
|
2007-06-21 05:06:09 +05:30
|
|
|
xml_file = os.path.join(path, ARCHIVE)
|
2012-05-18 02:27:23 +05:30
|
|
|
rdr(dbase, xml_file, user)
|
2007-06-21 05:06:09 +05:30
|
|
|
os.unlink(xml_file)
|
|
|
|
|
2012-05-18 06:51:30 +05:30
|
|
|
def check_in(dbase, filename, user, cursor_func = None):
|
2007-06-23 10:01:05 +05:30
|
|
|
"""
|
|
|
|
Checks in the specified file into RCS
|
|
|
|
"""
|
2009-11-19 23:02:11 +05:30
|
|
|
init = [ "rcs", '-x,v', '-i', '-U', '-q', '-t-"Gramps database"' ]
|
2008-06-02 02:07:56 +05:30
|
|
|
ci_cmd = [ "ci", '-x,v', "-q", "-f" ]
|
|
|
|
archive_name = filename + ",v"
|
2009-05-06 20:14:22 +05:30
|
|
|
|
2009-07-20 05:28:32 +05:30
|
|
|
glade = Glade(toplevel='comment')
|
|
|
|
top = glade.toplevel
|
|
|
|
text = glade.get_object('description')
|
2007-06-20 09:26:39 +05:30
|
|
|
top.run()
|
|
|
|
comment = text.get_text()
|
|
|
|
top.destroy()
|
2007-06-19 09:29:10 +05:30
|
|
|
|
2008-06-02 02:07:56 +05:30
|
|
|
if not os.path.isfile(archive_name):
|
|
|
|
cmd = init + [archive_name]
|
|
|
|
proc = subprocess.Popen(cmd,
|
2007-06-20 10:23:30 +05:30
|
|
|
stderr = subprocess.PIPE)
|
2007-06-20 10:14:32 +05:30
|
|
|
status = proc.wait()
|
|
|
|
message = "\n".join(proc.stderr.readlines())
|
|
|
|
proc.stderr.close()
|
|
|
|
del proc
|
2008-06-02 02:07:56 +05:30
|
|
|
|
|
|
|
if status != 0:
|
|
|
|
ErrorDialog(
|
|
|
|
_("Archiving failed"),
|
|
|
|
_("An attempt to create the archive failed "
|
|
|
|
"with the following message:\n\n%s") % message
|
|
|
|
)
|
2007-06-19 09:29:10 +05:30
|
|
|
|
2007-06-21 05:06:09 +05:30
|
|
|
if cursor_func:
|
|
|
|
cursor_func(_("Creating data to be archived..."))
|
2009-02-09 10:40:58 +05:30
|
|
|
|
2009-10-25 19:22:29 +05:30
|
|
|
plugin_manager = GuiPluginManager.get_instance()
|
2009-02-09 10:40:58 +05:30
|
|
|
for plugin in plugin_manager.get_export_plugins():
|
|
|
|
if plugin.get_extension() == "gramps":
|
|
|
|
export_function = plugin.get_export_function()
|
2012-05-18 06:51:30 +05:30
|
|
|
export_function(dbase, filename, user)
|
2007-06-19 09:29:10 +05:30
|
|
|
|
2007-06-21 05:06:09 +05:30
|
|
|
if cursor_func:
|
|
|
|
cursor_func(_("Saving archive..."))
|
2008-06-02 02:07:56 +05:30
|
|
|
|
|
|
|
cmd = ci_cmd + ['-m%s' % comment, filename, archive_name ]
|
|
|
|
proc = subprocess.Popen(cmd,
|
|
|
|
stderr = subprocess.PIPE)
|
2007-06-23 10:01:05 +05:30
|
|
|
|
2007-12-19 22:09:36 +05:30
|
|
|
status = proc.wait()
|
2008-06-02 02:07:56 +05:30
|
|
|
message = "\n".join(proc.stderr.readlines())
|
2007-12-20 15:33:05 +05:30
|
|
|
proc.stderr.close()
|
2007-06-19 09:29:10 +05:30
|
|
|
del proc
|
2007-06-20 09:26:39 +05:30
|
|
|
|
2007-06-21 05:06:09 +05:30
|
|
|
if status != 0:
|
|
|
|
ErrorDialog(
|
|
|
|
_("Archiving failed"),
|
|
|
|
_("An attempt to archive the data failed "
|
|
|
|
"with the following message:\n\n%s") % message
|
|
|
|
)
|