diff --git a/ChangeLog b/ChangeLog index 9241f253d..f1a434938 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,8 @@ 2007-03-26 Don Allingham - + * src/ViewManager.py: integrate the new DbManager + * src/glade/gramps.glade: integrate the new DbManager + * src/gramps_main.py: integrate the new DbManager + * src/DbManager.py: integrate the new DbManager * src/DisplayModels/_PeopleModel.py (PeopleModel._build_search_sub): switch back to old format for handling cursor until bug can be resolved diff --git a/src/DbManager.py b/src/DbManager.py new file mode 100644 index 000000000..8525108a6 --- /dev/null +++ b/src/DbManager.py @@ -0,0 +1,200 @@ +# +# Gramps - a GTK+/GNOME based genealogy program +# +# Copyright (C) 2000-2006 Donald N. Allingham +# +# 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 +# + +# $Id: Bookmarks.py 8197 2007-02-20 20:56:48Z hippy $ + +"Handle bookmarks for the gramps interface" + +__author__ = "Donald N. Allingham" +__version__ = "$Revision: 8197 $" + +#------------------------------------------------------------------------- +# +# Standard python modules +# +#------------------------------------------------------------------------- +import const +import os +import time +from gettext import gettext as _ + +#------------------------------------------------------------------------- +# +# set up logging +# +#------------------------------------------------------------------------- +import logging +log = logging.getLogger(".Bookmarks") + +#------------------------------------------------------------------------- +# +# GTK/Gnome modules +# +#------------------------------------------------------------------------- +import gtk +import gtk.glade + +#------------------------------------------------------------------------- +# +# gramps modules +# +#------------------------------------------------------------------------- +import QuestionDialog + + +DEFAULT_DIR = os.path.expanduser("~/grampsdb") +DEFAULT_TITLE = _("Unnamed Database") +NAME_FILE = "name.txt" +META_NAME = "meta_data.db" + +NAME_COL = 0 +PATH_COL = 1 +FILE_COL = 2 +DATE_COL = 3 + +class DbManager: + + def __init__(self): + + self.glade = gtk.glade.XML(const.gladeFile, "dbmanager", "gramps") + self.top = self.glade.get_widget('dbmanager') + + self.connect = self.glade.get_widget('ok') + self.cancel = self.glade.get_widget('cancel') + self.new = self.glade.get_widget('new') + self.remove = self.glade.get_widget('remove') + self.dblist = self.glade.get_widget('dblist') + self.model = None + + self.connect_signals() + self.build_interface() + self.populate() + + def connect_signals(self): + self.remove.connect('clicked', self.remove_db) + self.new.connect('clicked', self.new_db) + + def build_interface(self): + render = gtk.CellRendererText() + render.set_property('editable',True) + render.connect('edited', self.change_name) + column = gtk.TreeViewColumn(_('Database name'), render, + text=NAME_COL) + self.dblist.append_column(column) + + render = gtk.CellRendererText() + column = gtk.TreeViewColumn(_('Last modified'), render, text=DATE_COL) + self.dblist.append_column(column) + self.dblist.set_rules_hint(True) + + def populate(self): + self.model = gtk.ListStore(str, str, str, str, int) + + sort_list = [] + for dpath in os.listdir(DEFAULT_DIR): + path_name = os.path.join(DEFAULT_DIR, dpath, NAME_FILE) + if os.path.isfile(path_name): + name = file(path_name).readline().strip() + + meta = os.path.join(DEFAULT_DIR, dpath, META_NAME) + if os.path.isfile(meta): + tval = int(time.time()) + last = time.asctime(time.localtime(time.time())) + else: + tval = 0 + last = _("Never") + + sort_list.append((name, + os.path.join(DEFAULT_DIR, dpath), + path_name, + last, + tval)) + + sort_list.sort() + for items in sort_list: + data = [items[0], items[1], items[2], items[3], items[4]] + self.model.append(data) + self.dblist.set_model(self.model) + + def run(self): + value = self.top.run() + if value == gtk.RESPONSE_OK: + (model, node) = self.dblist.get_selection().get_selected() + if node: + self.top.destroy() + return self.model.get_value(node, PATH_COL) + else: + self.top.destroy() + return None + else: + self.top.destroy() + return None + + def change_name(self, text, path, new_text): + if len(new_text) > 0: + iter = self.model.get_iter(path) + filename = self.model.get_value(iter, FILE_COL) + try: + f = open(filename, "w") + f.write(new_text) + f.close() + self.model.set_value(iter, NAME_COL, new_text) + except: + pass + + def remove_db(self, obj): + store, iter = self.dblist.get_selection().get_selected() + path = store.get_path(iter) + row = store[path] + self.data_to_delete = (row[0], row[1], row[2]) + + QuestionDialog.QuestionDialog( + _("Remove the '%s' database?") % self.data_to_delete[0], + _("Removing this database will permanently destroy " + "the data."), + _("Remove database"), + self.really_delete_db) + self.populate() + + def really_delete_db(self): + for (top, dirs, files) in os.walk(self.data_to_delete[1]): + for f in files: + os.unlink(os.path.join(top,f)) + os.rmdir(top) + + def new_db(self, obj): + while True: + base = "%x" % int(time.time()) + new_path = os.path.join(DEFAULT_DIR, base) + if not os.path.isdir(new_path): + break + + os.mkdir(new_path) + path_name = os.path.join(new_path, NAME_FILE) + title = DEFAULT_TITLE + f = open(path_name, "w") + f.write(title) + f.close() + node = self.model.append([title, new_path, path_name, _("Never"), 0]) + self.dblist.get_selection().select_iter(node) + +if __name__ == "__main__": + a = DbManager(None,None) + a.run() diff --git a/src/ViewManager.py b/src/ViewManager.py index 67c9016fa..ea668ba00 100644 --- a/src/ViewManager.py +++ b/src/ViewManager.py @@ -105,7 +105,6 @@ _KNOWN_FORMATS = { UIDEFAULT = ''' - @@ -167,8 +166,6 @@ UIDEFAULT = ''' - - @@ -279,30 +276,30 @@ class ViewManager: toolbar = self.uimanager.get_widget('/ToolBar') self.filter_menu = self.uimanager.get_widget('/MenuBar/ViewMenu/Filter/') - openbtn = gtk.MenuToolButton(gtk.STOCK_OPEN) + openbtn = gtk.MenuToolButton('gramps-db') openbtn.connect('clicked', self.open_activate) openbtn.set_sensitive(False) self.uistate.set_open_widget(openbtn) - toolbar.insert(openbtn, 1) + toolbar.insert(openbtn, 0) self.open_tips = gtk.Tooltips() openbtn.set_arrow_tooltip(self.open_tips, - _("Open a recently opened database"), - _("Open a recently opened database")) + _("Connect to a recent database"), + _("Connect to a recent database")) openbtn.set_tooltip(self.open_tips, - _("Open an existing database"), - _("Open an existing database") + _("Manage databases"), + _("Manage databases") ) openbtn.show() self.person_nav = Navigation.PersonNavigation(self.state, self.uistate) self._navigation_type[PageView.NAVIGATION_PERSON] = (self.person_nav, None) - self.recent_manager = DisplayState.RecentDocsMenu( - self.uistate, self.state, self.read_recent_file) - self.recent_manager.build() + #self.recent_manager = DisplayState.RecentDocsMenu( + # self.uistate, self.state, self.read_recent_file) + #self.recent_manager.build() self.db_loader = DbLoader(self.state, self.uistate) @@ -333,10 +330,8 @@ class ViewManager: def _init_lists(self): self._file_action_list = [ ('FileMenu', None, _('_File')), - ('New', gtk.STOCK_NEW, _('_New'), "n", - _("Create a new database"), self.new_activate), - ('Open', gtk.STOCK_OPEN, _('_Open'), "o", - _("Open an existing database"), self.open_activate), + ('Open', 'gramps-db', _('_Manage Databases'), "o", + _("Manage databases"), self.open_activate), ('OpenRecent', None, _('Open _Recent'), None, _("Open an existing database")), ('Quit', gtk.STOCK_QUIT, _('_Quit'), "q",None,self.quit), @@ -905,8 +900,91 @@ class ViewManager: self.post_load() def open_activate(self, obj): - (filename, filetype) = self.db_loader.open_file() - self.post_load_newdb(filename, filetype) + import DbManager + dialog = DbManager.DbManager() + filename = dialog.run() + if filename: + self.read_file(filename, 'x-directory/normal') + try: + os.chdir(os.path.dirname(filename)) + except: + pass + self.post_load_newdb(filename, 'x-directory/normal') + + def read_file(self, filename, filetype): + """ + This method takes care of changing database, and loading the data. + + This method should only return on success. + Returning on failure makes no sense, because we cannot recover, + since database has already beeen changed. + Therefore, any errors should raise exceptions. + + On success, return with the disabled signals. The post-load routine + should enable signals, as well as finish up with other UI goodies. + """ + + import GrampsDb + + if os.path.exists(filename): + if not os.access(filename, os.W_OK): + mode = "r" + QuestionDialog.WarningDialog(_('Read only database'), + _('You do not have write access ' + 'to the selected file.')) + else: + mode = "w" + elif filetype == 'unknown': + QuestionDialog.WarningDialog( + _('Missing or Invalid database'), + _('%s could not be found.\n' + 'It is possible that this file no longer exists ' + 'or has been moved.') % filename) + return False + else: + mode = 'w' + + try: + dbclass = GrampsDb.gramps_db_factory(db_type = filetype) + except GrampsDb.GrampsDbException, msg: + QuestionDialog.ErrorDialog( + _("Could not open file: %s") % filename, + _("This may be caused by an improper installation of GRAMPS.") + + "\n" + str(msg)) + return + + + self.state.change_database(dbclass(Config.get(Config.TRANSACTIONS))) + self.state.db.disable_signals() + + self.uistate.window.window.set_cursor(gtk.gdk.Cursor(gtk.gdk.WATCH)) + self.uistate.progress.show() + + try: + self.state.db.load(filename,self.uistate.pulse_progressbar,mode) + self.state.db.set_save_path(filename) + try: + os.chdir(os.path.dirname(filename)) + except: + print "could not change directory" + except DBRunRecoveryError, msg: + QuestionDialog.ErrorDialog( + _("Low level database corruption detected"), + _("GRAMPS has detected a problem in the underlying " + "Berkeley database. Please exit the program, and GRAMPS " + "will attempt to run the recovery repair operation " + "the next time you open this database. If this " + "problem persists, create a new database, import " + "from a backup database, and report the problem to " + "gramps-bugs@lists.sourceforge.net.")) + except (DBAccessError, DBPageNotFoundError,DBInvalidArgError), msg: + QuestionDialog.ErrorDialog( + _("Could not open file: %s") % filename, + str(msg[1])) + except Exception: + log.error("Failed to open database.", exc_info=True) + + return True def save_as_activate(self, obj): if self.state.db.db_is_open: @@ -977,7 +1055,7 @@ class ViewManager: self.state.db.enable_signals() self.state.signal_change() - Config.set(Config.RECENT_FILE, filename) + #Config.set(Config.RECENT_FILE, filename) self.relationship = self.RelClass(self.state.db) @@ -992,8 +1070,8 @@ class ViewManager: self.file_loaded = True - RecentFiles.recent_files(filename, filetype) - self.recent_manager.build() + #RecentFiles.recent_files(filename, filetype) + #self.recent_manager.build() # Call common post_load self.post_load() diff --git a/src/glade/gramps.glade b/src/glade/gramps.glade index e7db971f0..630749580 100644 --- a/src/glade/gramps.glade +++ b/src/glade/gramps.glade @@ -15415,4 +15415,152 @@ Very High + + 6 + True + GRAMPS - Database Manager + GTK_WINDOW_TOPLEVEL + GTK_WIN_POS_NONE + False + 500 + 250 + True + False + True + False + False + GDK_WINDOW_TYPE_HINT_DIALOG + GDK_GRAVITY_NORTH_WEST + True + False + False + + + + True + False + 0 + + + + True + GTK_BUTTONBOX_END + + + + True + True + True + gtk-close + True + GTK_RELIEF_NORMAL + True + -7 + + + + + + True + True + True + gtk-connect + True + GTK_RELIEF_NORMAL + True + -5 + + + + + 0 + False + True + GTK_PACK_END + + + + + + True + False + 0 + + + + True + True + GTK_POLICY_AUTOMATIC + GTK_POLICY_AUTOMATIC + GTK_SHADOW_IN + GTK_CORNER_TOP_LEFT + + + + True + True + True + False + False + True + False + False + False + + + + + 0 + True + True + + + + + + True + GTK_BUTTONBOX_SPREAD + 0 + + + + True + True + True + gtk-new + True + GTK_RELIEF_NORMAL + True + + + + + + True + True + True + gtk-remove + True + GTK_RELIEF_NORMAL + True + + + + + 6 + False + True + + + + + 0 + True + True + + + + + + diff --git a/src/gramps_main.py b/src/gramps_main.py index 5e73f49c4..a03c5a36a 100644 --- a/src/gramps_main.py +++ b/src/gramps_main.py @@ -94,6 +94,7 @@ def register_stock_icons (): ] items = [ + ('gramps-db',_('Databases'),gtk.gdk.CONTROL_MASK,0,''), ('gramps-address',_('Address'),gtk.gdk.CONTROL_MASK,0,''), ('gramps-attribute',_('Attribute'),gtk.gdk.CONTROL_MASK,0,''), #('gramps-bookmark',_('Bookmarks'),gtk.gdk.CONTROL_MASK,0,''),