From 40f355e17d2da4fd95f5f3c226da9c8725dadee0 Mon Sep 17 00:00:00 2001 From: Alex Roitman Date: Wed, 10 May 2006 05:52:55 +0000 Subject: [PATCH] * src/GrampsDb/_GrampsBSDDB.py (load_from): Add method. * src/GrampsDb/_GrampsXMLDB.py (load_from): Add method. * src/GrampsDb/_GrampsGEDDB.py (load_from): Add method. * src/GrampsDb/_GrampsDbBase.py (load_from): Add method. * src/GrampsDb/_WriteGrdb.py: Use db_copy. * src/GrampsDb/_DbUtils.py (db_copy): Add function. * src/ViewManager.py: Save as support. * src/DataViews/_MapView.py (enable_debug): Set to False to be able to see the output besides MapView. svn: r6604 --- ChangeLog | 10 +++ src/DataViews/_MapView.py | 2 +- src/GrampsDb/_DbUtils.py | 92 +++++++++++++++++++++++ src/GrampsDb/_GrampsBSDDB.py | 11 ++- src/GrampsDb/_GrampsDbBase.py | 8 ++ src/GrampsDb/_GrampsGEDDB.py | 12 +++ src/GrampsDb/_GrampsXMLDB.py | 12 +++ src/GrampsDb/_WriteGrdb.py | 86 +-------------------- src/ViewManager.py | 136 +++++++++++++++++++++++++++++++++- 9 files changed, 281 insertions(+), 88 deletions(-) diff --git a/ChangeLog b/ChangeLog index 063500119..4930dd827 100644 --- a/ChangeLog +++ b/ChangeLog @@ -8,6 +8,16 @@ the session 2006-05-09 Alex Roitman + * src/GrampsDb/_GrampsBSDDB.py (load_from): Add method. + * src/GrampsDb/_GrampsXMLDB.py (load_from): Add method. + * src/GrampsDb/_GrampsGEDDB.py (load_from): Add method. + * src/GrampsDb/_GrampsDbBase.py (load_from): Add method. + * src/GrampsDb/_WriteGrdb.py: Use db_copy. + * src/GrampsDb/_DbUtils.py (db_copy): Add function. + * src/ViewManager.py: Save as support. + * src/DataViews/_MapView.py (enable_debug): Set to False to be + able to see the output besides MapView. + * src/plugins/FamilyGroup.py: Use triple quotes. * src/Exporter.py (Exporter.native_export): Use callback. * src/Utils.py (get_new_filename): Add path separator. diff --git a/src/DataViews/_MapView.py b/src/DataViews/_MapView.py index f98628c2e..4028557aa 100644 --- a/src/DataViews/_MapView.py +++ b/src/DataViews/_MapView.py @@ -78,7 +78,7 @@ glob_loc_data = [ # (Name, longitude, latitude) ("Mannheim-Neckarau",8.48,49.45), ("Gorxheimertal",8.73,49.53)] -enable_debug = True +enable_debug = False # Draws a map image and tries to allocate space in the correct aspect ratio diff --git a/src/GrampsDb/_DbUtils.py b/src/GrampsDb/_DbUtils.py index ca5a9c9a7..eabeddb5b 100644 --- a/src/GrampsDb/_DbUtils.py +++ b/src/GrampsDb/_DbUtils.py @@ -143,3 +143,95 @@ def add_child_to_family(db, family, child, if need_commit: db.transaction_commit(trans, _('Add child to family') ) + + +def db_copy(from_db,to_db,callback): + if '__call__' in dir(callback): # callback is really callable + update = update_real + + # Prepare length for the callback + person_len = from_db.get_number_of_people() + family_len = from_db.get_number_of_families() + event_len = from_db.get_number_of_events() + source_len = from_db.get_number_of_sources() + place_len = from_db.get_number_of_places() + repo_len = from_db.get_number_of_repositories() + obj_len = from_db.get_number_of_media_objects() + + total = person_len + family_len + event_len + place_len + \ + source_len + obj_len + repo_len + else: + update = update_empty + total = 0 + + primary_tables = { + 'Person': {'cursor_func': from_db.get_person_cursor, + 'table': to_db.person_map }, + 'Family': {'cursor_func': from_db.get_family_cursor, + 'table': to_db.family_map }, + 'Event': {'cursor_func': from_db.get_event_cursor, + 'table': to_db.event_map }, + 'Place': {'cursor_func': from_db.get_place_cursor, + 'table': to_db.place_map }, + 'Source': {'cursor_func': from_db.get_source_cursor, + 'table': to_db.source_map }, + 'MediaObject': {'cursor_func': from_db.get_media_cursor, + 'table': to_db.media_map }, + 'Repository': {'cursor_func': from_db.get_repository_cursor, + 'table': to_db.repository_map }, + } + + + if to_db.__class__.__name__ == 'GrampsBSDDB': + if to_db.UseTXN: + add_data = add_data_txn + else: + add_data = add_data_notxn + else: + add_data = add_data_dict + + oldval = 0 + count = 0 + + for table_name in primary_tables.keys(): + cursor_func = primary_tables[table_name]['cursor_func'] + table = primary_tables[table_name]['table'] + + cursor = cursor_func() + item = cursor.first() + while item: + (handle,data) = item + add_data(to_db,table,handle,data) + item = cursor.next() + count,oldval = update(callback,count,oldval,total) + update(callback,count,oldval,total) + cursor.close() + + # The metadata is always transactionless, + # and the table is small, so using key iteration is OK here. + for handle in from_db.metadata.keys(): + data = from_db.metadata.get(handle) + to_db.metadata[handle] = data + + +def add_data_txn(db,table,handle,data): + the_txn = db.env.txn_begin() + table.put(handle,data,txn=the_txn) + the_txn.commit() + +def add_data_notxn(db,table,handle,data): + table.put(handle,data) + +def add_data_dict(db,table,handle,data): + table[handle] = data + +def update_empty(callback,count,oldval,total): + pass + +def update_real(callback,count,oldval,total): + count += 1 + newval = int(100.0*count/total) + if newval != oldval: + callback(newval) + oldval = newval + return count,oldval diff --git a/src/GrampsDb/_GrampsBSDDB.py b/src/GrampsDb/_GrampsBSDDB.py index baa0f8101..5375e1cc9 100644 --- a/src/GrampsDb/_GrampsBSDDB.py +++ b/src/GrampsDb/_GrampsBSDDB.py @@ -53,6 +53,7 @@ except NameError: #------------------------------------------------------------------------- from RelLib import * from _GrampsDbBase import * +from _DbUtils import db_copy import const _MINVERSION = 5 @@ -316,15 +317,14 @@ class GrampsBSDDB(GrampsDbBase): else: env_flags = db.DB_CREATE|db.DB_PRIVATE|\ db.DB_INIT_MPOOL|db.DB_INIT_LOG - env_name = self.brief_name + env_name = os.path.expanduser('~') self.env.open(env_name,env_flags) if self.UseTXN: self.env.txn_checkpoint() callback(25) - - self.metadata =self.open_table(self.full_name,"meta",no_txn=True) + self.metadata = self.open_table(self.full_name,"meta",no_txn=True) self.family_map = self.open_table(self.full_name, "family") self.place_map = self.open_table(self.full_name, "places") @@ -386,6 +386,11 @@ class GrampsBSDDB(GrampsDbBase): return 1 + def load_from(self, other_database, filename, callback): + self.load(filename,callback) + db_copy(other_database,self,callback) + return 1 + def connect_secondary(self): """ This method connects or creates secondary index tables. diff --git a/src/GrampsDb/_GrampsDbBase.py b/src/GrampsDb/_GrampsDbBase.py index 0fa3f520a..d65fbbff0 100644 --- a/src/GrampsDb/_GrampsDbBase.py +++ b/src/GrampsDb/_GrampsDbBase.py @@ -356,6 +356,14 @@ class GrampsDbBase(GrampsDBCallback): """ assert False, "Needs to be overridden in the derived class" + def load_from(self, other_database, filename, callback): + """ + Loads data from the other database into itself. + The filename is the name of the file for the newly created database. + The method needs to be overridden in the derived class. + """ + assert False, "Needs to be overridden in the derived class" + def close(self): """ Closes the specified database. The method needs to be overridden diff --git a/src/GrampsDb/_GrampsGEDDB.py b/src/GrampsDb/_GrampsGEDDB.py index b00d72c78..c644456b3 100644 --- a/src/GrampsDb/_GrampsGEDDB.py +++ b/src/GrampsDb/_GrampsGEDDB.py @@ -30,6 +30,7 @@ from _GrampsInMemDB import * import _ReadGedcom as ReadGedcom import _WriteGedcom as WriteGedcom +from _DbUtils import db_copy #------------------------------------------------------------------------- # @@ -56,6 +57,17 @@ class GrampsGEDDB(GrampsInMemDB): self.db_is_open = True return 1 + def load_from(self, other_database, filename, callback): + db_copy(other_database,self,callback) + GrampsInMemDB.load(self,filename,callback) + self.bookmarks = self.metadata.get('bookmarks') + if self.bookmarks == None: + self.bookmarks = [] + self.db_is_open = True + writer = WriteGedcom.GedcomWriter(self,self.get_default_person()) + writer.export_data(self.full_name) + return 1 + def close(self): if not self.db_is_open: return diff --git a/src/GrampsDb/_GrampsXMLDB.py b/src/GrampsDb/_GrampsXMLDB.py index c42b90465..9de5055e9 100644 --- a/src/GrampsDb/_GrampsXMLDB.py +++ b/src/GrampsDb/_GrampsXMLDB.py @@ -30,6 +30,7 @@ from _GrampsInMemDB import * import _ReadXML as ReadXML import _WriteXML as WriteXML +from _DbUtils import db_copy #------------------------------------------------------------------------- # @@ -58,6 +59,17 @@ class GrampsXMLDB(GrampsInMemDB): self.db_is_open = True return 1 + def load_from(self, other_database, filename, callback): + self.id_trans = {} + db_copy(other_database,self,callback) + GrampsInMemDB.load(self,filename,callback) + self.bookmarks = self.metadata.get('bookmarks') + if self.bookmarks == None: + self.bookmarks = [] + self.db_is_open = True + WriteXML.quick_write(self,self.full_name) + return 1 + def close(self): if not self.db_is_open: return diff --git a/src/GrampsDb/_WriteGrdb.py b/src/GrampsDb/_WriteGrdb.py index c114a6f91..5151d282c 100644 --- a/src/GrampsDb/_WriteGrdb.py +++ b/src/GrampsDb/_WriteGrdb.py @@ -37,6 +37,7 @@ from gettext import gettext as _ #------------------------------------------------------------------------- from _GrampsBSDDB import GrampsBSDDB from QuestionDialog import ErrorDialog +from _DbUtils import db_copy #------------------------------------------------------------------------- # @@ -44,25 +45,7 @@ from QuestionDialog import ErrorDialog # #------------------------------------------------------------------------- def exportData(database, filename, person=None, callback=None, cl=False): - - if '__call__' in dir(callback): # callback is really callable - update = update_real - - # Prepare length for the callback - person_len = database.get_number_of_people() - family_len = database.get_number_of_families() - event_len = database.get_number_of_events() - source_len = database.get_number_of_sources() - place_len = database.get_number_of_places() - repo_len = database.get_number_of_repositories() - obj_len = database.get_number_of_media_objects() - - total = person_len + family_len + event_len + place_len + \ - source_len + obj_len + repo_len - else: - update = update_empty - total = 0 - + filename = os.path.normpath(filename) new_database = GrampsBSDDB() try: @@ -75,69 +58,6 @@ def exportData(database, filename, person=None, callback=None, cl=False): return # copy all data from new_database to database - - # Need different adders depending on whether the new db is transactional - if new_database.UseTXN: - add_data = add_data_txn - else: - add_data = add_data_notxn - - primary_tables = { - 'Person': {'cursor_func': database.get_person_cursor, - 'new_table': new_database.person_map }, - 'Family': {'cursor_func': database.get_family_cursor, - 'new_table': new_database.family_map }, - 'Event': {'cursor_func': database.get_event_cursor, - 'new_table': new_database.event_map }, - 'Place': {'cursor_func': database.get_place_cursor, - 'new_table': new_database.place_map }, - 'Source': {'cursor_func': database.get_source_cursor, - 'new_table': new_database.source_map }, - 'MediaObject': {'cursor_func': database.get_media_cursor, - 'new_table': new_database.media_map }, - 'Repository': {'cursor_func': database.get_repository_cursor, - 'new_table': new_database.repository_map }, - } - - count = 0 - oldval = 0 - - for table_name in primary_tables.keys(): - cursor_func = primary_tables[table_name]['cursor_func'] - new_table = primary_tables[table_name]['new_table'] - - cursor = cursor_func() - item = cursor.first() - while item: - (handle,data) = item - add_data(new_database,new_table,handle,data) - item = cursor.next() - count,oldval = update(callback,count,oldval,total) - cursor.close() - - # The metadata is always transactionless, - # and the table is small, so using key iteration is OK here. - for handle in database.metadata.keys(): - new_database.metadata.put(handle,database.metadata.get(handle)) + db_copy(database,new_database,callback) new_database.close() - - -def add_data_txn(db,table,handle,data): - the_txn = db.env.txn_begin() - table.put(handle,data,txn=the_txn) - the_txn.commit() - -def add_data_notxn(db,table,handle,data): - table.put(handle,data) - -def update_empty(callback,count,oldval,total): - pass - -def update_real(callback,count,oldval,total): - count += 1 - newval = int(100.0*count/total) - if newval != oldval: - callback(newval) - oldval = newval - return count,oldval diff --git a/src/ViewManager.py b/src/ViewManager.py index 96df78abb..8c1083360 100644 --- a/src/ViewManager.py +++ b/src/ViewManager.py @@ -329,7 +329,8 @@ class ViewManager: ] self._action_action_list = [ - ('SaveAs', gtk.STOCK_SAVE_AS, _('_Save As')), + ('SaveAs', gtk.STOCK_SAVE_AS, _('_Save As'),"s", + None, self.save_as_activate), ('Export', gtk.STOCK_SAVE_AS, _('_Export'), "e", None, self.export_data), ('Abandon', gtk.STOCK_REVERT_TO_SAVED, @@ -755,6 +756,79 @@ class ViewManager: choose.destroy() return False + def save_as_activate(self,obj): + choose = gtk.FileChooserDialog( + _('GRAMPS: Create GRAMPS database'), + self.uistate.window, + gtk.FILE_CHOOSER_ACTION_SAVE, + (gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL, + gtk.STOCK_OPEN, gtk.RESPONSE_OK)) + + # Always add automatic (macth all files) filter + add_all_files_filter(choose) + add_gramps_files_filter(choose) + add_grdb_filter(choose) + add_xml_filter(choose) + add_gedcom_filter(choose) + + format_list = [const.app_gramps,const.app_gramps_xml,const.app_gedcom] + (box, type_selector) = format_maker(format_list) + choose.set_extra_widget(box) + + # Suggested folder: try last open file, import, then last export, + # then home. + default_dir = os.path.split(Config.get(Config.RECENT_FILE))[0] \ + + os.path.sep + if len(default_dir)<=1: + default_dir = Config.get(Config.RECENT_IMPORT_DIR) + if len(default_dir)<=1: + default_dir = Config.get(Config.RECENT_EXPORT_DIR) + if len(default_dir)<=1: + default_dir = '~/' + + new_filename = Utils.get_new_filename('grdb', default_dir) + + choose.set_current_folder(default_dir) + choose.set_current_name(os.path.split(new_filename)[1]) + + response = choose.run() + if response == gtk.RESPONSE_OK: + filename = choose.get_filename() + if filename == None: + choose.destroy() + return False + + filetype = type_selector.get_value() + if filetype == 'auto': + try: + the_file = open(filename,'wb') + the_file.close() + filetype = Mime.get_type(filename) + os.remove(filename) + except RuntimeError, msg: + QuestionDialog.ErrorDialog( + _("Could not open file: %s") % filename, + str(msg)) + return False + # First we try our best formats + if filetype not in (const.app_gramps, + const.app_gramps_xml, + const.app_gedcom): + QuestionDialog.ErrorDialog( + _("Could not open file: %s") % filename, + _("Unknown type: %s") % filetype + ) + return False + choose.destroy() + try: + return self.open_saved_as(filename,filetype) + except: + log.error("Failed to save as", exc_info=True) + return False + else: + choose.destroy() + return False + def new_activate(self, obj): choose = gtk.FileChooserDialog( @@ -1159,6 +1233,66 @@ class ViewManager: self.progress.hide() self.window.window.set_cursor(None) + def open_saved_as(self, filename, filetype): + (the_path, the_file) = os.path.split(filename) + Config.set(Config.RECENT_IMPORT_DIR,the_path) + + dbclass = GrampsDb.gramps_db_factory(filetype) + success = self.do_save_as(filename,dbclass) + self.state.signal_change() + self.change_page(None, None) + + if success: + # Add the file to the recent items + RecentFiles.recent_files(filename, filetype) + self.recent_manager.build() + self.actiongroup.set_visible(True) + self.uistate.clear_history() + return success + + def do_save_as(self,filename,dbclass): + # FIXME: error checking on filename here + self.state.emit('database-changed', (GrampsDb.GrampsDbBase(), )) + try: + if self._do_copy(filename,dbclass): + if filename[-1] == '/': + filename = filename[:-1] + name = os.path.basename(filename) + msg = "%s - GRAMPS" % name + self.uistate.window.set_title(msg) + else: + Config.set(Config.RECENT_FILE,"") + QuestionDialog.ErrorDialog( + _('Cannot save a copy of the database'), + _('The database copy could not be saved.')) + return False + except (IOError,OSError), msg: + QuestionDialog.ErrorDialog(_('Cannot save database'), str(msg)) + return False + except (db.DBAccessError, db.DBError), msg: + QuestionDialog.ErrorDialog( + _('Cannot save database'), + _('%s could not be saved.' % filename) + '\n' + msg[1]) + return False + except Exception: + log.error("Failed to open database.", exc_info=True) + return False + self.file_loaded = True + self.actiongroup.set_visible(True) + return True + + def _do_copy(self,filename,dbclass): + self.window.window.set_cursor(gtk.gdk.Cursor(gtk.gdk.WATCH)) + self.progress.show() + new_database = dbclass() + if not new_database.load_from(self.state.db,filename, + self.uistate.pulse_progressbar): + return False + self.progress.hide() + self.state.db.close() + self.state.change_database(new_database) + return self.post_load(filename,self.uistate.pulse_progressbar) + def build_tools_menu(self): self.toolactions = gtk.ActionGroup('ToolWindow') (ui, actions) = self.build_plugin_menu('ToolsMenu',