# # Gramps - a GTK+/GNOME based genealogy program # # Copyright (C) 2000-2005 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$ #------------------------------------------------------------------------- # # Python modules # #------------------------------------------------------------------------- from gettext import gettext as _ #------------------------------------------------------------------------- # # GTK/Gnome modules # #------------------------------------------------------------------------- import gobject import gtk.glade import gtk.gdk import gnome #------------------------------------------------------------------------- # # gramps modules # #------------------------------------------------------------------------- import const import Utils import ImageSelect import ListModel import RelLib import NameDisplay import AutoComp import RepositoryRefEdit #------------------------------------------------------------------------- # # Classes to manager the list of Sources that have references to the # Repository # #------------------------------------------------------------------------- class ReposSrcListModel(gtk.ListStore): def __init__(self, model, repos=None): gtk.ListStore.__init__(self, object, # source object # repostory reference ) self.original_item_list = [] self.set_model(model) self.set_repos(repos) def rebuild(self): """Clear the list and repopulate from the current source record, remember the original list in case it is useful later""" self.clear() # Get the list of sources that reference this repository repos_handle = self._repos.get_handle() source_list = [ src_handle for src_handle \ in self._db.get_source_handles() \ if self._db.get_source_from_handle(src_handle).has_repo_reference(repos_handle)] # Add each (source,repos_ref) to list. It is possible for # a source to reference to same repository more than once. self.original_item_list = [] for source_hdl in source_list: source = self._db.get_source_from_handle(source_hdl) repos_ref_list = [ repos_ref for repos_ref in source.get_reporef_list() \ if repos_ref.get_reference_handle() == repos_handle ] for repos_ref in repos_ref_list: self.append([self._db.get_source_from_handle(source_hdl),repos_ref]) self.original_item_list.append((source_hdl,repos_ref)) def update(self,source,repos_ref,original_source=None): """Add the record if it is not already in the list otherwise replace the record with the new one.""" if original_source != None and \ source.get_handle() != original_source.get_handle(): # If the source has changed we need to remove the # original reference found = False for val in range(0,len(self)): iter = self.get_iter(val) if original_source.get_handle() == self.get_value(iter,0).get_handle() \ and repos_ref == self.get_value(iter,1): self.remove(iter) found = True break # If the source has not changed but the ref has then just update the row found = False for val in range(0,len(self)): iter = self.get_iter(val) if source.get_handle() == self.get_value(iter,0).get_handle and \ repos_ref == self.get_value(iter,1): self.row_changed(self.get_path(iter),iter) found = True break if not found: self.append([source,repos_ref]) def set_repos(self, repos): self._repos = repos self.rebuild() def set_model(self, model): self._model = model self._db = model.db def get_deleted_items(self): # These are the ones that are in the original sources list # but no longer in the list model self.items = [] for val in range(0,len(self)): iter = self.get_iter(val) self.items.append((self.get_value(iter,0).get_handle(),self.get_value(iter,1))) deleted = [] for item in self.original_item_list: found = False for cur_item in self.items: if item[0] == cur_item[0] and \ item[1] == cur_item[1]: found = True break if not found: deleted.append(item) return deleted def get_added_items(self): # These are the ones that are in the list model but not in the # original sources list. self.items = [] for val in range(0,len(self)): iter = self.get_iter(val) self.items.append((self.get_value(iter,0).get_handle(),self.get_value(iter,1))) added = [] for cur_item in self.items: found = False for item in self.original_item_list: if item[0] == cur_item[0] and \ item[1] == cur_item[1]: found = True break if not found: added.append(cur_item) return added def get_update_items(self): # These are in both lists but the repos_ref has changed in the # list model. self.items = [] for val in range(0,len(self)): iter = self.get_iter(val) self.items.append((self.get_value(iter,0).get_handle(),self.get_value(iter,1))) update = [] for cur_item in self.items: found = False for item in self.original_item_list: if item[0] == cur_item[0] and \ item[1] == cur_item[1]: found = True break if found: update.append(item) return update class ReposSrcListView: def __init__(self, model, widget): self._gramps_model = model self.database_changed(self._gramps_model.db) self._gramps_model.connect('database-changed', self.database_changed) self._widget = widget # Create the tree columns self._col1 = gtk.TreeViewColumn(_("Title")) self._col2 = gtk.TreeViewColumn(_("Author")) self._col3 = gtk.TreeViewColumn(_("Reference Note")) # Add columns self._widget.append_column(self._col1) self._widget.append_column(self._col2) self._widget.append_column(self._col3) # Create cell renders self._col1_cell = gtk.CellRendererText() self._col2_cell = gtk.CellRendererText() self._col3_cell = gtk.CellRendererText() # Add cells to view self._col1.pack_start(self._col1_cell, True) self._col2.pack_start(self._col2_cell, True) self._col3.pack_start(self._col3_cell, True) # Setup the cell data callback funcs self._col1.set_cell_data_func(self._col1_cell, self.object_title) self._col2.set_cell_data_func(self._col2_cell, self.object_author) self._col3.set_cell_data_func(self._col3_cell, self.object_ref_note) self._widget.set_enable_search(False) def database_changed(self,db): self._db = db # Methods for rendering the cells. def object_title(self, column, cell, model, iter, user_data=None): source = model.get_value(iter, 0) cell.set_property('text', source.get_title()) def object_author(self, column, cell, model, iter, user_data=None): source = model.get_value(iter, 0) cell.set_property('text', source.get_author()) def object_ref_note(self, column, cell, model, iter, user_data=None): o = model.get_value(iter, 1) cell.set_property('text', o.get_note()) # proxy methods to provide access to the real widget functions. def set_model(self,model=None): self._widget.set_model(model) def get_model(self): return self._widget.get_model() def get_selection(self): return self._widget.get_selection() class EditRepository: def __init__(self,repository,db,parent,parent_window=None,readonly=False): if repository: self.repository = repository else: self.repository = RelLib.Repository() self.db = db self.parent = parent self.name_display = NameDisplay.displayer.display if repository: if parent and self.parent.child_windows.has_key(repository.get_handle()): self.parent.child_windows[repository.get_handle()].present(None) return else: self.win_key = repository.get_handle() else: self.win_key = self self.child_windows = {} self.path = db.get_save_path() self.not_loaded = 1 self.ref_not_loaded = 1 self.lists_changed = 0 mode = not self.db.readonly self.top_window = gtk.glade.XML(const.gladeFile,"repositoryEditor","gramps") self.top = self.top_window.get_widget("repositoryEditor") Utils.set_titles(self.top,self.top_window.get_widget('repository_title'), _('Repository Editor')) self.name = self.top_window.get_widget("repository_name") self.name.set_text(repository.get_name()) self.name.set_editable(mode) self.type = self.top_window.get_widget("repository_type") self.type_selector = AutoComp.StandardCustomSelector( \ Utils.repository_types,self.type, RelLib.Repository.CUSTOM,RelLib.Repository.LIBRARY) self.type_selector.set_values(repository.get_type()) self.street = self.top_window.get_widget("repository_street") self.street.set_text(repository.get_address().get_parish()) self.street.set_editable(mode) self.city = self.top_window.get_widget("repository_city") self.city.set_text(repository.get_address().get_city()) self.city.set_editable(mode) self.county = self.top_window.get_widget("repository_county") self.county.set_text(repository.get_address().get_county()) self.county.set_editable(mode) self.state = self.top_window.get_widget("repository_state") self.state.set_text(repository.get_address().get_state()) self.state.set_editable(mode) self.postal = self.top_window.get_widget("repository_postal") self.postal.set_text(repository.get_address().get_postal_code()) self.postal.set_editable(mode) self.country = self.top_window.get_widget("repository_country") self.country.set_text(repository.get_address().get_country()) self.country.set_editable(mode) self.phone = self.top_window.get_widget("repository_phone") self.phone.set_text(repository.get_address().get_phone()) self.phone.set_editable(mode) self.email = self.top_window.get_widget("repository_email") self.email.set_text(repository.get_email()) self.email.set_editable(mode) self.search_url = self.top_window.get_widget("repository_search_url") self.search_url.set_text(repository.get_search_url()) self.search_url.set_editable(mode) self.home_url = self.top_window.get_widget("repository_home_url") self.home_url.set_text(repository.get_home_url()) self.home_url.set_editable(mode) self.note = self.top_window.get_widget("repository_note") self.note.set_editable(mode) self.notes_buffer = self.note.get_buffer() self.refs_label = self.top_window.get_widget("refsRepositoryEditor") self.notes_label = self.top_window.get_widget("notesRepositoryEditor") self.flowed = self.top_window.get_widget("repository_flowed") self.flowed.set_sensitive(mode) self.preform = self.top_window.get_widget("repository_preformatted") self.preform.set_sensitive(mode) self.refinfo = self.top_window.get_widget("refinfo") if repository.get_note(): self.notes_buffer.set_text(repository.get_note()) Utils.bold_label(self.notes_label) if repository.get_note_format() == 1: self.preform.set_active(1) else: self.flowed.set_active(1) # Setup source reference tab self.repos_source_view = ReposSrcListView(self.parent, self.top_window.get_widget("repository_sources")) self.repos_source_model = ReposSrcListModel(self.parent,repository) self.repos_source_view.set_model(self.repos_source_model) self.top_window.signal_autoconnect({ "on_switch_page" : self.on_switch_page, "on_repositoryEditor_help_clicked" : self.on_help_clicked, "on_repositoryEditor_ok_clicked" : self.on_repository_apply_clicked, "on_repositoryEditor_cancel_clicked" : self.close, "on_repositoryEditor_delete_event" : self.on_delete_event, "on_add_repos_sources_clicked" : self.on_add_repos_ref_clicked, "on_delete_repos_ref_clicked" : self.on_delete_repos_ref_clicked, "on_edit_repos_ref_clicked" : self.on_edit_repos_ref_clicked, "on_edit_repos_ref_row_activated" : self.on_edit_repos_ref_clicked, }) if parent_window: self.top.set_transient_for(parent_window) self.top_window.get_widget('repository_ok').set_sensitive(not self.db.readonly) if parent_window: self.top.set_transient_for(parent_window) self.add_itself_to_menu() self.top.show() #self.refs_label.window.set_cursor(gtk.gdk.Cursor(gtk.gdk.WATCH)) #gobject.idle_add(self.display_references) def edit_cb(self, cell, path, new_text, data): node = self.data_model.get_iter(path) self.data_model.set_value(node,data,new_text) def on_delete_event(self,obj,b): self.close_child_windows() self.remove_itself_from_menu() def on_help_clicked(self,obj): """Display the relevant portion of GRAMPS manual""" gnome.help_display('gramps-manual','adv-src') def close(self,obj): self.close_child_windows() self.remove_itself_from_menu() self.top.destroy() def close_child_windows(self): for child_window in self.child_windows.values(): child_window.close(None) self.child_windows = {} def add_itself_to_menu(self): self.parent.child_windows[self.win_key] = self if not self.repository: label = _("New Repository") else: label = self.repository.get_name() if not label.strip(): label = _("New Repository") label = "%s: %s" % (_('Repository'),label) self.parent_menu_item = gtk.MenuItem(label) self.parent_menu_item.set_submenu(gtk.Menu()) self.parent_menu_item.show() self.parent.winsmenu.append(self.parent_menu_item) self.winsmenu = self.parent_menu_item.get_submenu() self.menu_item = gtk.MenuItem(_('Repository Editor')) self.menu_item.connect("activate",self.present) self.menu_item.show() self.winsmenu.append(self.menu_item) def remove_itself_from_menu(self): del self.parent.child_windows[self.win_key] self.menu_item.destroy() self.winsmenu.destroy() self.parent_menu_item.destroy() def present(self,obj): self.top.present() def on_add_repos_ref_clicked(self,widget): RepositoryRefEdit.RepositoryRefSourceEdit(RelLib.RepoRef(), None, self.db, self.repos_source_model.update, self) def on_delete_repos_ref_clicked(self,widget): selection = self.repos_source_view.get_selection() model, iter = selection.get_selected() if iter: model.remove(iter) return def on_edit_repos_ref_clicked(self,widget,path=None,colm=None,userp=None): selection = self.repos_source_view.get_selection() model, iter = selection.get_selected() if iter: source = model.get_value(iter,0) repos_ref = model.get_value(iter,1) RepositoryRefEdit.RepositoryRefSourceEdit(repos_ref, source, self.db, self.repos_source_model.update, self) def on_repository_apply_clicked(self,obj): name = unicode(self.name.get_text()) if name != self.repository.get_name(): self.repository.set_name(name) repos_type = self.type_selector.get_values() if repos_type != self.repository.get_type(): self.repository.set_type(repos_type) street = unicode(self.street.get_text()) if street != self.repository.get_address().get_parish(): self.repository.get_address().set_parish(street) city = unicode(self.city.get_text()) if city != self.repository.get_address().get_city(): self.repository.get_address().set_city(city) county = unicode(self.county.get_text()) if county != self.repository.get_address().get_county(): self.repository.get_address().set_county(county) state = unicode(self.state.get_text()) if state != self.repository.get_address().get_state(): self.repository.get_address().set_state(state) postal = unicode(self.postal.get_text()) if postal != self.repository.get_address().get_postal_code(): self.repository.get_address().set_postal_code(postal) country = unicode(self.country.get_text()) if country != self.repository.get_address().get_country(): self.repository.get_address().set_country(country) phone = unicode(self.phone.get_text()) if phone != self.repository.get_address().get_phone(): self.repository.get_address().set_phone(phone) email = unicode(self.email.get_text()) if email != self.repository.get_email(): self.repository.set_email(email) search_url = unicode(self.search_url.get_text()) if search_url != self.repository.get_search_url(): self.repository.set_search_url(search_url) home_url = unicode(self.home_url.get_text()) if home_url != self.repository.get_home_url(): self.repository.set_home_url(home_url) note = unicode(self.notes_buffer.get_text(self.notes_buffer.get_start_iter(), self.notes_buffer.get_end_iter(),False)) if note != self.repository.get_note(): self.repository.set_note(note) format = self.preform.get_active() if format != self.repository.get_note_format(): self.repository.set_note_format(format) trans = self.db.transaction_begin() handle = None if self.repository.get_handle() == None: handle = self.db.add_repository(self.repository,trans) else: self.db.commit_repository(self.repository,trans) handle = self.repository.get_handle() self.db.transaction_commit(trans,_("Edit Repository (%s)") % name) # Handle the source reference list # First look for all the references that need to be deleted # These are the ones that are in the original sources list # but no longer in the list model items_deleted = self.repos_source_model.get_deleted_items() # Now look for those that need to be added. # These are the ones that are in the list model but not in the # original sources list. items_added = self.repos_source_model.get_added_items() for item in items_added: item[1].set_reference_handle(handle) # Finally look for those that need updating # These are in both lists but the repos_ref has changed in the # list model. items_updated = self.repos_source_model.get_update_items() all_sources = {} for item in items_deleted + items_added + items_updated: all_sources[item[0]] = 1 commit_list = [] for source_hdl in all_sources.keys(): # Fetch existing list of repo_refs source = self.db.get_source_from_handle(source_hdl) original_list = source.get_reporef_list() # strip out those from this repository stripped_list = [ repos_ref for repos_ref \ in original_list \ if repos_ref.get_reference_handle() != self.repository.get_handle() ] # Now add back in those to be added and updated new_list = stripped_list + \ [ item[1] for item in items_added ] + \ [ item[1] for item in items_updated ] # Set the new list on the source source.set_reporef_list(new_list) # add it to the list of sources to be commited commit_list.append(source) trans = self.db.transaction_begin() for source in commit_list: self.db.commit_source(source,trans) self.db.transaction_commit(trans,_("Edit Repository (%s)") % name) self.close(obj) def on_switch_page(self,obj,a,page): ##if page == 2 and self.not_loaded: ## self.not_loaded = 0 ## elif page == 3 and self.ref_not_loaded: ## self.ref_not_loaded = 0 ## self.refs_label.window.set_cursor(gtk.gdk.Cursor(gtk.gdk.WATCH)) ## gobject.idle_add(self.display_references) ## text = unicode(self.notes_buffer.get_text(self.notes_buffer.get_start_iter(), ## self.notes_buffer.get_end_iter(),False)) ## if text: ## Utils.bold_label(self.notes_label) ## else: ## Utils.unbold_label(self.notes_label) pass class DelReposQuery: def __init__(self,repository,db,sources): self.repository = repository self.db = db self.sources = sources def query_response(self): trans = self.db.transaction_begin() repos_handle_list = [self.repository.get_handle()] for handle in self.sources: source = self.db.get_source_from_handle(handle) source.remove_repo_references(repos_handle_list) self.db.commit_source(source,trans) self.db.remove_repository(self.repository.get_handle(),trans) self.db.transaction_commit( trans,_("Delete Repository (%s)") % self.repository.get_name())