diff --git a/gramps/gen/db/generic.py b/gramps/gen/db/generic.py index ca476cd9e..7100e8376 100644 --- a/gramps/gen/db/generic.py +++ b/gramps/gen/db/generic.py @@ -144,7 +144,15 @@ class DbGenericUndo(DbUndo): if key == REFERENCE_KEY: self.undo_reference(new_data, handle) else: - self.undo_data(new_data, handle, key, db.emit, SIGBASE[key]) + self.undo_data(new_data, handle, key) + # now emit the signals + for record_id in subitems: + (key, trans_type, handle, old_data, new_data) = \ + pickle.loads(self.undodb[record_id]) + + if key != REFERENCE_KEY: + self.undo_signals(new_data, handle, key, + db.emit, SIGBASE[key]) self.db._txn_commit() except: self.db._txn_abort() @@ -187,8 +195,15 @@ class DbGenericUndo(DbUndo): if key == REFERENCE_KEY: self.undo_reference(old_data, handle) else: - self.undo_data(old_data, handle, key, db.emit, SIGBASE[key]) + self.undo_data(old_data, handle, key) + # now emit the signals + for record_id in subitems: + (key, trans_type, handle, old_data, new_data) = \ + pickle.loads(self.undodb[record_id]) + if key != REFERENCE_KEY: + self.undo_signals(old_data, handle, key, + db.emit, SIGBASE[key]) self.db._txn_commit() except: self.db._txn_abort() @@ -224,7 +239,26 @@ class DbGenericUndo(DbUndo): "VALUES(?, ?, ?, ?)") self.db.dbapi.execute(sql, data) - def undo_data(self, data, handle, obj_key, emit, signal_root): + def undo_data(self, data, handle, obj_key): + """ + Helper method to undo/redo the changes made + """ + cls = KEY_TO_CLASS_MAP[obj_key] + table = cls.lower() + if data is None: + sql = "DELETE FROM %s WHERE handle = ?" % table + self.db.dbapi.execute(sql, [handle]) + else: + if self.db.has_handle(obj_key, handle): + sql = "UPDATE %s SET blob_data = ? WHERE handle = ?" % table + self.db.dbapi.execute(sql, [pickle.dumps(data), handle]) + else: + sql = "INSERT INTO %s (handle, blob_data) VALUES (?, ?)" % table + self.db.dbapi.execute(sql, [handle, pickle.dumps(data)]) + obj = self.db.get_table_func(cls)["class_func"].create(data) + self.db._update_secondary_values(obj) + + def undo_signals(self, data, handle, obj_key, emit, signal_root): """ Helper method to undo/redo the changes made """ @@ -232,19 +266,11 @@ class DbGenericUndo(DbUndo): table = cls.lower() if data is None: emit(signal_root + '-delete', ([handle],)) - sql = "DELETE FROM %s WHERE handle = ?" % table - self.db.dbapi.execute(sql, [handle]) else: if self.db.has_handle(obj_key, handle): signal = signal_root + '-update' - sql = "UPDATE %s SET blob_data = ? WHERE handle = ?" % table - self.db.dbapi.execute(sql, [pickle.dumps(data), handle]) else: signal = signal_root + '-add' - sql = "INSERT INTO %s (handle, blob_data) VALUES (?, ?)" % table - self.db.dbapi.execute(sql, [handle, pickle.dumps(data)]) - obj = self.db.get_table_func(cls)["class_func"].create(data) - self.db._update_secondary_values(obj) emit(signal, ([handle],)) class Cursor: diff --git a/gramps/gui/dialog.py b/gramps/gui/dialog.py index aebddca78..b48a34fce 100644 --- a/gramps/gui/dialog.py +++ b/gramps/gui/dialog.py @@ -73,6 +73,9 @@ class SaveDialog: label2.set_use_markup(True) if parent: self.top.set_transient_for(parent) + parent_modal = parent.get_modal() + if parent_modal: + parent.set_modal(False) self.top.show() response = self.top.run() if response == Gtk.ResponseType.NO: @@ -82,6 +85,8 @@ class SaveDialog: config.set('interface.dont-ask', self.dontask.get_active()) self.top.destroy() + if parent and parent_modal: + parent.set_modal(True) class QuestionDialog: def __init__(self, msg1, msg2, label, task, parent=None): @@ -103,9 +108,14 @@ class QuestionDialog: if parent: self.top.set_transient_for(parent) + parent_modal = parent.get_modal() + if parent_modal: + parent.set_modal(False) self.top.show() response = self.top.run() self.top.destroy() + if parent and parent_modal: + parent.set_modal(True) if response == Gtk.ResponseType.ACCEPT: task() @@ -138,13 +148,19 @@ class QuestionDialog2: self.xml.get_object('no').set_label(label_msg2) self.xml.get_object('no').set_use_underline(True) + self.parent = parent if parent: self.top.set_transient_for(parent) + self.parent_modal = parent.get_modal() + if self.parent_modal: + parent.set_modal(False) self.top.show() def run(self): response = self.top.run() self.top.destroy() + if self.parent and self.parent_modal: + self.parent.set_modal(True) return (response == Gtk.ResponseType.ACCEPT) class OptionDialog: @@ -167,6 +183,9 @@ class OptionDialog: self.xml.get_object('option2').set_label(btnmsg2) if parent: self.top.set_transient_for(parent) + parent_modal = parent.get_modal() + if parent_modal: + parent.set_modal(False) self.top.show() self.response = self.top.run() if self.response == Gtk.ResponseType.NO: @@ -176,6 +195,8 @@ class OptionDialog: if task2: task2() self.top.destroy() + if parent and parent_modal: + parent.set_modal(True) def get_response(self): return self.response @@ -191,9 +212,15 @@ class ErrorDialog(Gtk.MessageDialog): self.format_secondary_text(msg2) self.set_icon(ICON) self.set_title("%s - Gramps" % str(msg1)) + if parent: + parent_modal = parent.get_modal() + if parent_modal: + parent.set_modal(False) self.show() self.run() self.destroy() + if parent and parent_modal: + parent.set_modal(True) class RunDatabaseRepair(ErrorDialog): def __init__(self, msg, parent=None): @@ -236,9 +263,15 @@ class WarningDialog(Gtk.MessageDialog): # : unknown signal name: activate-link self.set_icon(ICON) self.set_title("%s - Gramps" % msg1) + if parent: + parent_modal = parent.get_modal() + if parent_modal: + parent.set_modal(False) self.show() self.run() self.destroy() + if parent and parent_modal: + parent.set_modal(True) class OkDialog(Gtk.MessageDialog): def __init__(self, msg1, msg2="", parent=None): @@ -251,9 +284,15 @@ class OkDialog(Gtk.MessageDialog): self.format_secondary_text(msg2) self.set_icon(ICON) self.set_title("%s - Gramps" % msg1) + if parent: + parent_modal = parent.get_modal() + if parent_modal: + parent.set_modal(False) self.show() self.run() self.destroy() + if parent and parent_modal: + parent.set_modal(True) class InfoDialog: """ @@ -312,6 +351,9 @@ class MissingMediaDialog: if parent: self.top.set_transient_for(parent) + parent_modal = parent.get_modal() + if parent_modal: + parent.set_modal(False) self.top.show() self.top.connect('delete_event', self.warn) response = Gtk.ResponseType.DELETE_EVENT @@ -333,6 +375,8 @@ class MissingMediaDialog: else: self.default_action = 0 self.top.destroy() + if parent and parent_modal: + parent.set_modal(True) def warn(self, obj, obj2): WarningDialog( @@ -367,6 +411,9 @@ class MultiSelectDialog: if parent: self.top.set_transient_for(parent) + parent_modal = parent.get_modal() + if parent_modal: + parent.set_modal(False) self.top.connect('delete_event', self.warn) default_action = 0 @@ -406,6 +453,8 @@ class MultiSelectDialog: if self.yes_func: self.yes_func(item) self.top.destroy() + if parent and parent_modal: + parent.set_modal(True) def warn(self, obj, obj2): WarningDialog( @@ -436,8 +485,13 @@ class MessageHideDialog: dont_show.connect('toggled', self.update_checkbox, key) if parent: self.top.set_transient_for(parent) + parent_modal = parent.get_modal() + if parent_modal: + parent.set_modal(False) self.top.run() self.top.destroy() + if parent and parent_modal: + parent.set_modal(True) def update_checkbox(self, obj, constant): config.set(constant, obj.get_active()) diff --git a/gramps/gui/plug/export/_exportassistant.py b/gramps/gui/plug/export/_exportassistant.py index a4cab8acc..fdad88e3b 100644 --- a/gramps/gui/plug/export/_exportassistant.py +++ b/gramps/gui/plug/export/_exportassistant.py @@ -350,6 +350,8 @@ class ExportAssistant(ManagedWindow, Gtk.Assistant): box.set_spacing(6) box.pack_start(image, False, False, 5) box.pack_start(self.confirm, False, False, 5) + self.progressbar = Gtk.ProgressBar() + box.pack_start(self.progressbar, False, False, 0) page = box self.append_page(page) @@ -369,14 +371,11 @@ class ExportAssistant(ManagedWindow, Gtk.Assistant): image.set_from_file(SPLASH) vbox.pack_start(image, False, False, 5) - self.labelsum = Gtk.Label(label=_("Please wait while your data is selected and exported")) + self.labelsum = Gtk.Label() self.labelsum.set_line_wrap(True) self.labelsum.set_use_markup(True) vbox.pack_start(self.labelsum, False, False, 0) - self.progressbar = Gtk.ProgressBar() - vbox.pack_start(self.progressbar, True, True, 0) - page = vbox page.show_all() @@ -486,6 +485,7 @@ class ExportAssistant(ManagedWindow, Gtk.Assistant): # Override message confirm_text = self.option_box_instance.confirm_text self.confirm.set_label(confirm_text) + self.progressbar.hide() elif self.get_page_type(page) == Gtk.AssistantPageType.SUMMARY : # The summary page @@ -601,11 +601,14 @@ class ExportAssistant(ManagedWindow, Gtk.Assistant): log.error(_("Error exporting your Family Tree"), exc_info=True) return success - def pre_save(self,page): - #as all is locked, show the page, which assistant normally only does - # after prepare signal! + def pre_save(self, page): + ''' Since we are in 'prepare', the next page is not yet shown, so + modify the 'confirm' page text and show the progress bar + ''' + self.confirm.set_label( + _("Please wait while your data is selected and exported")) self.writestarted = True - page.set_child_visible(True) + self.progressbar.show() self.show_all() self.set_busy_cursor(1) diff --git a/gramps/plugins/db/bsddb/undoredo.py b/gramps/plugins/db/bsddb/undoredo.py index be62072ce..21e1951e3 100644 --- a/gramps/plugins/db/bsddb/undoredo.py +++ b/gramps/plugins/db/bsddb/undoredo.py @@ -237,8 +237,15 @@ class DbUndo: if key == REFERENCE_KEY: self.undo_reference(old_data, handle, self.mapbase[key]) else: - self.undo_data(old_data, handle, self.mapbase[key], - db.emit, _SIGBASE[key]) + self.undo_data(old_data, handle, self.mapbase[key]) + # now emit the signals + for record_id in subitems: + (key, trans_type, handle, old_data, new_data) = \ + pickle.loads(self.undodb[record_id]) + + if key != REFERENCE_KEY: + self.undo_signals(old_data, handle, self.mapbase[key], + db.emit, _SIGBASE[key]) # Notify listeners if db.undo_callback: if self.undo_count > 0: @@ -275,8 +282,15 @@ class DbUndo: if key == REFERENCE_KEY: self.undo_reference(new_data, handle, self.mapbase[key]) else: - self.undo_data(new_data, handle, self.mapbase[key], - db.emit, _SIGBASE[key]) + self.undo_data(new_data, handle, self.mapbase[key]) + # Process all signals in the transaction + for record_id in subitems: + (key, trans_type, handle, old_data, new_data) = \ + pickle.loads(self.undodb[record_id]) + + if key != REFERENCE_KEY: + self.undo_signals(new_data, handle, self.mapbase[key], + db.emit, _SIGBASE[key]) # Notify listeners if db.undo_callback: db.undo_callback(_("_Undo %s") @@ -308,21 +322,33 @@ class DbUndo: self.db._log_error() raise DbError(msg) - def undo_data(self, data, handle, db_map, emit, signal_root): + def undo_data(self, data, handle, db_map): + """ + Helper method to undo/redo the changes made + """ + try: + if data is None: + db_map.delete(handle, txn=self.txn) + else: + db_map.put(handle, data, txn=self.txn) + + except DBERRS as msg: + self.db._log_error() + raise DbError(msg) + + def undo_signals(self, data, handle, db_map, emit, signal_root): """ Helper method to undo/redo the changes made """ try: if data is None: emit(signal_root + '-delete', ([handle.decode('utf-8')],)) - db_map.delete(handle, txn=self.txn) else: ex_data = db_map.get(handle, txn=self.txn) if ex_data: signal = signal_root + '-update' else: signal = signal_root + '-add' - db_map.put(handle, data, txn=self.txn) emit(signal, ([handle.decode('utf-8')],)) except DBERRS as msg: diff --git a/gramps/plugins/tool/check.py b/gramps/plugins/tool/check.py index 2f7183e89..f609e7526 100644 --- a/gramps/plugins/tool/check.py +++ b/gramps/plugins/tool/check.py @@ -381,7 +381,7 @@ class CheckIntegrity: error_count = 0 for bhandle in self.db.get_media_handles(): handle = bhandle.decode('utf-8') - data = self.db.media_map[bhandle] + data = self.db.get_raw_media_data(handle) if not isinstance(data[2], str) or not isinstance(data[4], str): obj = self.db.get_media_from_handle(handle) if not isinstance(data[2], str):