diff --git a/ChangeLog b/ChangeLog index eb3b4e384..17389df8b 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,10 @@ +2005-08-08 Don Allingham + * src/DbState.py: Added new class to keep track of database + status + * src/PageView.py: base class for pluggable views + * src/PersonView.py: new version of PeopleView + * src/ViewManager.py: view and database management class + 2005-08-05 Don Allingham * various: remove set_date/get_date removal to be replaced by DateHandler calls diff --git a/src/ArgHandler.py b/src/ArgHandler.py index 8cade7600..a398431e5 100644 --- a/src/ArgHandler.py +++ b/src/ArgHandler.py @@ -313,7 +313,7 @@ class ArgHandler: # the InMem formats, without setting up a new database. Then # go on and process the rest of the command line arguments. - self.parent.cl = bool(self.exports or self.actions) + #self.parent.cl = bool(self.exports or self.actions) name,format = self.open success = False @@ -339,7 +339,7 @@ class ArgHandler: os._exit(1) if self.imports: - self.parent.cl = bool(self.exports or self.actions or self.parent.cl) + #self.parent.cl = bool(self.exports or self.actions or self.parent.cl) # Create dir for imported database(s) self.impdir_path = os.path.expanduser("~/.gramps/import" ) @@ -373,33 +373,29 @@ class ArgHandler: "supply at least one input file to process." print "Launching interactive session..." - if self.parent.cl: - for expt in self.exports: - print "Exporting: file %s, format %s." % expt - self.cl_export(expt[0],expt[1]) +# if self.parent.cl: +# for expt in self.exports: +# print "Exporting: file %s, format %s." % expt +# self.cl_export(expt[0],expt[1]) - for (action,options_str) in self.actions: - print "Performing action: %s." % action - if options_str: - print "Using options string: %s" % options_str - self.cl_action(action,options_str) +# for (action,options_str) in self.actions: +# print "Performing action: %s." % action +# if options_str: +# print "Using options string: %s" % options_str +# self.cl_action(action,options_str) - print "Cleaning up." - # remove import db after use - self.parent.db.close() - if self.imports: - os.remove(self.imp_db_path) - print "Exiting." - os._exit(0) +# print "Cleaning up." +# # remove import db after use +# self.parent.db.close() +# if self.imports: +# os.remove(self.imp_db_path) +# print "Exiting." +# os._exit(0) if self.imports: self.parent.import_tool_callback() elif GrampsKeys.get_lastfile() and GrampsKeys.get_autoload(): - if self.auto_save_load(GrampsKeys.get_lastfile()) == 0: - DbPrompter.DbPrompter(self.parent,0) - else: - DbPrompter.DbPrompter(self.parent,0) - + self.auto_save_load(GrampsKeys.get_lastfile()) #------------------------------------------------------------------------- # diff --git a/src/DbPrompter.py b/src/DbPrompter.py index 7338e46e6..b1649604f 100644 --- a/src/DbPrompter.py +++ b/src/DbPrompter.py @@ -137,9 +137,9 @@ class ExistingDbPrompter: """ - def __init__(self,parent,parent_window=None): - self.parent = parent - self.parent_window = parent_window + def __init__(self,state): + self.state = state + self.parent_window = state.window def chooser(self): """ @@ -197,7 +197,7 @@ class ExistingDbPrompter: const.app_gedcom]: try: - return open_native(self.parent,filename,filetype) + return self.open_native(self.state,filename,filetype) except db.DBInvalidArgError, msg: QuestionDialog.ErrorDialog( _("Could not open file: %s") % filename, msg[1]) @@ -221,8 +221,8 @@ class ExistingDbPrompter: self.parent_window) prompter = NewNativeDbPrompter(self.parent,self.parent_window) if prompter.chooser(): - importData(self.parent.db,filename) - self.parent.import_tool_callback() + importData(self.state.db,filename) + #self.parent.import_tool_callback() return True else: return False @@ -400,7 +400,7 @@ class NewNativeDbPrompter: except: pass self.parent.db = GrampsBSDDB.GrampsBSDDB() - self.parent.read_file(filename) + self.read_file(filename) # Add the file to the recent items RecentFiles.recent_files(filename,const.app_gramps) self.parent.build_recent_menu() @@ -497,7 +497,7 @@ class NewSaveasDbPrompter: WriteGedcom.exportData(self.parent.db,filename,None,None) self.parent.db.close() self.parent.db = GrampsGEDDB.GrampsGEDDB() - self.parent.read_file(filename) + self.read_file(filename) # Add the file to the recent items RecentFiles.recent_files(filename,const.app_gramps) self.parent.build_recent_menu() @@ -508,47 +508,104 @@ class NewSaveasDbPrompter: choose.destroy() return False -#------------------------------------------------------------------------- -# -# Helper function -# -#------------------------------------------------------------------------- -def open_native(parent,filename,filetype): - """ - Open native database and return the status. - """ + def read_file(self,filename,callback=None): + mode = "w" + filename = os.path.normpath(os.path.abspath(filename)) + + if os.path.isdir(filename): + ErrorDialog(_('Cannot open database'), + _('The selected file is a directory, not ' + 'a file.\nA GRAMPS database must be a file.')) + return 0 + elif os.path.exists(filename): + if not os.access(filename,os.R_OK): + ErrorDialog(_('Cannot open database'), + _('You do not have read access to the selected ' + 'file.')) + return 0 + elif not os.access(filename,os.W_OK): + mode = "r" + WarningDialog(_('Read only database'), + _('You do not have write access to the selected ' + 'file.')) - (the_path,the_file) = os.path.split(filename) - GrampsKeys.save_last_import_dir(the_path) + try: + if self.load_database(filename,callback,mode=mode) == 1: + if filename[-1] == '/': + filename = filename[:-1] + name = os.path.basename(filename) + if self.state.db.readonly: + self.state.window.set_title("%s (%s) - GRAMPS" % (name,_('Read Only'))) + else: + self.state.window.set_title("%s - GRAMPS" % name) + else: + GrampsKeys.save_last_file("") + ErrorDialog(_('Cannot open database'), + _('The database file specified could not be opened.')) + return False + except ( IOError, OSError, Errors.FileVersionError), msg: + ErrorDialog(_('Cannot open database'),str(msg)) + return False + except (db.DBAccessError,db.DBError), msg: + ErrorDialog(_('Cannot open database'), + _('%s could not be opened.' % filename) + '\n' + msg[1]) + return False + except Exception: + DisplayTrace.DisplayTrace() + return False + + return True - success = False - if filetype == const.app_gramps: - parent.db = GrampsBSDDB.GrampsBSDDB() - msgxml = gtk.glade.XML(const.gladeFile, "load_message","gramps") - msg_top = msgxml.get_widget('load_message') - msg_label = msgxml.get_widget('message') + def load_database(self,name,callback=None,mode="w"): - def update_msg(msg): - msg_label.set_text("%s" % msg) - msg_label.set_use_markup(True) - while gtk.events_pending(): - gtk.main_iteration() + filename = name - success = parent.read_file(filename,update_msg) - msg_top.destroy() - elif filetype == const.app_gramps_xml: - parent.db = GrampsXMLDB.GrampsXMLDB() - success = parent.read_file(filename) - elif filetype == const.app_gedcom: - parent.db = GrampsGEDDB.GrampsGEDDB() - success = parent.read_file(filename) + if self.state.db.load(filename,callback,mode) == 0: + return 0 - if success: + #val = self.post_load(name,callback) + return val + + + def open_native(self,filename,filetype): + """ + Open native database and return the status. + """ + + (the_path,the_file) = os.path.split(filename) + GrampsKeys.save_last_import_dir(the_path) + + success = False + if filetype == const.app_gramps: + state.db = GrampsBSDDB.GrampsBSDDB() + msgxml = gtk.glade.XML(const.gladeFile, "load_message","gramps") + msg_top = msgxml.get_widget('load_message') + msg_label = msgxml.get_widget('message') + + def update_msg(msg): + msg_label.set_text("%s" % msg) + msg_label.set_use_markup(True) + while gtk.events_pending(): + gtk.main_iteration() + + success = self.read_file(filename,update_msg) + msg_top.destroy() + elif filetype == const.app_gramps_xml: + state.db = GrampsXMLDB.GrampsXMLDB() + success = self.read_file(filename) + elif filetype == const.app_gedcom: + state.db = GrampsGEDDB.GrampsGEDDB() + success = self.read_file(filename) + + #if success: # Add the file to the recent items - RecentFiles.recent_files(filename,filetype) - parent.build_recent_menu() + #RecentFiles.recent_files(filename,filetype) + #parent.build_recent_menu() + + return success + + - return success #------------------------------------------------------------------------- # diff --git a/src/DbState.py b/src/DbState.py new file mode 100644 index 000000000..b898a57d2 --- /dev/null +++ b/src/DbState.py @@ -0,0 +1,130 @@ +# +# 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$ + +#------------------------------------------------------------------------- +# +# Standard python modules +# +#------------------------------------------------------------------------- + +#------------------------------------------------------------------------- +# +# GNOME python modules +# +#------------------------------------------------------------------------- +import gobject +import gtk + +#------------------------------------------------------------------------- +# +# GRAMPS modules +# +#------------------------------------------------------------------------- +import GrampsDbBase +import GrampsDBCallback +import GrampsKeys +import NameDisplay + + +class History: + + def __init__(self): + self.history = [] + self.mhistory = [] + self.index = -1 + self.lock = False + + def clear(self): + self.history = [] + self.mistory = [] + self.index = -1 + self.lock = False + + def remove(self,person_handle,old_id=None): + """Removes a person from the history list""" + if old_id: + del_id = old_id + else: + del_id = person_handle + + hc = self.history.count(del_id) + for c in range(hc): + self.history.remove(del_id) + self.index -= 1 + + mhc = self.mhistory.count(del_id) + for c in range(mhc): + self.mhistory.remove(del_id) + +class DbState(GrampsDBCallback.GrampsDBCallback): + + __signals__ = { + 'database-changed' : (GrampsDbBase.GrampsDbBase,), + 'active-changed' : (str,), + } + + def __init__(self,window,status): + self.window = window + GrampsDBCallback.GrampsDBCallback.__init__(self) + self.db = GrampsDbBase.GrampsDbBase() + self.active = None + self.status = status + self.status_id = status.get_context_id('GRAMPS') + self.phistory = History() + + def clear_history(self): + self.phistory.clear() + + def change_active_person(self,person): + self.active = person + + def change_active_handle(self,handle): + self.emit('active-changed',(handle,)) + + def get_active_person(self): + return self.active + + def change_database(self,db): + self.db = db + self.emit('database-changed',(self.db,)) + + def modify_statusbar(self): + + self.status.pop(self.status_id) + if self.active == None: + self.status.push(self.status_id,"") + else: + if GrampsKeys.get_statusbar() <= 1: + pname = NameDisplay.displayer.display(self.active) + name = "[%s] %s" % (self.active.get_gramps_id(),pname) + else: + name = self.display_relationship() + self.status.push(self.status_id,name) + + while gtk.events_pending(): + gtk.main_iteration() + + def status_text(self,text): + self.status.pop(self.status_id) + self.status.push(self.status_id,text) + while gtk.events_pending(): + gtk.main_iteration() diff --git a/src/EditPerson.py b/src/EditPerson.py index facd82102..ee3fd74c6 100644 --- a/src/EditPerson.py +++ b/src/EditPerson.py @@ -796,7 +796,8 @@ class EditPerson: return changed def check_lds(self): - self.lds_baptism.set_date(unicode(self.ldsbap_date.get_text())) + date_str = unicode(self.ldsbap_date.get_text()) + DateHandler.set_date(self.lds_baptism,date_str) temple = _temple_names[self.ldsbap_temple.get_active()] if const.lds_temple_codes.has_key(temple): self.lds_baptism.set_temple(const.lds_temple_codes[temple]) @@ -804,7 +805,8 @@ class EditPerson: self.lds_baptism.set_temple("") self.lds_baptism.set_place_handle(self.get_place(self.ldsbapplace,1)) - self.lds_endowment.set_date(unicode(self.ldsend_date.get_text())) + date_str = unicode(self.ldsend_date.get_text()) + DateHandler.set_date(self.lds_endowment,date_str) temple = _temple_names[self.ldsend_temple.get_active()] if const.lds_temple_codes.has_key(temple): self.lds_endowment.set_temple(const.lds_temple_codes[temple]) @@ -812,7 +814,8 @@ class EditPerson: self.lds_endowment.set_temple("") self.lds_endowment.set_place_handle(self.get_place(self.ldsendowplace,1)) - self.lds_sealing.set_date(unicode(self.ldsseal_date.get_text())) + date_str = unicode(self.ldsseal_date.get_text()) + DateHandler.set_date(self.lds_sealing,date_str) temple = _temple_names[self.ldsseal_temple.get_active()] if const.lds_temple_codes.has_key(temple): self.lds_sealing.set_temple(const.lds_temple_codes[temple]) diff --git a/src/ListBox.py b/src/ListBox.py index b7f32950e..1ca1cb73a 100644 --- a/src/ListBox.py +++ b/src/ListBox.py @@ -384,7 +384,7 @@ class EventListBox(ReorderListBox): self.change_list.add(self.data[index]) def set_date(self,index,value): - self.data[index][1].set_date(value) + DateHandler.set_date(self.data[index][1],value) self.change_list.add(self.data[index]) def add(self,obj): @@ -536,7 +536,7 @@ class AddressListBox(ReorderListBox): button_list, titles, DdTargets.ADDRESS) def set_date(self,index,value): - self.data[index].set_date(value) + DateHandler.set_date(self.data[index],value) def set_addr(self,index,value): self.data[index].set_street(value) diff --git a/src/Marriage.py b/src/Marriage.py index 2f3cd2b24..3e97549a5 100644 --- a/src/Marriage.py +++ b/src/Marriage.py @@ -684,7 +684,7 @@ class Marriage: if not lds_ord: if date or temple or place or self.seal_stat: lds_ord = RelLib.LdsOrd() - lds_ord.set_date(date) + DateHandler.set_date(lds_ord,date) temple_code = const.lds_temple_codes.get(temple,"") lds_ord.set_temple(temple_code) lds_ord.set_status(self.seal_stat) diff --git a/src/PageView.py b/src/PageView.py new file mode 100644 index 000000000..e0c31fdd3 --- /dev/null +++ b/src/PageView.py @@ -0,0 +1,73 @@ +# +# Gramps - a GTK+/GNOME based genealogy program +# +# Copyright (C) 2001-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$ + +import gtk + +class PageView: + + def __init__(self,title,state): + self.title = title + self.state = state + self.action_list = [] + self.action_toggle_list = [] + self.action_group = None + self.widget = None + self.ui = "" + + def get_stock(self): + return gtk.STOCK_MEDIA_MISSING + + def get_ui(self): + return self.ui + + def get_title(self): + return self.title + + def get_display(self): + if not self.widget: + self.widget = self.build_widget() + return self.widget + + def build_widget(self): + assert False + + def define_actions(self): + assert False + + def _build_action_group(self): + self.action_group = gtk.ActionGroup(self.title) + if len(self.action_list) > 0: + self.action_group.add_actions(self.action_list) + if len(self.action_toggle_list) > 0: + self.action_group.add_toggle_actions(self.action_toggle_list) + + def add_action(self, name, stock_icon, label, accel=None, tip=None, callback=None): + self.action_list.append((name,stock_icon,label,accel,tip,callback)) + + def add_toggle_action(self, name, stock_icon, label, accel=None, tip=None, callback=None): + self.action_toggle_list.append((name,stock_icon,label,accel,tip,callback)) + + def get_actions(self): + if not self.action_group: + self.define_actions() + self._build_action_group() + return self.action_group diff --git a/src/PeopleView.py b/src/PeopleView.py index 802bf129e..3c448c2ab 100644 --- a/src/PeopleView.py +++ b/src/PeopleView.py @@ -78,6 +78,7 @@ class PeopleView: self.parent = parent self.parent.connect('database-changed',self.change_db) + self.parent.connect('active-changed',self.change_db) all = GenericFilter.GenericFilter() all.set_name(_("Entire Database")) @@ -243,15 +244,15 @@ class PeopleView: self.apply_filter() self.goto_active_person() - def goto_active_person(self): - if not self.parent.active_person or self.inactive: + def goto_active_person(self,obj=None): + if not self.state.active or self.inactive: return self.inactive = True - p = self.parent.active_person + p = self.state.active try: path = self.person_model.on_get_path(p.get_handle()) group_name = p.get_primary_name().get_group_name() - top_name = self.parent.db.get_name_group_mapping(group_name) + top_name = self.state.db.get_name_group_mapping(group_name) top_path = self.person_model.on_get_path(top_name) self.person_tree.expand_row(top_path,0) @@ -264,7 +265,7 @@ class PeopleView: except KeyError: self.person_selection.unselect_all() print "Person not currently available due to filter" - self.parent.active_person = p + self.state.active = p self.inactive = False def alpha_event(self,*obj): diff --git a/src/PersonView.py b/src/PersonView.py new file mode 100644 index 000000000..8f7c61cb5 --- /dev/null +++ b/src/PersonView.py @@ -0,0 +1,783 @@ +# -*- coding: utf-8 -*- +# +# Gramps - a GTK+/GNOME based genealogy program +# +# Copyright (C) 2000-2003 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$ + +#------------------------------------------------------------------------ +# +# standard python modules +# +#------------------------------------------------------------------------ + +from gettext import gettext as _ + +#------------------------------------------------------------------------- +# +# gtk +# +#------------------------------------------------------------------------- +import gtk +from gtk.gdk import ACTION_COPY, BUTTON1_MASK + +#------------------------------------------------------------------------- +# +# GRAMPS modules +# +#------------------------------------------------------------------------- +import PeopleModel +import PageView +import GenericFilter +import EditPerson +import NameDisplay +import Utils +import QuestionDialog + +from DdTargets import DdTargets + +column_names = [ + _('Name'), + _('ID') , + _('Gender'), + _('Birth Date'), + _('Birth Place'), + _('Death Date'), + _('Death Place'), + _('Spouse'), + _('Last Change'), + _('Cause of Death'), + ] + + +class PersonView(PageView.PageView): + + def __init__(self,state): + PageView.PageView.__init__(self,'Person View',state) + self.inactive = False + state.connect('database-changed',self.change_db) + state.connect('active-changed',self.goto_active_person) + + def setup_filter(self): + all = GenericFilter.GenericFilter() + all.set_name(_("Entire Database")) + all.add_rule(GenericFilter.Everyone([])) + + self.DataFilter = None + self.init_filters() + + def define_actions(self): + self.add_action('Add', gtk.STOCK_ADD, "_Add", callback=self.add) + self.add_action('Edit', gtk.STOCK_EDIT, "_Edit", callback=self.edit) + self.add_action('Remove', gtk.STOCK_REMOVE, "_Remove", callback=self.remove) + self.add_action('Forward',gtk.STOCK_GO_FORWARD,"_Forward", callback=self.fwd_clicked) + self.add_action('Back', gtk.STOCK_GO_BACK, "_Back", callback=self.back_clicked) + self.add_action('HomePerson', gtk.STOCK_HOME, "_Home", callback=self.home) + self.add_toggle_action('Filter', None, '_Filter', callback=self.filter_toggle) + + def get_stock(self): + return 'gramps-person' + + def build_tree(self): + self.person_model = PeopleModel.PeopleModel( + self.state.db, self.DataFilter, self.filter_invert.get_active()) + self.person_tree.set_model(self.person_model) + + def build_widget(self): + self.vbox = gtk.VBox() + self.vbox.set_border_width(4) + self.vbox.set_spacing(4) + + self.filterbar = gtk.HBox() + self.filterbar.set_spacing(4) + self.filter_text = gtk.Entry() + self.filter_label = gtk.Label('Label:') + self.filter_list = gtk.ComboBox() + self.filter_invert = gtk.CheckButton('Invert') + self.filter_button = gtk.Button('Apply') + self.filterbar.pack_start(self.filter_list,False) + self.filterbar.pack_start(self.filter_label,False) + self.filterbar.pack_start(self.filter_text,True) + self.filterbar.pack_start(self.filter_invert,False) + self.filterbar.pack_end(self.filter_button,False) + + self.filter_text.hide() + self.filter_text.set_sensitive(0) + self.filter_label.hide() + + self.person_tree = gtk.TreeView() + self.person_tree.set_rules_hint(True) + self.person_tree.set_headers_visible(True) + + scrollwindow = gtk.ScrolledWindow() + scrollwindow.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC) + scrollwindow.set_shadow_type(gtk.SHADOW_ETCHED_IN) + scrollwindow.add(self.person_tree) + + self.vbox.pack_start(self.filterbar,False) + self.vbox.pack_start(scrollwindow,True) + + # temporary hack + + self.renderer = gtk.CellRendererText() + self.inactive = False + + self.columns = [] + self.build_columns() + self.person_tree.connect('row_activated', self.alpha_event) + self.person_tree.connect('button-press-event', + self.on_plist_button_press) + self.person_tree.connect('drag_data_get', self.person_drag_data_get) + + + self.person_selection = self.person_tree.get_selection() + self.person_selection.set_mode(gtk.SELECTION_MULTIPLE) + self.person_selection.connect('changed',self.row_changed) + + self.vbox.set_focus_chain([self.person_tree,self.filter_list, self.filter_text, + self.filter_invert, self.filter_button]) + + a = gtk.ListStore(str,str) + self.person_tree.set_model(a) + + self.setup_filter() + + return self.vbox + + def ui_definition(self): + return ''' + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ''' + + def filter_toggle(self,obj): + if obj.get_active(): + self.filterbar.show() + else: + self.filterbar.hide() + + def add(self,obj): + person = RelLib.Person() + EditPerson.EditPerson(self, person, self.state.db, + None) + + def edit(self,obj): + EditPerson.EditPerson(self, self.state.active, self.state.db, + None) + + def remove(self,obj): + mlist = self.get_selected_objects() + if len(mlist) == 0: + return + + for sel in mlist: + p = self.state.db.get_person_from_handle(sel) + self.active_person = p + name = NameDisplay.displayer.display(p) + + msg = _('Deleting the person will remove the person ' + 'from the database.') + msg = "%s %s" % (msg,Utils.data_recover_msg) + QuestionDialog.QuestionDialog(_('Delete %s?') % name,msg, + _('_Delete Person'), + self.delete_person_response) + + def delete_person_response(self): + #self.disable_interface() + trans = self.state.db.transaction_begin() + + n = NameDisplay.displayer.display(self.active_person) + + if self.state.db.get_default_person() == self.active_person: + self.state.db.set_default_person_handle(None) + + for family_handle in self.active_person.get_family_handle_list(): + if not family_handle: + continue + family = self.state.db.get_family_from_handle(family_handle) + family_to_remove = False + if self.active_person.get_handle() == family.get_father_handle(): + if family.get_mother_handle(): + family.set_father_handle(None) + else: + family_to_remove = True + else: + if family.get_father_handle(): + family.set_mother_handle(None) + else: + family_to_remove = True + if family_to_remove: + for child_handle in family.get_child_handle_list(): + child = self.state.db.get_person_from_handle(child_handle) + child.remove_parent_family_handle(family_handle) + self.db.commit_person(child,trans) + self.state.db.remove_family(family_handle,trans) + else: + self.state.db.commit_family(family,trans) + + for (family_handle,mrel,frel) in self.active_person.get_parent_family_handle_list(): + if family_handle: + family = self.db.get_family_from_handle(family_handle) + family.remove_child_handle(self.active_person.get_handle()) + self.db.commit_family(family,trans) + + handle = self.active_person.get_handle() + + person = self.active_person + self.remove_from_person_list(person) + self.people_view.remove_from_history(handle) + self.state.db.remove_person(handle, trans) + + if self.state.phistory.index >= 0: + self.active_person = self.state.db.get_person_from_handle(self.state.phistory.history[self.index]) + else: + self.state.change_active_person(None) + self.state.db.transaction_commit(trans,_("Delete Person (%s)") % n) + #self.redraw_histmenu() + #self.enable_interface() + + def build_columns(self): + for column in self.columns: + self.person_tree.remove_column(column) + + column = gtk.TreeViewColumn(_('Name'), self.renderer,text=0) + column.set_resizable(True) + #column.set_clickable(True) + #column.connect('clicked',self.sort_clicked) + column.set_min_width(225) + column.set_sizing(gtk.TREE_VIEW_COLUMN_FIXED) + self.person_tree.append_column(column) + self.columns = [column] + + for pair in self.state.db.get_person_column_order(): + if not pair[0]: + continue + name = column_names[pair[1]] + column = gtk.TreeViewColumn(name, self.renderer, markup=pair[1]) + column.set_resizable(True) + column.set_min_width(60) + column.set_sizing(gtk.TREE_VIEW_COLUMN_GROW_ONLY) + self.columns.append(column) + self.person_tree.append_column(column) + + def row_changed(self,obj): + """Called with a row is changed. Check the selected objects from + the person_tree to get the IDs of the selected objects. Set the + active person to the first person in the list. If no one is + selected, set the active person to None""" + + selected_ids = self.get_selected_objects() + try: + person = self.state.db.get_person_from_handle(selected_ids[0]) + self.state.change_active_person(person) + self.goto_active_person() + except: + self.state.change_active_person(None) + + if len(selected_ids) == 1: + self.person_tree.drag_source_set(BUTTON1_MASK, + [DdTargets.PERSON_LINK.target()], + ACTION_COPY) + elif len(selected_ids) > 1: + self.person_tree.drag_source_set(BUTTON1_MASK, + [DdTargets.PERSON_LINK_LIST.target()], + ACTION_COPY) + self.state.modify_statusbar() + + def alpha_event(self,*obj): + pass + #self.parent.load_person(self.parent.active_person) + + def on_plist_button_press(self,obj,event): + if event.type == gtk.gdk.BUTTON_PRESS and event.button == 3: + self.build_people_context_menu(event) + + def person_drag_data_get(self, widget, context, sel_data, info, time): + selected_ids = self.get_selected_objects() + + if len(selected_ids) == 1: + sel_data.set(sel_data.target, 8, selected_ids[0]) + elif len(selected_ids) > 1: + sel_data.set(DdTargets.PERSON_LINK_LIST.drag_type,8, + pickle.dumps(selected_ids)) + + def apply_filter_clicked(self): + index = self.filter_list.get_active() + self.DataFilter = self.filter_model.get_filter(index) + if self.DataFilter.need_param: + qual = unicode(self.filter_text.get_text()) + self.DataFilter.set_parameter(qual) + self.apply_filter() + self.goto_active_person() + + def goto_active_person(self,obj=None): + if not self.state.active or self.inactive: + return + self.inactive = True + p = self.state.active + try: + path = self.person_model.on_get_path(p.get_handle()) + group_name = p.get_primary_name().get_group_name() + top_name = self.state.db.get_name_group_mapping(group_name) + top_path = self.person_model.on_get_path(top_name) + self.person_tree.expand_row(top_path,0) + + current = self.person_model.on_get_iter(path) + selected = self.person_selection.path_is_selected(path) + if current != p.get_handle() or not selected: + self.person_selection.unselect_all() + self.person_selection.select_path(path) + self.person_tree.scroll_to_cell(path,None,1,0.5,0) + except KeyError: + self.person_selection.unselect_all() + print "Person not currently available due to filter" + self.state.active = p + self.inactive = False + + def redisplay_person_list(self): + self.build_tree() + + def person_added(self,handle_list): + for node in handle_list: + person = self.state.db.get_person_from_handle(node) + top = person.get_primary_name().get_group_name() + self.person_model.rebuild_data(self.DataFilter) + if not self.person_model.is_visable(node): + continue + if (not self.person_model.sname_sub.has_key(top) or + len(self.person_model.sname_sub[top]) == 1): + path = self.person_model.on_get_path(top) + pnode = self.person_model.get_iter(path) + self.person_model.row_inserted(path,pnode) + path = self.person_model.on_get_path(node) + pnode = self.person_model.get_iter(path) + self.person_model.row_inserted(path,pnode) + + def person_removed(self,handle_list): + for node in handle_list: + person = self.state.db.get_person_from_handle(node) + if not self.person_model.is_visable(node): + continue + top = person.get_primary_name().get_group_name() + mylist = self.person_model.sname_sub.get(top,[]) + if mylist: + try: + path = self.person_model.on_get_path(node) + self.person_model.row_deleted(path) + if len(mylist) == 1: + path = self.person_model.on_get_path(top) + self.person_model.row_deleted(path) + except KeyError: + pass + self.person_model.rebuild_data(self.DataFilter,skip=node) + + def person_updated(self,handle_list): + for node in handle_list: + person = self.state.db.get_person_from_handle(node) + try: + oldpath = self.person_model.iter2path[node] + except: + return + pathval = self.person_model.on_get_path(node) + pnode = self.person_model.get_iter(pathval) + + # calculate the new data + + if person.primary_name.group_as: + surname = person.primary_name.group_as + else: + surname = self.state.db.get_name_group_mapping(person.primary_name.surname) + + + if oldpath[0] == surname: + self.person_model.build_sub_entry(surname) + else: + self.person_model.calculate_data(self.DataFilter) + + # find the path of the person in the new data build + newpath = self.person_model.temp_iter2path[node] + + # if paths same, just issue row changed signal + + if oldpath == newpath: + self.person_model.row_changed(pathval,pnode) + else: + # paths different, get the new surname list + + mylist = self.person_model.temp_sname_sub.get(oldpath[0],[]) + path = self.person_model.on_get_path(node) + + # delete original + self.person_model.row_deleted(pathval) + + # delete top node of original if necessar + if len(mylist)==0: + self.person_model.row_deleted(pathval[0]) + + # determine if we need to insert a new top node', + insert = not self.person_model.sname_sub.has_key(newpath[0]) + + # assign new data + self.person_model.assign_data() + + # insert new row if needed + if insert: + path = self.person_model.on_get_path(newpath[0]) + pnode = self.person_model.get_iter(path) + self.person_model.row_inserted(path,pnode) + + # insert new person + path = self.person_model.on_get_path(node) + pnode = self.person_model.get_iter(path) + self.person_model.row_inserted(path,pnode) + + self.goto_active_person() + + def change_db(self,db): + self.build_columns() + db.connect('person-add', self.person_added) + db.connect('person-update', self.person_updated) + db.connect('person-delete', self.person_removed) + db.connect('person-rebuild', self.redisplay_person_list) + self.apply_filter() + + def init_filters(self): + + cell = gtk.CellRendererText() + self.filter_list.clear() + self.filter_list.pack_start(cell,True) + self.filter_list.add_attribute(cell,'text',0) + + filter_list = [] + + all = GenericFilter.GenericFilter() + all.set_name(_("Entire Database")) + all.add_rule(GenericFilter.Everyone([])) + filter_list.append(all) + + all = GenericFilter.GenericFilter() + all.set_name(_("Females")) + all.add_rule(GenericFilter.IsFemale([])) + filter_list.append(all) + + all = GenericFilter.GenericFilter() + all.set_name(_("Males")) + all.add_rule(GenericFilter.IsMale([])) + filter_list.append(all) + + all = GenericFilter.GenericFilter() + all.set_name(_("People with unknown gender")) + all.add_rule(GenericFilter.HasUnknownGender([])) + filter_list.append(all) + + all = GenericFilter.GenericFilter() + all.set_name(_("Disconnected individuals")) + all.add_rule(GenericFilter.Disconnected([])) + filter_list.append(all) + + all = GenericFilter.ParamFilter() + all.set_name(_("People with names containing...")) + all.add_rule(GenericFilter.SearchName([])) + filter_list.append(all) + + all = GenericFilter.GenericFilter() + all.set_name(_("Adopted people")) + all.add_rule(GenericFilter.HaveAltFamilies([])) + filter_list.append(all) + + all = GenericFilter.GenericFilter() + all.set_name(_("People with images")) + all.add_rule(GenericFilter.HavePhotos([])) + filter_list.append(all) + + all = GenericFilter.GenericFilter() + all.set_name(_("People with incomplete names")) + all.add_rule(GenericFilter.IncompleteNames([])) + filter_list.append(all) + + all = GenericFilter.GenericFilter() + all.set_name(_("People with children")) + all.add_rule(GenericFilter.HaveChildren([])) + filter_list.append(all) + + all = GenericFilter.GenericFilter() + all.set_name(_("People with no marriage records")) + all.add_rule(GenericFilter.NeverMarried([])) + filter_list.append(all) + + all = GenericFilter.GenericFilter() + all.set_name(_("People with multiple marriage records")) + all.add_rule(GenericFilter.MultipleMarriages([])) + filter_list.append(all) + + all = GenericFilter.GenericFilter() + all.set_name(_("People without a known birth date")) + all.add_rule(GenericFilter.NoBirthdate([])) + filter_list.append(all) + + all = GenericFilter.GenericFilter() + all.set_name(_("People with incomplete events")) + all.add_rule(GenericFilter.PersonWithIncompleteEvent([])) + filter_list.append(all) + + all = GenericFilter.GenericFilter() + all.set_name(_("Families with incomplete events")) + all.add_rule(GenericFilter.FamilyWithIncompleteEvent([])) + filter_list.append(all) + + all = GenericFilter.ParamFilter() + all.set_name(_("People probably alive")) + all.add_rule(GenericFilter.ProbablyAlive([])) + filter_list.append(all) + + all = GenericFilter.GenericFilter() + all.set_name(_("People marked private")) + all.add_rule(GenericFilter.PeoplePrivate([])) + filter_list.append(all) + + all = GenericFilter.GenericFilter() + all.set_name(_("Witnesses")) + all.add_rule(GenericFilter.IsWitness([])) + filter_list.append(all) + + all = GenericFilter.ParamFilter() + all.set_name(_("People with records containing...")) + all.add_rule(GenericFilter.HasTextMatchingSubstringOf([])) + filter_list.append(all) + + all = GenericFilter.ParamFilter() + all.set_name(_("People with records matching regular expression...")) + all.add_rule(GenericFilter.HasTextMatchingRegexpOf([])) + filter_list.append(all) + + all = GenericFilter.GenericFilter() + all.set_name(_("People with notes")) + all.add_rule(GenericFilter.HasNote([])) + filter_list.append(all) + + all = GenericFilter.ParamFilter() + all.set_name(_("People with notes containing...")) + all.add_rule(GenericFilter.HasNoteMatchingSubstringOf([])) + filter_list.append(all) + + self.filter_model = GenericFilter.FilterStore(filter_list) + self.filter_list.set_model(self.filter_model) + self.filter_list.set_active(self.filter_model.default_index()) + self.filter_list.connect('changed',self.on_filter_name_changed) + self.filter_text.set_sensitive(0) + + def on_filter_name_changed(self,obj): + index = self.filter_list.get_active() + mime_filter = self.filter_model.get_filter(index) + qual = mime_filter.need_param + if qual: + self.filter_text.show() + self.filter_text.set_sensitive(1) + self.filter_label.show() + self.filter_label.set_text(mime_filter.get_rules()[0].labels[0]) + else: + self.filter_text.hide() + self.filter_text.set_sensitive(0) + self.filter_label.hide() + + def apply_filter(self,current_model=None): + #self.parent.status_text(_('Updating display...')) + self.build_tree() + #self.parent.modify_statusbar() + + def get_selected_objects(self): + (mode,paths) = self.person_selection.get_selected_rows() + mlist = [] + for path in paths: + node = self.person_model.on_get_iter(path) + mlist.append(self.person_model.on_get_value(node, PeopleModel.COLUMN_INT_ID)) + return mlist + + def remove_from_person_list(self,person): + """Remove the selected person from the list. A person object is + expected, not an ID""" + path = self.person_model.on_get_path(person.get_handle()) + (col,row) = path + if row > 0: + self.person_selection.select_path((col,row-1)) + elif row == 0 and self.person_model.on_get_iter(path): + self.person_selection.select_path(path) + + def build_backhistmenu(self,event): + """Builds and displays the menu with the back portion of the history""" + hobj = self.state.phistory + if hobj.index > 0: + backhistmenu = gtk.Menu() + backhistmenu.set_title(_('Back Menu')) + pids = hobj.history[:hobj.index] + pids.reverse() + num = 1 + for pid in pids: + if num <= 10: + f,r = divmod(num,10) + hotkey = "_%d" % r + elif num <= 20: + hotkey = "_%s" % chr(ord('a')+num-11) + elif num >= 21: + break + person = self.state.db.get_person_from_handle(pid) + item = gtk.MenuItem("%s. %s [%s]" % + (hotkey, + NameDisplay.displayer.display(person), + person.get_gramps_id())) + item.connect("activate",self.back_clicked,num) + item.show() + backhistmenu.append(item) + num = num + 1 + backhistmenu.popup(None,None,None,event.button,event.time) + + def back_pressed(self,obj,event): + if event.type == gtk.gdk.BUTTON_PRESS and event.button == 3: + self.build_backhistmenu(event) + + def build_fwdhistmenu(self,event): + """Builds and displays the menu with the forward portion of the history""" + if self.hindex < len(self.history)-1: + fwdhistmenu = gtk.Menu() + fwdhistmenu.set_title(_('Forward Menu')) + pids = self.history[self.hindex+1:] + num = 1 + for pid in pids: + if num <= 10: + f,r = divmod(num,10) + hotkey = "_%d" % r + elif num <= 20: + hotkey = "_%s" % chr(ord('a')+num-11) + elif num >= 21: + break + person = self.db.get_person_from_handle(pid) + item = gtk.MenuItem("%s. %s [%s]" % + (hotkey, + NameDisplay.displayer.display(person), + person.get_gramps_id())) + item.connect("activate",self.fwd_clicked,num) + item.show() + fwdhistmenu.append(item) + num = num + 1 + fwdhistmenu.popup(None,None,None,event.button,event.time) + + def fwd_pressed(self,obj,event): + if event.type == gtk.gdk.BUTTON_PRESS and event.button == 3: + self.build_fwdhistmenu(event) + + def fwd_clicked(self,obj,step=1): + print "fwd clicked" + hobj = self.state.phistory + hobj.lock = True + print hobj.history + if hobj.index+1 < len(hobj.history): + try: + hobj.index += step + handle = str(hobj.history[hobj.index]) + self.state.active = self.state.db.get_person_from_handle(handle) + self.state.modify_statusbar() + self.state.change_active_handle(handle) + hobj.mhistory.append(self.history[hobj.index]) + #self.redraw_histmenu() + self.set_buttons(True) + if hobj.index == len(hobj.history)-1: + self.fwdbtn.set_sensitive(False) + self.forward.set_sensitive(False) + else: + self.fwdbtn.set_sensitive(True) + self.forward.set_sensitive(True) + self.backbtn.set_sensitive(True) + self.back.set_sensitive(True) + except: + self.clear_history() + else: + self.fwdbtn.set_sensitive(False) + self.forward.set_sensitive(False) + self.backbtn.set_sensitive(True) + self.back.set_sensitive(True) + self.goto_active_person() + hobj.lock = False + + def back_clicked(self,obj,step=1): + hobj = self.state.phistory + hobj.lock = True + if hobj.index > 0: + try: + hobj.index -= step + handle = str(hobj.history[hobj.hindex]) + self.active = self.db.get_person_from_handle(handle) + self.modify_statusbar() + self.change_active_handle(handle) + hobj.mhistory.append(hobj.history[hobj.index]) + self.redraw_histmenu() + self.set_buttons(1) + if hobj.index == 0: + self.backbtn.set_sensitive(False) + self.back.set_sensitive(False) + else: + self.backbtn.set_sensitive(True) + self.back.set_sensitive(True) + self.fwdbtn.set_sensitive(True) + self.forward.set_sensitive(True) + except: + hobj.clear_history() + else: + self.backbtn.set_sensitive(False) + self.back.set_sensitive(False) + self.fwdbtn.set_sensitive(True) + self.forward.set_sensitive(True) + self.goto_active_person() + hobj.lock = False + + def home(self,obj): + defperson = self.state.db.get_default_person() + if defperson: + self.state.change_active_person(defperson) + self.goto_active_person() diff --git a/src/ReadXML.py b/src/ReadXML.py index a82c9bb08..1e6df568a 100644 --- a/src/ReadXML.py +++ b/src/ReadXML.py @@ -1264,9 +1264,9 @@ class GrampsParser: def stop_date(self,tag): if tag: if self.address: - self.address.set_date(tag) + DateHandler.set_date(self.address,tag) else: - self.event.set_date(tag) + DateHandler.set_date(self.event,tag) def stop_first(self,tag): self.name.set_first_name(tag) diff --git a/src/ViewManager.py b/src/ViewManager.py new file mode 100644 index 000000000..17ac2acc8 --- /dev/null +++ b/src/ViewManager.py @@ -0,0 +1,677 @@ +# +# 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 +# + +#------------------------------------------------------------------------- +# +# Standard python modules +# +#------------------------------------------------------------------------- + +from gettext import gettext as _ +from bsddb import db +import os + +#------------------------------------------------------------------------- +# +# GNOME modules +# +#------------------------------------------------------------------------- +import gtk +try: + from gnomevfs import get_mime_type +except: + from gnome.vfs import get_mime_type + +#------------------------------------------------------------------------- +# +# GRAMPS modules +# +#------------------------------------------------------------------------- +import DbState +import DbPrompter +import const +import PluginMgr +import GrampsKeys +import GrampsDbBase +import GrampsBSDDB +import GrampsGEDDB +import GrampsXMLDB +import GrampsCfg +import Errors +import DisplayTrace +import Utils + +#------------------------------------------------------------------------- +# +# Constants +# +#------------------------------------------------------------------------- +_KNOWN_FORMATS = { + const.app_gramps : _('GRAMPS (grdb)'), + const.app_gramps_xml : _('GRAMPS XML'), + const.app_gedcom : _('GEDCOM'), +} + +uidefault = ''' + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +''' + +class ViewManager: + + def __init__(self): + + self.active_page = None + self.views = [] + self.window = gtk.Window() + self.window.connect('destroy', lambda w: gtk.main_quit()) + self.window.set_size_request(775,500) + + self.statusbar = gtk.Statusbar() + self.state = DbState.DbState(self.window,self.statusbar) + + self.RelClass = PluginMgr.relationship_class + + vbox = gtk.VBox() + self.window.add(vbox) + hbox = gtk.HBox() + hbox.set_border_width(4) + self.ebox = gtk.EventBox() + self.bbox = gtk.VBox() + self.ebox.add(self.bbox) + hbox.pack_start(self.ebox,False) + + self.notebook = gtk.Notebook() + self.notebook.set_show_tabs(False) + self.build_ui_manager() + + hbox.pack_start(self.notebook,True) + self.menubar = self.uimanager.get_widget('/MenuBar') + self.toolbar = self.uimanager.get_widget('/ToolBar') + vbox.pack_start(self.menubar, False) + vbox.pack_start(self.toolbar, False) + vbox.add(hbox) + vbox.pack_end(self.statusbar,False) + + self.notebook.connect('switch-page',self.change_page) + + self.window.show_all() + + def init_interface(self): + self.create_pages() + self.change_page(None,None,0) + + def set_color(self,obj): + style = obj.get_style().copy() + new_color = style.bg[gtk.STATE_ACTIVE] + style.bg[gtk.STATE_NORMAL] = new_color + style.bg[gtk.STATE_PRELIGHT] = new_color + style.bg[gtk.STATE_ACTIVE] = new_color + style.bg[gtk.STATE_INSENSITIVE] = new_color + style.bg[gtk.STATE_SELECTED] = new_color + obj.set_style(style) + + def build_ui_manager(self): + self.merge_id = 0 + self.uimanager = gtk.UIManager() + + accelgroup = self.uimanager.get_accel_group() + self.window.add_accel_group(accelgroup) + + self.actiongroup = gtk.ActionGroup('MainWindow') + self.actiongroup.add_actions([ + # Name Stock Icon Label + ('FileMenu', None, '_File'), + ('New', gtk.STOCK_NEW, '_New', "n", None, self.on_new_activate), + ('Open', gtk.STOCK_OPEN, '_Open', "o", None, self.on_open_activate), + ('OpenRecent', gtk.STOCK_OPEN, 'Open _Recent'), + ('Import', gtk.STOCK_CONVERT, '_Import'), + ('SaveAs', gtk.STOCK_SAVE_AS, '_Save As'), + ('Export', gtk.STOCK_SAVE_AS, '_Export'), + ('Abandon', gtk.STOCK_REVERT_TO_SAVED, '_Abandon changes and quit'), + ('Quit', gtk.STOCK_QUIT, '_Quit', 'q', None, gtk.main_quit), + ('Undo', gtk.STOCK_UNDO, '_Undo', 'z' ), + ('Preferences',gtk.STOCK_PREFERENCES, '_Preferences'), + ('ColumnEdit', gtk.STOCK_PROPERTIES, '_Column Editor'), + ('CmpMerge', None, '_Compare and merge'), + ('FastMerge', None, '_Fast merge'), + ('ScratchPad', gtk.STOCK_PASTE, '_ScratchPad', None, None, self.on_scratchpad), + ('Reports', gtk.STOCK_DND_MULTIPLE, '_Reports'), + ('Tools', gtk.STOCK_EXECUTE, '_Tools'), + ('EditMenu', None, '_Edit'), + ('GoMenu', None, '_Go'), + ('ViewMenu', None, '_View'), + ('BookMenu', None, '_Bookmarks'), + ('AddBook', gtk.STOCK_INDEX, '_Add bookmark', 'd'), + ('EditBook', None, '_Edit bookmarks', 'b'), + ('GoToBook', gtk.STOCK_JUMP_TO, '_Go to bookmark'), + ('ReportsMenu',None, '_Reports'), + ('ToolsMenu', None, '_Tools'), + ('WindowsMenu',None, '_Windows'), + ('HelpMenu', None, '_Help'), + ('About', gtk.STOCK_ABOUT, '_About'), + ]) + + self.actiongroup.add_toggle_actions([ + ('Sidebar', None, '_Sidebar', None, None, self.sidebar_toggle), + ('Toolbar', None, '_Toolbar', None, None, self.toolbar_toggle), + ]) + + merge_id = self.uimanager.add_ui_from_string(uidefault) + self.uimanager.insert_action_group(self.actiongroup,1) + + def sidebar_toggle(self,obj): + if obj.get_active(): + self.ebox.show() + self.notebook.set_show_tabs(False) + else: + self.ebox.hide() + self.notebook.set_show_tabs(True) + + def toolbar_toggle(self,obj): + if obj.get_active(): + self.toolbar.show() + else: + self.toolbar.hide() + + def register_view(self, view): + self.views.append(view) + + def create_pages(self): + self.pages = [] + index = 0 + self.set_color(self.ebox) + for page_def in self.views: + page = page_def(self.state) + + # create icon/label for notebook + hbox = gtk.HBox() + image = gtk.Image() + image.set_from_stock(page.get_stock(),gtk.ICON_SIZE_MENU) + hbox.pack_start(image,False) + hbox.add(gtk.Label(page.get_title())) + hbox.show_all() + + # create notebook page and add to notebook + page_display = page.get_display() + page_display.show_all() + self.notebook.append_page(page_display,hbox) + self.pages.append(page) + + # create the button add it to the sidebar + button = gtk.Button(stock=page.get_stock(),label=page.get_title()) + button.set_border_width(4) + button.set_relief(gtk.RELIEF_NONE) + button.set_alignment(0,0.5) + button.connect('clicked',lambda x,y : self.notebook.set_current_page(y), + index) + self.set_color(button) + button.show() + index += 1 + self.bbox.pack_start(button,False) + + def change_page(self,obj,page,num): + if self.merge_id: + self.uimanager.remove_ui(self.merge_id) + if self.active_page: + self.uimanager.remove_action_group(self.active_page.get_actions()) + + if len(self.pages) > 0: + self.active_page = self.pages[num] + + self.uimanager.insert_action_group(self.active_page.get_actions(),1) + self.merge_id = self.uimanager.add_ui_from_string(self.active_page.ui_definition()) + + def on_open_activate(self,obj): + + choose = gtk.FileChooserDialog(_('GRAMPS: Open database'), + self.state.window, + gtk.FILE_CHOOSER_ACTION_OPEN, + (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_grdb_filter(choose) + add_xml_filter(choose) + add_gedcom_filter(choose) + + format_list = [const.app_gramps,const.app_gramps_xml,const.app_gedcom] + # Add more data type selections if opening existing db + for (importData,mime_filter,mime_type,native_format,format_name) in PluginMgr.import_list: + if not native_format: + choose.add_filter(mime_filter) + format_list.append(mime_type) + _KNOWN_FORMATS[mime_type] = format_name + + (box,type_selector) = format_maker(format_list) + choose.set_extra_widget(box) + + # Suggested folder: try last open file, last import, last export, + # then home. + default_dir = os.path.split(GrampsKeys.get_lastfile())[0] + os.path.sep + if len(default_dir)<=1: + default_dir = GrampsKeys.get_last_import_dir() + if len(default_dir)<=1: + default_dir = GrampsKeys.get_last_export_dir() + if len(default_dir)<=1: + default_dir = '~/' + + choose.set_current_folder(default_dir) + response = choose.run() + if response == gtk.RESPONSE_OK: + filename = choose.get_filename() + if len(filename) == 0: + return False + filetype = type_selector.get_value() + if filetype == 'auto': + filetype = get_mime_type(filename) + (the_path,the_file) = os.path.split(filename) + choose.destroy() + if filetype in [const.app_gramps,const.app_gramps_xml, + const.app_gedcom]: + + try: + return self.open_native(filename,filetype) + except db.DBInvalidArgError, msg: + QuestionDialog.ErrorDialog( + _("Could not open file: %s") % filename, msg[1]) + return False + except: + import DisplayTrace + DisplayTrace.DisplayTrace() + return False + + # The above native formats did not work, so we need to + # look up the importer for this format + # and create an empty native database to import data in +# for (importData,mime_filter,mime_type,native_format,format_name) in PluginMgr.import_list: +# if filetype == mime_type or the_file == mime_type: +# QuestionDialog.OkDialog( +# _("Opening non-native format"), +# _("New GRAMPS database has to be set up " +# "when opening non-native formats. The " +# "following dialog will let you select " +# "the new database."), +# self.state.window) +# prompter = NewNativeDbPrompter(self.parent,self.parent_window) +# if prompter.chooser(): +# importData(self.state.db,filename) +# #self.parent.import_tool_callback() +# return True +# else: +# return False + QuestionDialog.ErrorDialog( + _("Could not open file: %s") % filename, + _('File type "%s" is unknown to GRAMPS.\n\nValid types are: GRAMPS database, GRAMPS XML, GRAMPS package, and GEDCOM.') % filetype) + choose.destroy() + return False + + def on_new_activate(self,obj): + + choose = gtk.FileChooserDialog(_('GRAMPS: Create GRAMPS database'), + self.state.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_grdb_filter(choose) + + # Suggested folder: try last open file, import, then last export, + # then home. + default_dir = os.path.split(GrampsKeys.get_lastfile())[0] + os.path.sep + if len(default_dir)<=1: + default_dir = GrampsKeys.get_last_import_dir() + if len(default_dir)<=1: + default_dir = GrampsKeys.get_last_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]) + + while (True): + response = choose.run() + if response == gtk.RESPONSE_OK: + filename = choose.get_filename() + if filename == None: + continue + if os.path.splitext(filename)[1] != ".grdb": + filename = filename + ".grdb" + choose.destroy() + try: + self.state.db.close() + except: + pass + self.state.db = GrampsBSDDB.GrampsBSDDB() + self.read_file(filename) + # Add the file to the recent items + #RecentFiles.recent_files(filename,const.app_gramps) + #self.parent.build_recent_menu() + return True + else: + choose.destroy() + return False + choose.destroy() + return False + + def open_native(self,filename,filetype): + """ + Open native database and return the status. + """ + + (the_path,the_file) = os.path.split(filename) + GrampsKeys.save_last_import_dir(the_path) + + success = False + if filetype == const.app_gramps: + self.state.db = GrampsBSDDB.GrampsBSDDB() + msgxml = gtk.glade.XML(const.gladeFile, "load_message","gramps") + msg_top = msgxml.get_widget('load_message') + msg_label = msgxml.get_widget('message') + + def update_msg(msg): + msg_label.set_text("%s" % msg) + msg_label.set_use_markup(True) + while gtk.events_pending(): + gtk.main_iteration() + + success = self.read_file(filename,update_msg) + msg_top.destroy() + elif filetype == const.app_gramps_xml: + self.state.db = GrampsXMLDB.GrampsXMLDB() + success = self.read_file(filename) + elif filetype == const.app_gedcom: + self.state.db = GrampsGEDDB.GrampsGEDDB() + success = self.read_file(filename) + + #if success: + # Add the file to the recent items + #RecentFiles.recent_files(filename,filetype) + #parent.build_recent_menu() + + return success + + def read_file(self,filename,callback=None): + mode = "w" + filename = os.path.normpath(os.path.abspath(filename)) + + if os.path.isdir(filename): + ErrorDialog(_('Cannot open database'), + _('The selected file is a directory, not ' + 'a file.\nA GRAMPS database must be a file.')) + return 0 + elif os.path.exists(filename): + if not os.access(filename,os.R_OK): + ErrorDialog(_('Cannot open database'), + _('You do not have read access to the selected ' + 'file.')) + return 0 + elif not os.access(filename,os.W_OK): + mode = "r" + WarningDialog(_('Read only database'), + _('You do not have write access to the selected ' + 'file.')) + + try: + if self.load_database(filename,callback,mode=mode) == 1: + if filename[-1] == '/': + filename = filename[:-1] + name = os.path.basename(filename) + if self.state.db.readonly: + self.state.window.set_title("%s (%s) - GRAMPS" % (name,_('Read Only'))) + else: + self.state.window.set_title("%s - GRAMPS" % name) + else: + GrampsKeys.save_last_file("") + ErrorDialog(_('Cannot open database'), + _('The database file specified could not be opened.')) + return 0 + except ( IOError, OSError, Errors.FileVersionError), msg: + ErrorDialog(_('Cannot open database'),str(msg)) + return 0 + except (db.DBAccessError,db.DBError), msg: + ErrorDialog(_('Cannot open database'), + _('%s could not be opened.' % filename) + '\n' + msg[1]) + return 0 + except Exception: + DisplayTrace.DisplayTrace() + return 0 + + # Undo/Redo always start with standard labels and insensitive state + #self.undo_callback(None) + #self.redo_callback(None) + #self.goto_active_person() + return 1 + + def load_database(self,name,callback=None,mode="w"): + + filename = name + + if self.state.db.load(filename,callback,mode) == 0: + return 0 + val = self.post_load(name,callback) + return val + + def post_load(self,name,callback=None): + if not self.state.db.version_supported(): + raise Errors.FileVersionError( + "The database version is not supported by this version of GRAMPS.\n" + "Please upgrade to the corresponding version or use XML for porting" + "data between different database versions.") + + self.state.db.set_save_path(name) + + res = self.state.db.get_researcher() + owner = GrampsCfg.get_researcher() + if res.get_name() == "" and owner.get_name(): + self.state.db.set_researcher(owner) + + #self.setup_bookmarks() + + #self.state.db.set_undo_callback(self.undo_callback) + #self.state.db.set_redo_callback(self.redo_callback) + + if self.state.db.need_upgrade(): + if callback: + callback(_('Upgrading database...')) + self.state.db.upgrade() + + GrampsKeys.save_last_file(name) + + self.relationship = self.RelClass(self.state.db) + self.state.emit("database-changed", (self.state.db,)) + + #self.change_active_person(self.find_initial_person()) + #self.goto_active_person() + + #if callback: + # callback(_('Setup complete')) + #self.enable_buttons(True) + return 1 + + def on_scratchpad(self,obj): + import ScratchPad + ScratchPad.ScratchPadWindow(self.db, self) + +def add_all_files_filter(chooser): + """ + Add an all-permitting filter to the file chooser dialog. + """ + mime_filter = gtk.FileFilter() + mime_filter.set_name(_('All files')) + mime_filter.add_pattern('*') + chooser.add_filter(mime_filter) + +def add_gramps_files_filter(chooser): + """ + Add an all-GRAMPS filter to the file chooser dialog. + """ + mime_filter = gtk.FileFilter() + mime_filter.set_name(_('All GRAMPS files')) + mime_filter.add_mime_type(const.app_gramps) + mime_filter.add_mime_type(const.app_gramps_xml) + mime_filter.add_mime_type(const.app_gedcom) + chooser.add_filter(mime_filter) + +def add_grdb_filter(chooser): + """ + Add a GRDB filter to the file chooser dialog. + """ + mime_filter = gtk.FileFilter() + mime_filter.set_name(_('GRAMPS databases')) + mime_filter.add_mime_type(const.app_gramps) + chooser.add_filter(mime_filter) + +def add_xml_filter(chooser): + """ + Add a GRAMPS XML filter to the file chooser dialog. + """ + mime_filter = gtk.FileFilter() + mime_filter.set_name(_('GRAMPS XML databases')) + mime_filter.add_mime_type(const.app_gramps_xml) + chooser.add_filter(mime_filter) + +def add_gedcom_filter(chooser): + """ + Add a GEDCOM filter to the file chooser dialog. + """ + mime_filter = gtk.FileFilter() + mime_filter.set_name(_('GEDCOM files')) + mime_filter.add_mime_type(const.app_gedcom) + chooser.add_filter(mime_filter) + +#------------------------------------------------------------------------- +# +# Format selectors and filters +# +#------------------------------------------------------------------------- +class GrampsFormatWidget(gtk.ComboBox): + + def __init__(self): + gtk.ComboBox.__init__(self,model=None) + + def set(self,format_list): + self.store = gtk.ListStore(str) + self.set_model(self.store) + cell = gtk.CellRendererText() + self.pack_start(cell,True) + self.add_attribute(cell,'text',0) + self.format_list = format_list + + for format,label in format_list: + self.store.append(row=[label]) + self.set_active(0) + + def get_value(self): + active = self.get_active() + if active < 0: + return None + return self.format_list[active][0] + +def format_maker(formats): + """ + A factory function making format selection widgets. + + Accepts a list of formats to include into selector. + The auto selection is always added as the first one. + The returned box contains both the label and the selector. + """ + format_list = [ ('auto',_('Automatically detected')) ] + for format in formats: + if _KNOWN_FORMATS.has_key(format): + format_list.append( (format,_KNOWN_FORMATS[format]) ) + + type_selector = GrampsFormatWidget() + type_selector.set(format_list) + + box = gtk.HBox() + label = gtk.Label(_('Select file _type:')) + label.set_use_underline(True) + label.set_mnemonic_widget(type_selector) + box.pack_start(label,expand=False,fill=False,padding=6) + box.add(type_selector) + box.show_all() + return (box,type_selector) + diff --git a/src/gramps_main.py b/src/gramps_main.py index 11c4adefa..bfcce3633 100755 --- a/src/gramps_main.py +++ b/src/gramps_main.py @@ -1,7 +1,7 @@ # # Gramps - a GTK+/GNOME based genealogy program # -# Copyright (C) 2000-2005 Donald N. Allingham +# Copyright (C) 2001-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 @@ -20,107 +20,106 @@ # $Id$ -#------------------------------------------------------------------------- -# -# Standard python modules -# -#------------------------------------------------------------------------- -import os - -#------------------------------------------------------------------------- -# -# internationalization -# -#------------------------------------------------------------------------- -from gettext import gettext as _ - -#------------------------------------------------------------------------- -# -# GTK/Gnome modules -# -#------------------------------------------------------------------------- -import gobject import gtk -import gnome -import gnome.ui -import gtk.glade -import gtk.gdk - -#------------------------------------------------------------------------- -# -# gramps modules -# -#------------------------------------------------------------------------- -import RelLib -import GrampsDbBase -import GrampsBSDDB -import PedView -import MediaView -import PlaceView -import FamilyView -import EventView -import SourceView -import RepositoryView -import PeopleView -import GenericFilter +import ViewManager +import PersonView +import ArgHandler import DisplayTrace -import const -import Plugins -import PluginMgr -import Utils -import Bookmarks import GrampsKeys import GrampsCfg -import EditPerson -import DbPrompter -import TipOfDay -import ArgHandler -import Exporter -import RelImage -import RecentFiles -import NameDisplay +import const import Errors -import GrampsDBCallback +import PluginMgr from GrampsMime import mime_type_is_defined -from QuestionDialog import * -from bsddb import db +from QuestionDialog import ErrorDialog -#------------------------------------------------------------------------- -# -# Constants -# -#------------------------------------------------------------------------- -_HOMEPAGE = "http://gramps-project.org" -_MAILLIST = "http://sourceforge.net/mail/?group_id=25770" -_BUGREPORT = "http://sourceforge.net/tracker/?group_id=25770&atid=385137" +import gnome -PERSON_VIEW = 0 -FAMILY_VIEW1 = 1 -FAMILY_VIEW2 = 2 -PEDIGREE_VIEW = 3 -SOURCE_VIEW = 4 -REPOSITORY_VIEW = 5 -PLACE_VIEW = 6 -MEDIA_VIEW = 7 -EVENT_VIEW = 8 -#------------------------------------------------------------------------- -# -# Main GRAMPS class -# -#------------------------------------------------------------------------- -class Gramps(GrampsDBCallback.GrampsDBCallback): +iconpaths = ["/usr/share/gramps","~/devel/srcx"] - __signals__ = { - 'database-changed' : (GrampsDbBase.GrampsDbBase,), - 'active-changed' : (str,), +def register_stock_icons (): + import os + items = { + 'people48.png': ('gramps-person', 'Person', gtk.gdk.CONTROL_MASK, 0, ''), + 'family48.png': ('gramps-family', 'Family', gtk.gdk.CONTROL_MASK, 0, ''), + 'repos.png' : ('gramps-repository', 'Repositories', gtk.gdk.CONTROL_MASK, 0, ''), + 'sources.png' : ('gramps-source', 'Sources', gtk.gdk.CONTROL_MASK, 0, ''), + 'events.png' : ('gramps-event', 'Events', gtk.gdk.CONTROL_MASK, 0, ''), + 'place.png' : ('gramps-place', 'Places', gtk.gdk.CONTROL_MASK, 0, ''), } + + # Register our stock items + gtk.stock_add (items.values()) + + # Add our custom icon factory to the list of defaults + factory = gtk.IconFactory () + factory.add_default () + + + keys = items.keys() + for key in keys: + + for dirname in iconpaths: + icon_file = os.path.expanduser(os.path.join(dirname,key)) + if os.path.isfile(icon_file): + break + else: + icon_file = os.path.join(iconpaths[0],'gramps.png') + + pixbuf = gtk.gdk.pixbuf_new_from_file (icon_file) + pixbuf = pixbuf.add_alpha(True, chr(0xff), chr(0xff), chr(0xff)) + + # Register icon to accompany stock item + if pixbuf: + icon_set = gtk.IconSet (pixbuf) + factory.add (items[key][0], icon_set) + else: + print 'failed to load GTK logo for toolbar' + +# class EventView(ListView): + +# def __init__(self): +# PageView.__init__(self,'Events') + +# def define_actions(self): +# self.add_action('Add', gtk.STOCK_ADD, '_Add', callback=self.add), +# self.add_action('Edit', gtk.STOCK_EDIT, "_Edit") +# self.add_action('Remove',gtk.STOCK_REMOVE,"_Remove") + +# def get_stock(self): +# return 'gramps-event' + +# def ui_definition(self): +# return ''' +# +# +# +# +# +# +# +# +# +# +# +# +# +# +# +# +# ''' + +# def add(self,obj): +# print "Event Add" + + + +class Gramps: def __init__(self,args): - GrampsDBCallback.GrampsDBCallback.__init__(self) - try: self.program = gnome.program_init('gramps',const.version, gnome.libgnome_module_info_get(), @@ -132,30 +131,9 @@ class Gramps(GrampsDBCallback.GrampsDBCallback): self.program.set_property('app-sysconfdir','%s/etc' % const.prefixdir) self.program.set_property('app-prefix', const.prefixdir) - self.parents_index = 0 - self.active_person = None - self.bookmarks = None - self.c_details = 6 - self.cl = 0 - self.lock_history = False - - self.history = [] - self.mhistory = [] - self.hindex = -1 - - self.undo_active = False - - self.db = GrampsBSDDB.GrampsBSDDB() - try: GrampsCfg.loadConfig() self.welcome() - self.RelClass = PluginMgr.relationship_class - self.relationship = self.RelClass(self.db) - self.gtop = gtk.glade.XML(const.gladeFile, "gramps", "gramps") - - self.init_interface() - except OSError, msg: ErrorDialog(_("Configuration error"),str(msg)) return @@ -186,27 +164,29 @@ class Gramps(GrampsDBCallback.GrampsDBCallback): self.researcher_key_update) GrampsKeys.client.notify_add("/apps/gramps/interface/statusbar", self.statusbar_key_update) - GrampsKeys.client.notify_add("/apps/gramps/interface/toolbar", - self.toolbar_key_update) - GrampsKeys.client.notify_add("/apps/gramps/interface/toolbar-on", - self.toolbar_on_key_update) - GrampsKeys.client.notify_add("/apps/gramps/interface/filter", - self.filter_key_update) - GrampsKeys.client.notify_add("/apps/gramps/interface/view", - self.sidebar_key_update) - GrampsKeys.client.notify_add("/apps/gramps/interface/familyview", - self.familyview_key_update) - GrampsKeys.client.notify_add("/apps/gramps/preferences/name-format", - self.familyview_key_update) - GrampsKeys.client.notify_add("/apps/gramps/preferences/date-format", - self.date_format_key_update) - self.topWindow.show() +# GrampsKeys.client.notify_add("/apps/gramps/interface/toolbar", +## self.toolbar_key_update) +# GrampsKeys.client.notify_add("/apps/gramps/interface/toolbar-on", +# self.toolbar_on_key_update) +# GrampsKeys.client.notify_add("/apps/gramps/interface/filter", +# self.filter_key_update) +# GrampsKeys.client.notify_add("/apps/gramps/interface/view", +# self.sidebar_key_update) +# GrampsKeys.client.notify_add("/apps/gramps/interface/familyview", +# self.familyview_key_update) +# GrampsKeys.client.notify_add("/apps/gramps/preferences/name-format", +# self.familyview_key_update) +# GrampsKeys.client.notify_add("/apps/gramps/preferences/date-format", +# self.date_format_key_update) + + register_stock_icons() + a = ViewManager.ViewManager() + a.register_view(PersonView.PersonView) + a.init_interface() if GrampsKeys.get_usetips(): TipOfDay.TipOfDay(self) - self.db.set_researcher(GrampsCfg.get_researcher()) - def welcome(self): if GrampsKeys.get_welcome() >= 200: return @@ -251,17 +231,14 @@ class Gramps(GrampsDBCallback.GrampsDBCallback): GrampsKeys.save_welcome(200) GrampsKeys.sync() - def date_format_key_update(self,client,cnxn_id,entry,data): - GrampsCfg.set_calendar_date_format() - self.familyview_key_update(client,cnxn_id,entry,data) - def researcher_key_update(self,client,cnxn_id,entry,data): - self.db.set_person_id_prefix(GrampsKeys.get_person_id_prefix()) - self.db.set_family_id_prefix(GrampsKeys.get_family_id_prefix()) - self.db.set_source_id_prefix(GrampsKeys.get_source_id_prefix()) - self.db.set_object_id_prefix(GrampsKeys.get_object_id_prefix()) - self.db.set_place_id_prefix(GrampsKeys.get_place_id_prefix()) - self.db.set_event_id_prefix(GrampsKeys.get_event_id_prefix()) + pass +# self.db.set_person_id_prefix(GrampsKeys.get_person_id_prefix()) +# self.db.set_family_id_prefix(GrampsKeys.get_family_id_prefix()) +# self.db.set_source_id_prefix(GrampsKeys.get_source_id_prefix()) +# self.db.set_object_id_prefix(GrampsKeys.get_object_id_prefix()) +# self.db.set_place_id_prefix(GrampsKeys.get_place_id_prefix()) +# self.db.set_event_id_prefix(GrampsKeys.get_event_id_prefix()) def statusbar_key_update(self,client,cnxn_id,entry,data): self.modify_statusbar() @@ -273,1773 +250,7 @@ class Gramps(GrampsDBCallback.GrampsDBCallback): else: self.toolbar.set_style(the_style) - def toolbar_on_key_update(self,client,cnxn_id,entry,data): - is_on = GrampsKeys.get_toolbar_on() - self.toolbar_btn.set_active(is_on) - self.enable_toolbar(is_on) - def filter_key_update(self,client,cnxn_id,entry,data): - is_on = GrampsKeys.get_filter() - self.filter_btn.set_active(is_on) - self.enable_filter(is_on) - def sidebar_key_update(self,client,cnxn_id,entry,data): - is_on = GrampsKeys.get_view() - self.sidebar_btn.set_active(is_on) - self.enable_sidebar(is_on) - - def familyview_key_update(self,client,cnxn_id,entry,data): - self.family_view.init_interface() - self.update_display(1) - self.goto_active_person() - - def init_interface(self): - """Initializes the GLADE interface, and gets references to the - widgets that it will need. - """ - - self.topWindow = self.gtop.get_widget("gramps") - - self.report_button = self.gtop.get_widget("reports") - self.tool_button = self.gtop.get_widget("tools") - self.remove_button = self.gtop.get_widget("removebtn") - self.edit_button = self.gtop.get_widget("editbtn") - self.remove_item = self.gtop.get_widget("remove_item") - self.edit_item = self.gtop.get_widget("edit_item") - self.sidebar = self.gtop.get_widget('side_event') - self.filterbar = self.gtop.get_widget('filterbar') - - self.tool_button.set_sensitive(0) - self.report_button.set_sensitive(0) - self.remove_button.set_sensitive(0) - self.edit_button.set_sensitive(0) - self.remove_item.set_sensitive(0) - self.edit_item.set_sensitive(0) - - set_panel(self.sidebar) - set_panel(self.gtop.get_widget('side_people')) - set_panel(self.gtop.get_widget('side_family')) - set_panel(self.gtop.get_widget('side_pedigree')) - set_panel(self.gtop.get_widget('side_sources')) - set_panel(self.gtop.get_widget('side_places')) - set_panel(self.gtop.get_widget('side_media')) - set_panel(self.gtop.get_widget('side_events')) - set_panel(self.gtop.get_widget('side_repos')) - - self.sidebar_btn = self.gtop.get_widget("sidebar1") - self.filter_btn = self.gtop.get_widget("filter1") - self.toolbar_btn = self.gtop.get_widget("toolbar2") - self.statusbar = self.gtop.get_widget("statusbar") - self.progress = self.statusbar.get_children()[0] - self.progress.set_pulse_step(0.01) - - self.filter_list = self.gtop.get_widget("filter_list") - self.views = self.gtop.get_widget("views") - self.merge_button= self.gtop.get_widget("merge") - self.canvas = self.gtop.get_widget("canvas1") - self.toolbar = self.gtop.get_widget("toolbar1") - self.toolbardock = self.gtop.get_widget("dockitem2") - self.filter_text = self.gtop.get_widget('filter') - self.filter_label= self.gtop.get_widget('filter_label') - self.filter_invert= self.gtop.get_widget('filter_invert') - self.qual_label = self.gtop.get_widget("qual") - self.child_type = self.gtop.get_widget("childtype") - self.spouse_tab = self.gtop.get_widget("lab_or_list") - self.pref_spouse = self.gtop.get_widget("pref_spouse") - self.multi_spouse= self.gtop.get_widget("multi_spouse") - self.spouse_pref = self.gtop.get_widget("prefrel") - self.spouse_edit = self.gtop.get_widget("edit_sp") - self.spouse_del = self.gtop.get_widget("delete_sp") - self.spouse_combo= self.gtop.get_widget("spouse_combo") - self.spouse_tab = self.gtop.get_widget("spouse_tab") - self.undolabel = self.gtop.get_widget('undolabel') - #self.redolabel = self.gtop.get_widget('redolabel') - self.open_recent = self.gtop.get_widget('open_recent1') - - self.child_model = gtk.ListStore( - gobject.TYPE_INT, gobject.TYPE_STRING, gobject.TYPE_STRING, - gobject.TYPE_STRING, gobject.TYPE_STRING, gobject.TYPE_STRING, - gobject.TYPE_STRING, - ) - - self.build_plugin_menus() - self.init_filters() - - self.build_recent_menu() - - the_style = GrampsKeys.get_toolbar() - if the_style == -1: - self.toolbar.unset_style() - else: - self.toolbar.set_style(the_style) - self.views.set_show_tabs(0) - - self.family_view = FamilyView.FamilyView(self) - self.people_view = PeopleView.PeopleView(self) - - self.pedigree_view = PedView.PedigreeView( - self, self.canvas, self.modify_statusbar, self.statusbar, - self.load_person - ) - - self.place_view = PlaceView.PlaceView(self,self.db,self.gtop) - self.source_view = SourceView.SourceView(self,self.db,self.gtop) - self.repository_view = RepositoryView.RepositoryView(self,self.db,self.gtop) - self.media_view = MediaView.MediaView(self,self.db,self.gtop, - self.update_display) - self.event_view = EventView.EventView(self,self.db,self.gtop) - - self.add_button = self.gtop.get_widget('addbtn') - self.add_item = self.gtop.get_widget('add_item') - self.backbtn = self.gtop.get_widget('back_btn') - self.fwdbtn = self.gtop.get_widget('fwd_btn') - self.gomenuitem = self.gtop.get_widget("go1") - - # FIXME: Horrible and ugly hack that works around a bug in - # either gtk or libglade: button-press-event does not propagate - # from ToolButton to the child. - self.backbtn.get_children()[0].connect("button-press-event",self.back_pressed) - self.fwdbtn.get_children()[0].connect("button-press-event",self.fwd_pressed) - - self.wins = self.gtop.get_widget("windows1") - self.wins.set_submenu(gtk.Menu()) - self.winsmenu = self.wins.get_submenu() - self.child_windows = {} - - self.gtop.signal_autoconnect({ - "on_undo_activate" : self.undo, - "on_abandon_activate" : self.exit_and_undo, - "on_column_order_activate": self.column_order, - "on_back_clicked" : self.back_clicked, - "on_scratchpad_clicked" : self.scratchpad_clicked, - # FIXME: uncomment when fixed - #"on_back_pressed" : self.back_pressed, - "on_fwd_clicked" : self.fwd_clicked, - # FIXME: uncomment when fixed - #"on_fwd_pressed" : self.fwd_pressed, - "on_editbtn_clicked" : self.edit_button_clicked, - "on_addbtn_clicked" : self.add_button_clicked, - "on_removebtn_clicked" : self.remove_button_clicked, - "delete_event" : self.delete_event, - "destroy_passed_object" : Utils.destroy_passed_object, - "on_about_activate" : self.on_about_activate, - "on_add_bookmark_activate" : self.on_add_bookmark_activate, - "on_add_place_clicked" : self.place_view.on_add_place_clicked, - "on_add_source_clicked" : self.source_view.on_add_clicked, - "on_add_repository_clicked" : self.repository_view.on_add_clicked, - "on_addperson_clicked" : self.load_new_person, - "on_apply_filter_clicked" : self.on_apply_filter_clicked, - "on_contents_activate" : self.on_contents_activate, - "on_faq_activate" : self.on_faq_activate, - "on_default_person_activate" : self.on_default_person_activate, - "on_delete_person_clicked" : self.delete_person_clicked, - "on_delete_place_clicked" : self.place_view.on_delete_clicked, - "on_delete_source_clicked" : self.source_view.on_delete_clicked, - "on_delete_repository_clicked" : self.repository_view.on_delete_clicked, - "on_delete_media_clicked" : self.media_view.on_delete_clicked, - "on_edit_active_person" : self.load_active_person, - "on_edit_selected_people" : self.load_selected_people, - "on_edit_bookmarks_activate" : self.on_edit_bookmarks_activate, - "on_exit_activate" : self.on_exit_activate, - "on_family_activate" : self.on_family_activate, - "on_family1_activate" : self.on_family1_activate, - "on_family2_activate" : self.on_family2_activate, - "on_home_clicked" : self.on_home_clicked, - "on_new_clicked" : self.on_new_clicked, - "on_notebook1_switch_page" : self.on_views_switch_page, - "on_open_activate" : self.on_open_activate, - "on_import_activate" : self.on_import_activate, - "on_export_activate" : self.on_export_activate, - "on_saveas_activate" : self.on_saveas_activate, - "on_pedigree1_activate" : self.on_pedigree1_activate, - "on_person_list1_activate" : self.on_person_list1_activate, - "on_media_activate" : self.on_media_activate, - "on_media_list_select_row" : self.media_view.on_select_row, - "on_media_list_drag_data_get" : self.media_view.on_drag_data_get, - "on_media_list_drag_data_received" : self.media_view.on_drag_data_received, - "on_merge_activate" : self.on_merge_activate, - "on_fast_merge1_activate" : self.on_fast_merge_activate, - "on_sidebar1_activate" : self.on_sidebar_activate, - "on_toolbar2_activate" : self.on_toolbar_activate, - "on_filter1_activate" : self.on_filter_activate, - "on_places_activate" : self.on_places_activate, - "on_preferences1_activate" : self.on_preferences_activate, - "on_reports_clicked" : self.on_reports_clicked, - "on_revert_activate" : self.on_revert_activate, - "on_show_plugin_status" : self.on_show_plugin_status, - "on_source_list_button_press" : self.source_view.button_press, - "on_repository_list_button_press" : self.repository_view.button_press, - "on_sources_activate" : self.on_sources_activate, - "on_tools_clicked" : self.on_tools_clicked, - "on_gramps_home_page_activate" : self.home_page_activate, - "on_gramps_report_bug_activate" : self.report_bug_activate, - "on_gramps_mailing_lists_activate" : self.mailing_lists_activate, - "on_open_example" : self.open_example, - "on_events_activate" : self.on_events_activate, - "on_repos_activate" : self.on_repos_activate, - }) - - self.filter_btn.set_active(GrampsKeys.get_filter()) - self.enable_filter(GrampsKeys.get_filter()) - self.toolbar_btn.set_active(GrampsKeys.get_toolbar_on()) - self.enable_toolbar(GrampsKeys.get_toolbar_on()) - - if not GrampsKeys.get_screen_size_checked(): - GrampsKeys.save_screen_size_checked(1) - if gtk.gdk.screen_width() <= 900: - GrampsKeys.save_view(0) - self.sidebar_btn.set_active(GrampsKeys.get_view()) - self.enable_sidebar(GrampsKeys.get_view()) - - self.find_place = None - self.find_source = None - self.find_media = None - - if GrampsKeys.get_default_view() == 0: - self.views.set_current_page(PERSON_VIEW) - elif GrampsKeys.get_family_view() == 0: - self.views.set_current_page(FAMILY_VIEW1) - else: - self.views.set_current_page(FAMILY_VIEW2) - - self.accel_group = gtk.AccelGroup() - self.topWindow.add_accel_group(self.accel_group) - self.back = gtk.ImageMenuItem(gtk.STOCK_GO_BACK) - self.forward = gtk.ImageMenuItem(gtk.STOCK_GO_FORWARD) - - def build_recent_menu(self): - gramps_rf = RecentFiles.GrampsRecentFiles() - gramps_rf.gramps_recent_files.sort() - gramps_rf.gramps_recent_files.reverse() - recent_menu = gtk.Menu() - recent_menu.show() - index = 0 - for item in gramps_rf.gramps_recent_files: - index = index + 1 - name = os.path.basename(item.get_path()) - if gtk.pygtk_version < (2,4,0): - menu_item = gtk.MenuItem(name) - else: - menu_item = gtk.MenuItem(name,False) - menu_item.connect("activate",self.recent_callback, - item.get_path(),item.get_mime()) - menu_item.show() - recent_menu.append(menu_item) - self.open_recent.set_submenu(recent_menu) - - def recent_callback(self,obj,filename,filetype): - if os.path.exists(filename): - DbPrompter.open_native(self,filename,filetype) - else: - ErrorDialog(_('File does not exist'), - _("The file %s cannot be found. " - "It will be removed from the list of recent files.") % filename ) - RecentFiles.remove_filename(filename) - self.build_recent_menu() - - def undo_callback(self,text): - self.undolabel.set_sensitive(bool(text)) - label = self.undolabel.get_children()[0] - if text: - label.set_text(text) - else: - label.set_text(_("_Undo")) - label.set_use_underline(1) - - def redo_callback(self,text): - return - #self.redolabel.set_sensitive(bool(text)) - #label = self.redolabel.get_children()[0] - #if text: - # label.set_text(text) - #else: - # label.set_text(_("_Redo")) - #label.set_use_underline(1) - - def undo(self,*args): - """ - Undo signal handler - it is possible to reenter this routine too quickly if - the user presses the C-z signal too quickly. So, we need to check to make sure - we aren't already active. - """ - if self.undo_active: - return - self.undo_active = True - self.db.disable_signals() - self.db.undo() - self.db.enable_signals() - self.db.request_rebuild() - if self.active_person: - p = self.db.get_person_from_handle(self.active_person.get_handle()) - self.change_active_person(p) - self.undo_active = False - - def exit_and_undo(self,*args): - self.db.disable_signals() - self.db.abort_changes() - gtk.main_quit() - - def set_person_column_order(self,list): - self.db.set_person_column_order(list) - self.people_view.build_columns() - - def set_child_column_order(self,list): - self.db.set_child_column_order(list) - self.family_view.build_columns() - - def set_place_column_order(self,list): - self.db.set_place_column_order(list) - self.place_view.build_columns() - - def set_source_column_order(self,list): - self.db.set_source_column_order(list) - self.source_view.build_columns() - - def set_repository_column_order(self,list): - self.db.set_repository_column_order(list) - self.repository_view.build_columns() - - def set_media_column_order(self,list): - self.db.set_media_column_order(list) - self.media_view.build_columns() - - def set_event_column_order(self,list): - self.db.set_event_column_order(list) - self.event_view.build_columns() - - def column_order(self,obj): - import ColumnOrder - - cpage = self.views.get_current_page() - if cpage == PERSON_VIEW: - ColumnOrder.ColumnOrder(self.db.get_person_column_order(), - PeopleView.column_names, - self.set_person_column_order) - elif cpage == FAMILY_VIEW1 or cpage == FAMILY_VIEW2: - ColumnOrder.ColumnOrder(self.db.get_child_column_order(), - map(lambda x: x[0], FamilyView.column_names), - self.set_child_column_order) - elif cpage == SOURCE_VIEW: - ColumnOrder.ColumnOrder(self.db.get_source_column_order(), - SourceView.column_names, - self.set_source_column_order) - elif cpage == REPOSITORY_VIEW: - ColumnOrder.ColumnOrder(self.db.get_repository_column_order(), - RepositoryView.column_names, - self.set_repository_column_order) - elif cpage == PLACE_VIEW: - ColumnOrder.ColumnOrder(self.db.get_place_column_order(), - PlaceView.column_names, - self.set_place_column_order) - elif cpage == MEDIA_VIEW: - ColumnOrder.ColumnOrder(self.db.get_media_column_order(), - MediaView.column_names, - self.set_media_column_order) - elif cpage == EVENT_VIEW: - ColumnOrder.ColumnOrder(self.db.get_event_column_order(), - EventView.column_names, - self.set_event_column_order) - - def clear_history(self): - self.history = [] - self.mhistory = [] - self.hindex = -1 - self.back.set_sensitive(0) - self.forward.set_sensitive(0) - self.backbtn.set_sensitive(0) - self.fwdbtn.set_sensitive(0) - self.redraw_histmenu() - - def redraw_histmenu(self): - """Create the history submenu of the Go menu""" - - # Start a brand new menu and create static items: - # back, forward, separator, home. - gomenu = gtk.Menu() - - self.back.destroy() - self.forward.destroy() - - self.back = gtk.ImageMenuItem(gtk.STOCK_GO_BACK) - self.back.connect("activate",self.back_clicked) - self.back.add_accelerator("activate", self.accel_group, - gtk.gdk.keyval_from_name("Left"), - gtk.gdk.MOD1_MASK, gtk.ACCEL_VISIBLE) - self.back.show() - gomenu.append(self.back) - - self.forward = gtk.ImageMenuItem(gtk.STOCK_GO_FORWARD) - self.forward.connect("activate",self.fwd_clicked) - self.forward.add_accelerator("activate", self.accel_group, - gtk.gdk.keyval_from_name("Right"), - gtk.gdk.MOD1_MASK, gtk.ACCEL_VISIBLE) - self.forward.show() - gomenu.append(self.forward) - - item = gtk.MenuItem() - item.show() - gomenu.append(item) - - #FIXME: revert to stock item when German gtk translation is fixed - #item = gtk.ImageMenuItem(gtk.STOCK_HOME) - item = gtk.ImageMenuItem(_("Home")) - im = gtk.image_new_from_stock(gtk.STOCK_HOME,gtk.ICON_SIZE_MENU) - im.show() - item.set_image(im) - item.connect("activate",self.on_home_clicked) - item.add_accelerator("activate", self.accel_group, - gtk.gdk.keyval_from_name("Home"), - gtk.gdk.MOD1_MASK, gtk.ACCEL_VISIBLE) - item.show() - gomenu.append(item) - - try: - if len(self.history) > 0: - # Draw separator - item = gtk.MenuItem() - item.show() - gomenu.append(item) - - pids = self.mhistory[:] - pids.reverse() - num = 0 - haveit = [] - for pid in pids: - if num >= 10: - break - if pid not in haveit: - haveit.append(pid) - person = self.db.get_person_from_handle(pid) - item = gtk.MenuItem("_%d. %s [%s]" % - (num, - NameDisplay.displayer.display(person), - person.get_gramps_id())) - item.connect("activate",self.bookmark_callback, - person.get_handle()) - item.show() - gomenu.append(item) - num = num + 1 - else: - self.back.set_sensitive(0) - self.forward.set_sensitive(0) - except: - self.clear_history() - - self.gomenuitem.remove_submenu() - self.gomenuitem.set_submenu(gomenu) - - def build_backhistmenu(self,event): - """Builds and displays the menu with the back portion of the history""" - if self.hindex > 0: - backhistmenu = gtk.Menu() - backhistmenu.set_title(_('Back Menu')) - pids = self.history[:self.hindex] - pids.reverse() - num = 1 - for pid in pids: - if num <= 10: - f,r = divmod(num,10) - hotkey = "_%d" % r - elif num <= 20: - hotkey = "_%s" % chr(ord('a')+num-11) - elif num >= 21: - break - person = self.db.get_person_from_handle(pid) - item = gtk.MenuItem("%s. %s [%s]" % - (hotkey, - NameDisplay.displayer.display(person), - person.get_gramps_id())) - item.connect("activate",self.back_clicked,num) - item.show() - backhistmenu.append(item) - num = num + 1 - backhistmenu.popup(None,None,None,event.button,event.time) - - def back_pressed(self,obj,event): - if event.type == gtk.gdk.BUTTON_PRESS and event.button == 3: - self.build_backhistmenu(event) - - def build_fwdhistmenu(self,event): - """Builds and displays the menu with the forward portion of the history""" - if self.hindex < len(self.history)-1: - fwdhistmenu = gtk.Menu() - fwdhistmenu.set_title(_('Forward Menu')) - pids = self.history[self.hindex+1:] - num = 1 - for pid in pids: - if num <= 10: - f,r = divmod(num,10) - hotkey = "_%d" % r - elif num <= 20: - hotkey = "_%s" % chr(ord('a')+num-11) - elif num >= 21: - break - person = self.db.get_person_from_handle(pid) - item = gtk.MenuItem("%s. %s [%s]" % - (hotkey, - NameDisplay.displayer.display(person), - person.get_gramps_id())) - item.connect("activate",self.fwd_clicked,num) - item.show() - fwdhistmenu.append(item) - num = num + 1 - fwdhistmenu.popup(None,None,None,event.button,event.time) - - def fwd_pressed(self,obj,event): - if event.type == gtk.gdk.BUTTON_PRESS and event.button == 3: - self.build_fwdhistmenu(event) - - def set_buttons(self,val): - self.report_menu.set_sensitive(val) - self.tools_menu.set_sensitive(val) - self.report_button.set_sensitive(val) - self.tool_button.set_sensitive(val) - if self.views.get_current_page() == PERSON_VIEW: - self.remove_button.set_sensitive(val) - self.edit_button.set_sensitive(val) - self.remove_item.set_sensitive(val) - self.edit_item.set_sensitive(val) - - def scratchpad_clicked(self,obj): - import ScratchPad - ScratchPad.ScratchPadWindow(self.db, self) - - def back_clicked(self,obj,step=1): - self.lock_history = True - if self.hindex > 0: - try: - self.hindex -= step - handle = str(self.history[self.hindex]) - self.active_person = self.db.get_person_from_handle(handle) - self.modify_statusbar() - self.emit('active-changed',(handle,)) - self.mhistory.append(self.history[self.hindex]) - self.redraw_histmenu() - self.set_buttons(1) - if self.hindex == 0: - self.backbtn.set_sensitive(False) - self.back.set_sensitive(False) - else: - self.backbtn.set_sensitive(True) - self.back.set_sensitive(True) - self.fwdbtn.set_sensitive(True) - self.forward.set_sensitive(True) - except: - self.clear_history() - else: - self.backbtn.set_sensitive(False) - self.back.set_sensitive(False) - self.fwdbtn.set_sensitive(True) - self.forward.set_sensitive(True) - self.goto_active_person() - self.lock_history = False - - def fwd_clicked(self,obj,step=1): - self.lock_history = True - if self.hindex+1 < len(self.history): - try: - self.hindex += step - handle = str(self.history[self.hindex]) - self.active_person = self.db.get_person_from_handle(handle) - self.modify_statusbar() - self.emit('active-changed',(handle,)) - self.mhistory.append(self.history[self.hindex]) - self.redraw_histmenu() - self.set_buttons(1) - if self.hindex == len(self.history)-1: - self.fwdbtn.set_sensitive(False) - self.forward.set_sensitive(False) - else: - self.fwdbtn.set_sensitive(True) - self.forward.set_sensitive(True) - self.backbtn.set_sensitive(True) - self.back.set_sensitive(True) - except: - self.clear_history() - else: - self.fwdbtn.set_sensitive(False) - self.forward.set_sensitive(False) - self.backbtn.set_sensitive(True) - self.back.set_sensitive(True) - self.goto_active_person() - self.lock_history = False - - def edit_button_clicked(self,obj): - cpage = self.views.get_current_page() - if cpage == PERSON_VIEW: - self.load_selected_people(obj) - elif cpage == FAMILY_VIEW2 or cpage == FAMILY_VIEW1: - self.load_person(self.active_person) - elif cpage == SOURCE_VIEW: - self.source_view.on_edit_clicked(obj) - elif cpage == REPOSITORY_VIEW: - self.repository_view.on_edit_clicked(obj) - elif cpage == PLACE_VIEW: - self.place_view.on_edit_clicked(obj) - elif cpage == MEDIA_VIEW: - self.media_view.on_edit_clicked(obj) - elif cpage == EVENT_VIEW: - self.event_view.on_edit_clicked(obj) - - def add_button_clicked(self,obj): - cpage = self.views.get_current_page() - if cpage == PERSON_VIEW or cpage == FAMILY_VIEW2 or cpage == FAMILY_VIEW1: - self.load_new_person(obj) - elif cpage == SOURCE_VIEW: - self.source_view.on_add_clicked(obj) - elif cpage == REPOSITORY_VIEW: - self.repository_view.on_add_clicked(obj) - elif cpage == PLACE_VIEW: - self.place_view.on_add_place_clicked(obj) - elif cpage == MEDIA_VIEW: - self.media_view.on_add_clicked(obj) - elif cpage == EVENT_VIEW: - self.event_view.on_add_clicked(obj) - - def remove_button_clicked(self,obj): - cpage = self.views.get_current_page() - if cpage == PERSON_VIEW or cpage == FAMILY_VIEW2 or cpage == FAMILY_VIEW1: - self.delete_person_clicked(obj) - elif cpage == SOURCE_VIEW: - self.source_view.on_delete_clicked(obj) - elif cpage == REPOSITORY_VIEW: - self.repository_view.on_delete_clicked(obj) - elif cpage == PLACE_VIEW: - self.place_view.on_delete_clicked(obj) - elif cpage == MEDIA_VIEW: - self.media_view.on_delete_clicked(obj) - elif cpage == EVENT_VIEW: - self.event_view.on_delete_clicked(obj) - - def enable_buttons(self,val): - if self.db.readonly: - mode = False - else: - mode = val - self.add_button.set_sensitive(mode) - self.remove_button.set_sensitive(mode) - self.add_item.set_sensitive(mode) - self.remove_item.set_sensitive(mode) - - self.edit_button.set_sensitive(val) - self.edit_item.set_sensitive(val) - - def on_show_plugin_status(self,obj): - Plugins.PluginStatus(self) - - def on_sidebar_activate(self,obj): - self.enable_sidebar(obj.get_active()) - GrampsKeys.save_view(obj.get_active()) - - def enable_sidebar(self,val): - if val: - self.sidebar.show() - self.views.set_show_tabs(False) - else: - self.sidebar.hide() - self.views.set_show_tabs(True) - - def enable_filter(self,val): - if val: - self.filterbar.show() - else: - self.filterbar.hide() - - def on_filter_activate(self,obj): - GrampsKeys.save_filter(obj.get_active()) - - def on_toolbar_activate(self,obj): - GrampsKeys.save_toolbar_on(obj.get_active()) - - def enable_toolbar(self,val): - if val: - self.toolbardock.show() - else: - self.toolbardock.hide() - - def build_plugin_menus(self): - self.report_menu = self.gtop.get_widget("reports_menu") - self.tools_menu = self.gtop.get_widget("tools_menu") - - self.report_menu.set_sensitive(False) - self.tools_menu.set_sensitive(False) - - error = PluginMgr.load_plugins(const.docgenDir) - error |= PluginMgr.load_plugins(os.path.expanduser("~/.gramps/docgen")) - error |= PluginMgr.load_plugins(const.pluginsDir) - error |= PluginMgr.load_plugins(os.path.expanduser("~/.gramps/plugins")) - - if GrampsKeys.get_pop_plugin_status() and error: - Plugins.PluginStatus(self) - Plugins.build_report_menu(self.report_menu,self.menu_report) - Plugins.build_tools_menu(self.tools_menu,self.menu_tools) - - self.RelClass = PluginMgr.relationship_class - self.relationship = self.RelClass(self.db) - - def init_filters(self): - - cell = gtk.CellRendererText() - self.filter_list.clear() - self.filter_list.pack_start(cell,True) - self.filter_list.add_attribute(cell,'text',0) - - filter_list = [] - - all = GenericFilter.GenericFilter() - all.set_name(_("Entire Database")) - all.add_rule(GenericFilter.Everyone([])) - filter_list.append(all) - - all = GenericFilter.GenericFilter() - all.set_name(_("Females")) - all.add_rule(GenericFilter.IsFemale([])) - filter_list.append(all) - - all = GenericFilter.GenericFilter() - all.set_name(_("Males")) - all.add_rule(GenericFilter.IsMale([])) - filter_list.append(all) - - all = GenericFilter.GenericFilter() - all.set_name(_("People with unknown gender")) - all.add_rule(GenericFilter.HasUnknownGender([])) - filter_list.append(all) - - all = GenericFilter.GenericFilter() - all.set_name(_("Disconnected individuals")) - all.add_rule(GenericFilter.Disconnected([])) - filter_list.append(all) - - all = GenericFilter.ParamFilter() - all.set_name(_("People with names containing...")) - all.add_rule(GenericFilter.SearchName([])) - filter_list.append(all) - - all = GenericFilter.GenericFilter() - all.set_name(_("Adopted people")) - all.add_rule(GenericFilter.HaveAltFamilies([])) - filter_list.append(all) - - all = GenericFilter.GenericFilter() - all.set_name(_("People with images")) - all.add_rule(GenericFilter.HavePhotos([])) - filter_list.append(all) - - all = GenericFilter.GenericFilter() - all.set_name(_("People with incomplete names")) - all.add_rule(GenericFilter.IncompleteNames([])) - filter_list.append(all) - - all = GenericFilter.GenericFilter() - all.set_name(_("People with children")) - all.add_rule(GenericFilter.HaveChildren([])) - filter_list.append(all) - - all = GenericFilter.GenericFilter() - all.set_name(_("People with no marriage records")) - all.add_rule(GenericFilter.NeverMarried([])) - filter_list.append(all) - - all = GenericFilter.GenericFilter() - all.set_name(_("People with multiple marriage records")) - all.add_rule(GenericFilter.MultipleMarriages([])) - filter_list.append(all) - - all = GenericFilter.GenericFilter() - all.set_name(_("People without a known birth date")) - all.add_rule(GenericFilter.NoBirthdate([])) - filter_list.append(all) - - all = GenericFilter.GenericFilter() - all.set_name(_("People with incomplete events")) - all.add_rule(GenericFilter.PersonWithIncompleteEvent([])) - filter_list.append(all) - - all = GenericFilter.GenericFilter() - all.set_name(_("Families with incomplete events")) - all.add_rule(GenericFilter.FamilyWithIncompleteEvent([])) - filter_list.append(all) - - all = GenericFilter.ParamFilter() - all.set_name(_("People probably alive")) - all.add_rule(GenericFilter.ProbablyAlive([])) - filter_list.append(all) - - all = GenericFilter.GenericFilter() - all.set_name(_("People marked private")) - all.add_rule(GenericFilter.PeoplePrivate([])) - filter_list.append(all) - - all = GenericFilter.GenericFilter() - all.set_name(_("Witnesses")) - all.add_rule(GenericFilter.IsWitness([])) - filter_list.append(all) - - all = GenericFilter.ParamFilter() - all.set_name(_("People with records containing...")) - all.add_rule(GenericFilter.HasTextMatchingSubstringOf([])) - filter_list.append(all) - - all = GenericFilter.ParamFilter() - all.set_name(_("People with records matching regular expression...")) - all.add_rule(GenericFilter.HasTextMatchingRegexpOf([])) - filter_list.append(all) - - all = GenericFilter.GenericFilter() - all.set_name(_("People with notes")) - all.add_rule(GenericFilter.HasNote([])) - filter_list.append(all) - - all = GenericFilter.ParamFilter() - all.set_name(_("People with notes containing...")) - all.add_rule(GenericFilter.HasNoteMatchingSubstringOf([])) - filter_list.append(all) - - self.filter_model = GenericFilter.FilterStore(filter_list) - self.filter_list.set_model(self.filter_model) - self.filter_list.set_active(self.filter_model.default_index()) - self.filter_list.connect('changed',self.on_filter_name_changed) - self.filter_text.set_sensitive(0) - - def home_page_activate(self,obj): - gnome.url_show(_HOMEPAGE) - - def mailing_lists_activate(self,obj): - gnome.url_show(_MAILLIST) - - def report_bug_activate(self,obj): - gnome.url_show(_BUGREPORT) - - def on_fast_merge_activate(self,obj): - """Calls up the merge dialog for the selection""" - page = self.views.get_current_page() - if page == PERSON_VIEW: - - mlist = self.people_view.get_selected_objects() - - if len(mlist) != 2: - msg = _("Cannot merge people.") - msg2 = _("Exactly two people must be selected to perform a merge. " - "A second person can be selected by holding down the " - "control key while clicking on the desired person.") - ErrorDialog(msg,msg2) - else: - import MergePeople - p1 = self.db.get_person_from_handle(mlist[0]) - p2 = self.db.get_person_from_handle(mlist[1]) - if p1 and p2: - merger = MergePeople.MergePeopleUI(self.db,p1,p2,self.merge_update) - else: - msg = _("Cannot merge people.") - msg2 = _("Exactly two people must be selected to perform a merge. " - "A second person can be selected by holding down the " - "control key while clicking on the desired person.") - ErrorDialog(msg,msg2) - elif page == PLACE_VIEW: - self.place_view.merge() - elif page == SOURCE_VIEW: - self.source_view.merge() - - def on_merge_activate(self,obj): - """Calls up the merge dialog for the selection""" - page = self.views.get_current_page() - if page == PERSON_VIEW: - - mlist = self.people_view.get_selected_objects() - - if len(mlist) != 2: - msg = _("Cannot merge people.") - msg2 = _("Exactly two people must be selected to perform a merge. " - "A second person can be selected by holding down the " - "control key while clicking on the desired person.") - ErrorDialog(msg,msg2) - else: - import MergePeople - p1 = self.db.get_person_from_handle(mlist[0]) - p2 = self.db.get_person_from_handle(mlist[1]) - if p1 and p2: - merger = MergePeople.Compare(self.db,p1,p2,self.merge_update) - else: - msg = _("Cannot merge people.") - msg2 = _("Exactly two people must be selected to perform a merge. " - "A second person can be selected by holding down the " - "control key while clicking on the desired person.") - ErrorDialog(msg,msg2) - elif page == PLACE_VIEW: - self.place_view.merge() - elif page == SOURCE_VIEW: - self.source_view.merge() - - def delete_event(self,widget, event): - """Catch the destruction of the top window, prompt to save if needed""" - self.on_exit_activate(widget) - return 1 - - def on_exit_activate(self,obj): - """Prompt to save on exit if needed""" - self.db.close() - gtk.main_quit() - - def quit(self): - """Catch the reponse to the save on exit question""" - self.db.close() - gtk.main_quit() - - def close_noquit(self): - """Close database and delete abandoned photos, no quit""" - self.db.close() - - def on_about_activate(self,obj): - """Displays the about box. Called from Help menu""" - pixbuf = gtk.gdk.pixbuf_new_from_file(const.logo) - - if const.translators[0:11] == "TRANSLATORS": - trans = '' - else: - trans = const.translators - - gnome.ui.About(const.progName, - const.version, - const.copyright, - const.comments, - const.authors, - const.documenters, - trans, - pixbuf).show() - def on_contents_activate(self,obj): - """Display the GRAMPS manual""" - try: - gnome.help_display('gramps-manual','index') - except gobject.GError, msg: - ErrorDialog(_("Could not open help"),str(msg)) - def on_faq_activate(self,obj): - """Display FAQ""" - try: - gnome.help_display('gramps-manual','faq') - except gobject.GError, msg: - ErrorDialog(_("Could not open help"),str(msg)) - - def on_new_clicked(self,obj): - """Prompt for permission to close the current database""" - prompter = DbPrompter.NewNativeDbPrompter(self,self.topWindow) - prompter.chooser() - - def clear_database(self): - """Clear out the database if permission was granted""" - return - - def tool_callback(self,epo,val): - if val: - self.import_tool_callback() - - def import_tool_callback(self): - home = self.db.get_default_person() - if home: - self.change_active_person(home) - self.update_display(0) - self.goto_active_person() - self.full_update() - - def full_update(self): - """Brute force display update, updating all the pages""" - if Utils.wasHistory_broken(): - self.clear_history() - Utils.clearHistory_broken() - self.emit('database-changed',(self.db,)) - if not self.active_person: - self.change_active_person(self.find_initial_person()) - self.goto_active_person() - - def update_display(self,changed=True): - """Incremental display update, update only the displayed page""" - page = self.views.get_current_page() - if page == PERSON_VIEW: - self.people_view.apply_filter() - - def on_tools_clicked(self,obj): - if self.active_person: - Plugins.ToolPlugins(self,self.db,self.active_person, - self.tool_callback) - - def on_reports_clicked(self,obj): - if self.active_person: - Plugins.ReportPlugins(self,self.db,self.active_person) - - def read_pkg(self,filename): - # Create tempdir, if it does not exist, then check for writability - tmpdir_path = os.path.expanduser("~/.gramps/tmp" ) - if not os.path.isdir(tmpdir_path): - try: - os.mkdir(tmpdir_path,0700) - except: - DisplayTrace.DisplayTrace() - return - elif not os.access(tmpdir_path,os.W_OK): - ErrorDialog( _("Cannot unpak archive"), - _("Temporary directory %s is not writable") % tmpdir_path ) - return - else: # tempdir exists and writable -- clean it up if not empty - files = os.listdir(tmpdir_path) ; - for fn in files: - os.remove( os.path.join(tmpdir_path,fn) ) - - try: - import TarFile - t = TarFile.ReadTarFile(filename,tmpdir_path) - t.extract() - t.close() - except: - DisplayTrace.DisplayTrace() - return - - dbname = os.path.join(tmpdir_path,const.xmlFile) - - try: - import ReadXML - ReadXML.importData(self.db,dbname,self.update_bar) - except: - DisplayTrace.DisplayTrace() - - # Clean up tempdir after ourselves - files = os.listdir(tmpdir_path) - for fn in files: - os.remove(os.path.join(tmpdir_path,fn)) - os.rmdir(tmpdir_path) - self.import_tool_callback() - - def update_bar(self,percent): - if percent: - self.progress.pulse() - else: - self.progress.set_fraction(0) - - def read_file(self,filename,callback=None): - mode = "w" - filename = os.path.normpath(os.path.abspath(filename)) - - if os.path.isdir(filename): - ErrorDialog(_('Cannot open database'), - _('The selected file is a directory, not ' - 'a file.\nA GRAMPS database must be a file.')) - return 0 - elif os.path.exists(filename): - if not os.access(filename,os.R_OK): - ErrorDialog(_('Cannot open database'), - _('You do not have read access to the selected ' - 'file.')) - return 0 - elif not os.access(filename,os.W_OK): - mode = "r" - WarningDialog(_('Read only database'), - _('You do not have write access to the selected ' - 'file.')) - - try: - if self.load_database(filename,callback,mode=mode) == 1: - if filename[-1] == '/': - filename = filename[:-1] - name = os.path.basename(filename) - if self.db.readonly: - self.topWindow.set_title("%s (%s) - GRAMPS" % (name,_('Read Only'))) - else: - self.topWindow.set_title("%s - GRAMPS" % name) - else: - GrampsKeys.save_last_file("") - ErrorDialog(_('Cannot open database'), - _('The database file specified could not be opened.')) - return 0 - except ( IOError, OSError, Errors.FileVersionError), msg: - ErrorDialog(_('Cannot open database'),str(msg)) - return 0 - except (db.DBAccessError,db.DBError), msg: - ErrorDialog(_('Cannot open database'), - _('%s could not be opened.' % filename) + '\n' + msg[1]) - return 0 - except Exception: - DisplayTrace.DisplayTrace() - return 0 - - # Undo/Redo always start with standard labels and insensitive state - self.undo_callback(None) - self.redo_callback(None) - # The rest depends on readonly-ness of the database - self.gtop.get_widget('import1').set_sensitive(not self.db.readonly) - self.gtop.get_widget('abandon').set_sensitive(not self.db.readonly) - self.gtop.get_widget('add_item').set_sensitive(not self.db.readonly) - self.gtop.get_widget('remove_item').set_sensitive(not self.db.readonly) - self.gtop.get_widget('merge').set_sensitive(not self.db.readonly) - self.gtop.get_widget('fast_merge1').set_sensitive(not self.db.readonly) - self.gtop.get_widget('default_person1').set_sensitive(not self.db.readonly) - self.gtop.get_widget('edit_bookmarks').set_sensitive(not self.db.readonly) - self.gtop.get_widget('tools_menu').set_sensitive(not self.db.readonly) - self.gtop.get_widget('tools').set_sensitive(not self.db.readonly) - - self.goto_active_person() - return 1 - - def save_media(self,filename): - missmedia_action = 0 - #------------------------------------------------------------------------- - def remove_clicked(): - # File is lost => remove all references and the object itself - for p in self.db.get_family_handle_map().values(): - nl = p.get_media_list() - for o in nl: - if o.get_reference_handle() == ObjectId: - nl.remove(o) - p.set_media_list(nl) - for key in self.db.get_person_handles(sort_handles=False): - p = self.db.get_person_from_handle(key) - nl = p.get_media_list() - for o in nl: - if o.get_reference_handle() == ObjectId: - nl.remove(o) - p.set_media_list(nl) - for key in self.db.get_source_handles(): - p = self.db.get_source_from_handle(key) - nl = p.get_media_list() - for o in nl: - if o.get_reference_handle() == ObjectId: - nl.remove(o) - p.set_media_list(nl) - for key in self.db.get_place_handles(): - p = self.db.get_place_from_handle(key) - nl = p.get_media_list() - for o in nl: - if o.get_reference_handle() == ObjectId: - nl.remove(o) - p.set_media_list(nl) - - trans = self.db.transaction_begin() - self.db.remove_object(ObjectId) - self.db.transaction_commit(trans,_("Save Media Object")) - - def leave_clicked(): - # File is lost => do nothing, leave as is - pass - - def select_clicked(): - choose = gtk.FileChooserDialog('Open GRAMPS database', - None, - gtk.FILE_CHOOSER_ACTION_OPEN, - (gtk.STOCK_CANCEL, - gtk.RESPONSE_CANCEL, - gtk.STOCK_OPEN, - gtk.RESPONSE_OK)) - - mime_filter = gtk.FileFilter() - mime_filter.set_name(_('All files')) - mime_filter.add_pattern('*') - choose.add_filter(mime_filter) - - response = choose.run() - if response == gtk.RESPONSE_OK: - name = choose.get_filename() - if os.path.isfile(name): - obj = self.db.get_object_from_handle(ObjectId) - obj.set_path(name) - choose.destroy() - - #------------------------------------------------------------------------- - for ObjectId in self.db.get_media_object_handles(): - obj = self.db.get_object_from_handle(ObjectId) - if 0: - oldfile = obj.get_path() - (base,ext) = os.path.splitext(os.path.basename(oldfile)) - newfile = os.path.join(filename,os.path.basename(oldfile)) - obj.set_path(newfile) - if os.path.isfile(oldfile): - RelImage.import_media_object(oldfile,filename,base) - else: - if self.cl: - print "Warning: media file %s was not found," \ - % os.path.basename(oldfile), "so it was ignored." - else: - # File is lost => ask what to do - if missmedia_action == 0: - mmd = MissingMediaDialog( - _("Media object could not be found"), - _("%(file_name)s is referenced in the database, but no longer exists. " - "The file may have been deleted or moved to a different location. " - "You may choose to either remove the reference from the database, " - "keep the reference to the missing file, or select a new file." - ) % { 'file_name' : oldfile }, - remove_clicked, leave_clicked, select_clicked) - missmedia_action = mmd.default_action - elif missmedia_action == 1: - remove_clicked() - elif missmedia_action == 2: - leave_clicked() - elif missmedia_action == 3: - select_clicked() - - def load_selected_people(self,obj): - """Display the selected people in the EditPerson display""" - mlist = self.people_view.get_selected_objects() - if mlist and self.active_person.get_handle() == mlist[0]: - self.load_person(self.active_person) - - def load_active_person(self,obj): - self.load_person(self.active_person) - - def load_new_person(self,obj): - person = RelLib.Person() - try: - EditPerson.EditPerson(self, person, self.db, - self.new_after_edit) - except: - DisplayTrace.DisplayTrace() - - def delete_person_clicked(self,obj): - cpage = self.views.get_current_page() - if cpage == PERSON_VIEW: - mlist = self.people_view.get_selected_objects() - else: - mlist = [ self.active_person.get_handle() ] - - if len(mlist) == 0: - return - - for sel in mlist: - p = self.db.get_person_from_handle(sel) - self.active_person = p - name = NameDisplay.displayer.display(p) - - msg = _('Deleting the person will remove the person ' - 'from the database.') - msg = "%s %s" % (msg,Utils.data_recover_msg) - QuestionDialog(_('Delete %s?') % name,msg, - _('_Delete Person'), - self.delete_person_response) - - def disable_interface(self): - self.remove_button.set_sensitive(False) - self.edit_button.set_sensitive(False) - self.add_button.set_sensitive(False) - - def enable_interface(self): - self.remove_button.set_sensitive(True) - self.edit_button.set_sensitive(True) - self.add_button.set_sensitive(True) - - def delete_person_response(self): - self.disable_interface() - trans = self.db.transaction_begin() - - n = self.active_person.get_primary_name().get_regular_name() - - if self.db.get_default_person() == self.active_person: - self.db.set_default_person_handle(None) - - for family_handle in self.active_person.get_family_handle_list(): - if not family_handle: - continue - family = self.db.get_family_from_handle(family_handle) - family_to_remove = False - if self.active_person.get_handle() == family.get_father_handle(): - if family.get_mother_handle(): - family.set_father_handle(None) - else: - family_to_remove = True - else: - if family.get_father_handle(): - family.set_mother_handle(None) - else: - family_to_remove = True - if family_to_remove: - for child_handle in family.get_child_handle_list(): - child = self.db.get_person_from_handle(child_handle) - child.remove_parent_family_handle(family_handle) - self.db.commit_person(child,trans) - self.db.remove_family(family_handle,trans) - else: - self.db.commit_family(family,trans) - - for (family_handle,mrel,frel) in self.active_person.get_parent_family_handle_list(): - if family_handle: - family = self.db.get_family_from_handle(family_handle) - family.remove_child_handle(self.active_person.get_handle()) - self.db.commit_family(family,trans) - - handle = self.active_person.get_handle() - - person = self.active_person - self.people_view.remove_from_person_list(person) - self.people_view.remove_from_history(handle) - self.db.remove_person(handle, trans) - - if self.hindex >= 0: - self.active_person = self.db.get_person_from_handle(self.history[self.hindex]) - else: - self.change_active_person(None) - self.goto_active_person() - self.db.transaction_commit(trans,_("Delete Person (%s)") % n) - self.redraw_histmenu() - self.enable_interface() - - def merge_update(self): - self.redraw_histmenu() - - def goto_active_person(self): - self.people_view.goto_active_person() - - def change_active_person(self,person,force=0): - nph = "" - if person: - nph = person.get_handle() - oph = "" - if self.active_person: - oph = self.active_person.get_handle() - if nph == oph: # no need to change to the current active person again - return - - if person == None: - self.set_buttons(0) - self.active_person = None - self.modify_statusbar() - self.emit('active-changed',("",)) - elif (self.active_person == None or - person.get_handle() != self.active_person.get_handle()): - self.active_person = self.db.get_person_from_handle(person.get_handle()) - self.modify_statusbar() - self.set_buttons(1) - if person and not self.lock_history: - if self.hindex+1 < len(self.history): - self.history = self.history[0:self.hindex+1] - - self.history.append(person.get_handle()) - self.mhistory.append(person.get_handle()) - self.hindex += 1 - self.redraw_histmenu() - - if self.hindex+1 < len(self.history): - self.fwdbtn.set_sensitive(1) - self.forward.set_sensitive(1) - else: - self.fwdbtn.set_sensitive(0) - self.forward.set_sensitive(0) - - if self.hindex > 0: - self.backbtn.set_sensitive(1) - self.back.set_sensitive(1) - else: - self.backbtn.set_sensitive(0) - self.back.set_sensitive(0) - self.emit('active-changed',(str(person.get_handle()),)) - else: - self.active_person = self.db.get_person_from_handle(person.get_handle()) - self.set_buttons(1) - self.emit('active-changed',(str(person.get_handle()),)) - - def modify_statusbar(self): - - if self.active_person == None: - self.status_text("") - else: - if GrampsKeys.get_statusbar() <= 1: - pname = NameDisplay.displayer.display(self.active_person) - name = "[%s] %s" % (self.active_person.get_gramps_id(),pname) - else: - name = self.display_relationship() - self.status_text(name) - return 0 - - def display_relationship(self): - default_person = self.db.get_default_person() - active = self.active_person - if default_person == None or active == None: - return u'' - try: - pname = NameDisplay.displayer.display(default_person) - (name,plist) = self.relationship.get_relationship( - default_person,active) - - if name: - if plist == None: - return name - return _("%(relationship)s of %(person)s") % { - 'relationship' : name, 'person' : pname } - else: - return u"" - except: - DisplayTrace.DisplayTrace() - return u"" - - def on_open_activate(self,obj): - prompter = DbPrompter.ExistingDbPrompter(self,self.topWindow) - prompter.chooser() - - def on_import_activate(self,obj): - prompter = DbPrompter.ImportDbPrompter(self,self.topWindow) - prompter.chooser() - - def on_saveas_activate(self,obj): - prompter = DbPrompter.NewSaveasDbPrompter(self,self.topWindow) - prompter.chooser() - - def on_export_activate(self,obj): - Exporter.Exporter(self,self.topWindow) - - def on_revert_activate(self,obj): - pass - - def on_person_list1_activate(self,obj): - """Switches to the person list view""" - self.views.set_current_page(PERSON_VIEW) - - def on_family_activate(self,obj): - """Switches to the family view""" - if GrampsKeys.get_family_view() == 0: - self.on_family1_activate(obj) - else: - self.on_family2_activate(obj) - - def on_family1_activate(self,obj): - """Switches to the family view""" - self.views.set_current_page(FAMILY_VIEW1) - - def on_family2_activate(self,obj): - """Switches to the family view""" - self.views.set_current_page(FAMILY_VIEW2) - - def on_pedigree1_activate(self,obj): - """Switches to the pedigree view""" - self.views.set_current_page(PEDIGREE_VIEW) - - def on_sources_activate(self,obj): - """Switches to the sources view""" - self.views.set_current_page(SOURCE_VIEW) - - def on_places_activate(self,obj): - """Switches to the places view""" - self.status_text(_('Updating display...')) - self.views.set_current_page(PLACE_VIEW) - self.modify_statusbar() - - def on_media_activate(self,obj): - """Switches to the media view""" - self.views.set_current_page(MEDIA_VIEW) - - def on_events_activate(self,obj): - """Switches to the event view""" - self.views.set_current_page(EVENT_VIEW) - - def on_repos_activate(self,obj): - """Switches to the repository view""" - self.views.set_current_page(REPOSITORY_VIEW) - - def on_views_switch_page(self,obj,junk,page): - """Load the appropriate page after a notebook switch""" - if page == PERSON_VIEW: - self.enable_buttons(1) - self.people_view.goto_active_person() - self.merge_button.set_sensitive(1) - elif page == FAMILY_VIEW1 or page == FAMILY_VIEW2: - self.enable_buttons(1) - self.merge_button.set_sensitive(0) - self.family_view.load_family() - elif page == PEDIGREE_VIEW: - self.enable_buttons(0) - self.merge_button.set_sensitive(0) - elif page == SOURCE_VIEW: - self.enable_buttons(1) - self.merge_button.set_sensitive(1) - elif page == PLACE_VIEW: - self.enable_buttons(1) - self.merge_button.set_sensitive(1) - elif page == MEDIA_VIEW: - self.enable_buttons(1) - self.merge_button.set_sensitive(0) - elif page == EVENT_VIEW: - self.enable_buttons(1) - self.merge_button.set_sensitive(0) - - def on_apply_filter_clicked(self,obj): - self.people_view.apply_filter_clicked() - - def on_filter_name_changed(self,obj): - index = self.filter_list.get_active() - mime_filter = self.filter_model.get_filter(index) - qual = mime_filter.need_param - if qual: - self.filter_text.show() - self.filter_text.set_sensitive(1) - self.filter_label.show() - self.filter_label.set_text(mime_filter.get_rules()[0].labels[0]) - else: - self.filter_text.hide() - self.filter_text.set_sensitive(0) - self.filter_label.hide() - - def new_after_edit(self,epo,val): - self.change_active_person(epo.person) - self.family_view.load_family() - self.goto_active_person() - - def update_after_edit(self,epo,change=1): - self.change_active_person(epo.person) - self.goto_active_person() - - def load_person(self,person): - if person: - try: - EditPerson.EditPerson(self, person, self.db, - self.update_after_edit) - except: - DisplayTrace.DisplayTrace() - - def list_item(self,label,filter): - l = gtk.Label(label) - l.set_alignment(0,0.5) - l.show() - c = gtk.ListItem() - c.add(l) - c.set_data('d',filter) - c.show() - return c - - def parent_name(self,person): - if person == None: - return _("Unknown") - else: - return NameDisplay.displayer.display(person) - - def status_text(self,text): - self.statusbar.set_status(text) - while gtk.events_pending(): - gtk.main_iteration() - - def post_load(self,name,callback=None): - if not self.db.version_supported(): - raise Errors.FileVersionError( - "The database version is not supported by this version of GRAMPS.\n" - "Please upgrade to the corresponding version or use XML for porting data between different database versions.") - - self.db.set_save_path(name) - - res = self.db.get_researcher() - owner = GrampsCfg.get_researcher() - if res.get_name() == "" and owner.get_name(): - self.db.set_researcher(owner) - - self.setup_bookmarks() - - self.db.set_undo_callback(self.undo_callback) - self.db.set_redo_callback(self.redo_callback) - - if self.db.need_upgrade(): - if callback: - callback(_('Upgrading database...')) - self.db.upgrade() - - GrampsKeys.save_last_file(name) - self.gtop.get_widget("filter").set_text("") - - self.relationship = self.RelClass(self.db) - self.emit("database-changed", (self.db,)) - - self.change_active_person(self.find_initial_person()) - self.goto_active_person() - - if callback: - callback(_('Setup complete')) - self.enable_buttons(True) - return 1 - - def find_initial_person(self): - person = self.db.get_default_person() - if not person: - the_ids = self.db.get_person_handles(sort_handles=False) - if the_ids: - the_ids.sort() - person = self.db.get_person_from_handle(the_ids[0]) - return person - - def load_database(self,name,callback=None,mode="w"): - - filename = name - - self.status_text(_("Loading %s...") % name) - - if callback: - callback(_('Opening database...')) - - if self.db.load(filename,callback,mode) == 0: - self.status_text('') - return 0 - self.status_text('') - - val = self.post_load(name,callback) - return val - - def setup_bookmarks(self): - self.bookmarks = Bookmarks.Bookmarks(self.db,self.db.get_bookmarks(), - self.gtop.get_widget("jump_to"), - self.bookmark_callback) - - def displayError(self,msg,msg2): - ErrorDialog(msg,msg2) - self.status_text("") - - def complete_rebuild(self): - self.people_view.apply_filter() - self.goto_active_person() - self.modify_statusbar() - - def on_home_clicked(self,obj): - temp = self.db.get_default_person() - if temp: - self.change_active_person(temp) - self.update_display(0) - self.goto_active_person() - else: - ErrorDialog(_("No Home Person has been set."), - _("The Home Person may be set from the Edit menu.")) - - def on_add_bookmark_activate(self,obj): - if self.active_person: - self.bookmarks.add(self.active_person.get_handle()) - name = NameDisplay.displayer.display(self.active_person) - self.status_text(_("%s has been bookmarked") % name) - gtk.timeout_add(5000,self.modify_statusbar) - else: - WarningDialog(_("Could Not Set a Bookmark"), - _("A bookmark could not be set because " - "no one was selected.")) - - def on_edit_bookmarks_activate(self,obj): - self.bookmarks.edit() - - def bookmark_callback(self,obj,person_handle): - old_person = self.active_person - person = self.db.get_person_from_handle(person_handle) - try: - self.change_active_person(person) - self.update_display(0) - self.goto_active_person() - except TypeError: - WarningDialog(_("Could not go to a Person"), - _("Either stale bookmark or broken history " - "caused by IDs reorder.")) - self.clear_history() - self.change_active_person(old_person) - self.update_display(0) - self.goto_active_person() - - def on_default_person_activate(self,obj): - if self.active_person: - name = self.active_person.get_primary_name().get_regular_name() - QuestionDialog(_('Set %s as the Home Person') % name, - _('Once a Home Person is defined, pressing the ' - 'Home button on the toolbar will make the home ' - 'person the active person.'), - _('_Set Home Person'), - self.set_person) - - def set_person(self): - self.db.set_default_person_handle(self.active_person.get_handle()) - - def export_callback(self,obj,plugin_function): - """Call the export plugin, with the active person and database""" - if self.active_person: - plugin_function(self.db,self.active_person) - else: - ErrorDialog(_('A person must be selected to export'), - _('Exporting requires that an active person be selected. ' - 'Please select a person and try again.')) - - def import_callback(self,obj,plugin_function): - """Call the import plugin""" - plugin_function(self.db,self.active_person,self.import_tool_callback) - self.people_view.person_model.rebuild_data() - self.topWindow.set_title("%s - GRAMPS" % self.db.get_save_path()) - - def on_preferences_activate(self,obj): - GrampsCfg.display_preferences_box(self.db) - - def menu_report(self,obj,task,report_class,options_class, - translated_name,name,category): - """Call the report plugin selected from the menus""" - if self.active_person: - task(self.db,self.active_person,report_class, - options_class,translated_name,name,category) - - def menu_tools(self,obj,task): - """Call the tool plugin selected from the menus""" - if self.active_person: - task(self.db,self.active_person,self.tool_callback,self) - - def open_example(self,obj): - import shutil - dest = os.path.expanduser("~/.gramps/example") - if not os.path.isdir(dest): - try: - os.mkdir(dest) - except IOError,msg: - ErrorDialog(_('Could not create example database'), - _('The directory ~/.gramps/example could not ' - 'be created.') + '\n' + str(msg) ) - except OSError,msg: - ErrorDialog(_('Could not create example database'), - _('The directory ~/.gramps/example could not ' - 'be created.') + '\n' + str(msg) ) - except: - ErrorDialog(_('Could not create example database'), - _('The directory ~/.gramps/example could not ' - 'be created.')) - try: - example_dir = "%s/share/gramps/example" % const.prefixdir - for filename in os.listdir(example_dir): - shutil.copyfile("%s/%s" % (example_dir,filename), - "%s/%s" % (dest,filename) ) - try: - shutil.copystat("%s/%s" % (example_dir,filename), - "%s/%s" % (dest,filename)) - except: - pass - except IOError,msg: - ErrorDialog(_('Could not create example database'),str(msg)) - except OSError,msg: - ErrorDialog(_('Could not create example database'),str(msg)) - - filename = "%s/%s" % (dest,const.xmlFile) - DbPrompter.open_native(self,filename,const.app_gramps_xml) - -DARKEN = 1.4 - -def ms_shift_color_component (component, shift_by): - if shift_by > 1.0 : - result = int(component * (2 - shift_by)) - else: - result = 0xffff - shift_by * (0xffff - component) - return (result & 65535) - -def modify_color(color): - red = ms_shift_color_component(color.red,DARKEN) - green = ms_shift_color_component(color.green,DARKEN) - blue = ms_shift_color_component(color.blue,DARKEN) - return (red,green,blue) - -def set_panel(obj): - style = obj.get_style().copy() - color = style.bg[gtk.STATE_NORMAL] - (r,g,b) = modify_color(color) - new_color = obj.get_colormap().alloc_color(r,g,b) - style.bg[gtk.STATE_NORMAL] = new_color - style.bg[gtk.STATE_PRELIGHT] = new_color - style.bg[gtk.STATE_ACTIVE] = new_color - style.bg[gtk.STATE_INSENSITIVE] = new_color - style.bg[gtk.STATE_SELECTED] = new_color - obj.set_style(style) - -#------------------------------------------------------------------------- -# -# Start it all -# -#------------------------------------------------------------------------- -if __name__ == '__main__': - Gramps(None) - gtk.main()