diff --git a/ChangeLog b/ChangeLog index 23de6e81a..8405b52f2 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,20 @@ +2005-06-07 Alex Roitman + * src/gramps.glade (selecty_person): Change positioning; add icon. + * src/edit_person.glade (event_tab): Correct tooltips. + * src/SelectEvent.py: Add to CVS. + * src/Makefile.am: Ship SelectEvent.py file. + * src/SelectChild.py (build_list): Use mapping from Utils. + * src/ReadGrdb.py (importData): Properly copy event table. + * src/ListBox.py: Properly fill in the Combo maps without + collisions; Add Role to the EventListbox; Support selecting an + existing Event object. + * src/GrampsInMemDB.py: Support for event id table. + * src/GrampsDbBase.py: Support for event id table. + * src/GrampsBSDDB.py: Support for event id table; emit + event-delete signal when events are deleted. + * src/EventView.py: Support deleting events. + * src/EventEdit.py: Support deleting events; Proper adding events. + 2005-06-07 Martin Hawlisch * various: const to RelLib transitition. diff --git a/src/EventEdit.py b/src/EventEdit.py index 3ae085a18..6f67ea0b0 100644 --- a/src/EventEdit.py +++ b/src/EventEdit.py @@ -335,18 +335,20 @@ class EventEditor: # self.elist.append(ename) # self.elist.sort() - just_added = False - if self.event == None: - self.event = RelLib.Event() - self.event.set_handle(Utils.create_id()) - self.event.set_source_reference_list(self.srcreflist) - self.event.set_type(event_data) - just_added = True + just_added = self.event.handle == None +# if just_added: +# self.event.set_handle(Utils.create_id()) +# self.event.set_source_reference_list(self.srcreflist) +# self.event.set_type(event_data) +# just_added = True self.update_event(event_data,self.date,eplace_obj,edesc,enote,eformat, epriv,ecause) - - if self.parent.lists_changed: + if just_added: + trans = self.db.transaction_begin() + self.db.add_event(self.event,trans) + self.db.transaction_commit(trans,_("Add Event")) + elif self.parent.lists_changed: trans = self.db.transaction_begin() self.db.commit_event(self.event,trans) self.db.transaction_commit(trans,_("Edit Event")) @@ -411,7 +413,7 @@ class EventEditor: # #------------------------------------------------------------------------- class EventRefEditor: - def __init__(self, event_ref, event, referent, database, update, parent): + def __init__(self, event, event_ref, referent, database, update, parent): self.db = database self.parent = parent self.referent = referent @@ -682,3 +684,36 @@ class EventRefEditor: Utils.bold_label(self.eer_notes_label) else: Utils.unbold_label(self.eer_notes_label) + +#------------------------------------------------------------------------- +# +# Delete Query class +# +#------------------------------------------------------------------------- +class DelEventQuery: + def __init__(self,event,db,person_list,family_list): + self.event = event + self.db = db + self.person_list = person_list + self.family_list = family_list + + def query_response(self): + trans = self.db.transaction_begin() + self.db.disable_signals() + + ev_handle_list = [self.event.get_handle()] + + for handle in self.person_list: + person = self.db.get_person_from_handle(handle) + person.remove_handle_references('Event',ev_handle_list) + self.db.commit_person(person,trans) + + for handle in self.family_list: + family = self.db.get_family_from_handle(handle) + family.remove_handle_references('Event',ev_handle_list) + self.db.commit_family(family,trans) + + self.db.enable_signals() + self.db.remove_event(self.event.get_handle(),trans) + self.db.transaction_commit( + trans,_("Delete Event (%s)") % self.event.get_gramps_id()) diff --git a/src/EventView.py b/src/EventView.py index f448614f2..5d885b27e 100644 --- a/src/EventView.py +++ b/src/EventView.py @@ -46,7 +46,6 @@ from QuestionDialog import QuestionDialog, ErrorDialog #------------------------------------------------------------------------- from gettext import gettext as _ - column_names = [ _('Description'), _('ID'), @@ -126,7 +125,6 @@ class EventView: for pair in self.parent.db.get_event_column_order(): if not pair[0]: continue - print pair name = column_names[pair[1]] column = gtk.TreeViewColumn(name, self.renderer, text=pair[1]) column.connect('clicked',self.column_clicked,index) @@ -219,10 +217,10 @@ class EventView: event = self.parent.db.get_event_from_handle(event_handle) - ans = EventEdit.DelReposQuery(event,self.parent.db, - person_list+family_list) + ans = EventEdit.DelEventQuery(event,self.parent.db, + person_list,family_list) - if len(person_list+family_list) > 0: + if len(person_list) + len(family_list) > 0: msg = _('This event is currently being used. Deleting it ' 'will remove it from the database and from all ' 'people and families that reference it.') diff --git a/src/GrampsBSDDB.py b/src/GrampsBSDDB.py index e0acb8e2a..bb7271313 100644 --- a/src/GrampsBSDDB.py +++ b/src/GrampsBSDDB.py @@ -168,6 +168,10 @@ class GrampsBSDDB(GrampsDbBase): self.fid_trans.set_flags(db.DB_DUP) self.fid_trans.open(name, "fidtrans", db.DB_HASH, flags=openflags) + self.eid_trans = db.DB(self.env) + self.eid_trans.set_flags(db.DB_DUP) + self.eid_trans.open(name, "eidtrans", db.DB_HASH, flags=openflags) + self.pid_trans = db.DB(self.env) self.pid_trans.set_flags(db.DB_DUP) self.pid_trans.open(name, "pidtrans", db.DB_HASH, flags=openflags) @@ -196,6 +200,7 @@ class GrampsBSDDB(GrampsDbBase): self.person_map.associate(self.surnames, find_surname, openflags) self.person_map.associate(self.id_trans, find_idmap, openflags) self.family_map.associate(self.fid_trans, find_idmap, openflags) + self.event_map.associate(self.eid_trans, find_idmap, openflags) self.repository_map.associate(self.rid_trans, find_idmap, openflags) self.repository_map.associate(self.repository_types, find_repository_type, openflags) self.place_map.associate(self.pid_trans, find_idmap, openflags) @@ -247,6 +252,7 @@ class GrampsBSDDB(GrampsDbBase): self.repository_types.close() self.id_trans.close() self.fid_trans.close() + self.eid_trans.close() self.rid_trans.close() self.oid_trans.close() self.sid_trans.close() @@ -367,6 +373,7 @@ class GrampsBSDDB(GrampsDbBase): if transaction != None: old_data = self.event_map.get(str(handle)) transaction.add(EVENT_KEY,handle,old_data) + self.emit('event-delete',([str(handle)],)) self.event_map.delete(str(handle)) def remove_place(self,handle,transaction): @@ -387,7 +394,7 @@ class GrampsBSDDB(GrampsDbBase): def get_person_from_gramps_id(self,val): """finds a Person in the database from the passed gramps' ID. - If no such Person exists, a new Person is added to the database.""" + If no such Person exists, None is returned.""" data = self.id_trans.get(str(val)) if data: @@ -399,7 +406,7 @@ class GrampsBSDDB(GrampsDbBase): def get_family_from_gramps_id(self,val): """finds a Family in the database from the passed gramps' ID. - If no such Family exists, a new Person is added to the database.""" + If no such Family exists, None is returned.""" data = self.fid_trans.get(str(val)) if data: @@ -409,9 +416,21 @@ class GrampsBSDDB(GrampsDbBase): else: return None + def get_event_from_gramps_id(self,val): + """finds an Event in the database from the passed gramps' ID. + If no such Event exists, None is returned.""" + + data = self.eid_trans.get(str(val)) + if data: + event = Event() + event.unserialize(cPickle.loads(data)) + return event + else: + return None + def get_place_from_gramps_id(self,val): """finds a Place in the database from the passed gramps' ID. - If no such Place exists, a new Person is added to the database.""" + If no such Place exists, None is returned.""" data = self.pid_trans.get(str(val)) if data: @@ -423,7 +442,7 @@ class GrampsBSDDB(GrampsDbBase): def get_source_from_gramps_id(self,val): """finds a Source in the database from the passed gramps' ID. - If no such Source exists, a new Person is added to the database.""" + If no such Source exists, None is returned.""" data = self.sid_trans.get(str(val)) if data: @@ -435,7 +454,7 @@ class GrampsBSDDB(GrampsDbBase): def get_repository_from_gramps_id(self,val): """finds a Repository in the database from the passed gramps' ID. - If no such Repository exists, a new Repository is added to the database.""" + If no such Repository exists, None is returned.""" data = self.rid_trans.get(str(val)) if data: @@ -447,7 +466,7 @@ class GrampsBSDDB(GrampsDbBase): def get_object_from_gramps_id(self,val): """finds a MediaObject in the database from the passed gramps' ID. - If no such MediaObject exists, a new Person is added to the database.""" + If no such MediaObject exists, None is returned.""" data = self.oid_trans.get(str(val)) if data: @@ -472,6 +491,7 @@ class GrampsBSDDB(GrampsDbBase): self.name_group.sync() self.id_trans.sync() self.fid_trans.sync() + self.eid_trans.sync() self.pid_trans.sync() self.sid_trans.sync() self.rid_trans.sync() diff --git a/src/GrampsDbBase.py b/src/GrampsDbBase.py index f1a1ae3f4..9c3c4ffdd 100644 --- a/src/GrampsDbBase.py +++ b/src/GrampsDbBase.py @@ -192,6 +192,7 @@ class GrampsDbBase(GrampsDBCallback.GrampsDBCallback): self.sid_trans = None self.oid_trans = None self.rid_trans = None + self.eid_trans = None self.env = None self.person_map = None self.family_map = None @@ -404,6 +405,9 @@ class GrampsDbBase(GrampsDBCallback.GrampsDBCallback): off the person ID prefix. """ index = self.eprefix % self.emap_index + while self.eid_trans.get(str(index)): + self.emap_index += 1 + index = self.eprefix % self.emap_index self.emap_index += 1 return index diff --git a/src/GrampsInMemDB.py b/src/GrampsInMemDB.py index 97fdbe3a0..53de8fadf 100644 --- a/src/GrampsInMemDB.py +++ b/src/GrampsInMemDB.py @@ -84,6 +84,7 @@ class GrampsInMemDB(GrampsDbBase): self.id_trans = {} self.pid_trans = {} self.fid_trans = {} + self.eid_trans = {} self.sid_trans = {} self.rid_trans = {} self.oid_trans = {} @@ -188,6 +189,7 @@ class GrampsInMemDB(GrampsDbBase): del self.family_map[str(handle)] def _del_event(self,handle): + del self.eid_trans[event.get_gramps_id()] del self.event_map[str(handle)] def commit_person(self,person,transaction,change_time=None): @@ -211,6 +213,13 @@ class GrampsInMemDB(GrampsDbBase): self.fid_trans[gid] = family.get_handle() GrampsDbBase.commit_family(self,family,transaction,change_time) + def commit_event(self,event,transaction,change_time=None): + if self.readonly or not event.get_handle(): + return + gid = event.get_gramps_id() + self.eid_trans[gid] = event.get_handle() + GrampsDbBase.commit_event(self,event,transaction,change_time) + def commit_media_object(self,obj,transaction,change_time=None): if self.readonly or not obj.get_handle(): return @@ -252,6 +261,16 @@ class GrampsInMemDB(GrampsDbBase): return family return None + def get_event_from_gramps_id(self,val): + handle = self.eid_trans.get(str(val)) + if handle: + data = self.event_map[handle] + if data: + event = Event() + event.unserialize(data) + return event + return None + def get_place_from_gramps_id(self,val): handle = self.pid_trans.get(str(val)) if handle: diff --git a/src/ListBox.py b/src/ListBox.py index deaf79b7f..693dd7e86 100644 --- a/src/ListBox.py +++ b/src/ListBox.py @@ -83,12 +83,12 @@ class ListBox: self.change_list = Set() def build_maps(self,custom,string_map): - self.name_map = {} - self.val_map = string_map - self.custom = custom - for key in self.val_map.keys(): - val = self.val_map[key] - self.name_map[val] = key + name_map = {} + val_map = string_map + for key in val_map.keys(): + val = val_map[key] + name_map[val] = key + return (name_map,val_map) def keypress(self,obj,event): if event.keyval == 65379: @@ -229,14 +229,15 @@ class AttrListBox(ReorderListBox): ListBox.__init__(self, parent, person, obj, label, button_list, titles) - self.build_maps(RelLib.Attribute.CUSTOM, Utils.personal_attributes) + self.attr_name_map,self.attr_val_map = self.build_maps( + RelLib.Attribute.CUSTOM,Utils.personal_attributes) def set_type(self,index,value): - val = self.name_map.get(value,self.custom) - if val == self.custom: + val = self.attr_name_map.get(value,RelLib.Attribute.CUSTOM) + if val == RelLib.Attribute.CUSTOM: self.data[index].set_type((val,value)) else: - self.data[index].set_type((val,self.val_map[val])) + self.data[index].set_type((val,self.attr_val_map[val])) self.change_list.add(self.data[index]) def set_value(self,index,value): @@ -290,32 +291,48 @@ class EventListBox(ReorderListBox): self.data.append((event_ref, parent.db.get_event_from_handle(event_ref.ref))) - custom_str = Utils.personal_events[RelLib.Event.CUSTOM] - eventnames = filter(lambda x: x != custom_str, + ev_custom_str = Utils.personal_events[RelLib.Event.CUSTOM] + eventnames = filter(lambda x: x != ev_custom_str, Utils.personal_events.values()) eventnames.sort(locale.strcoll) + role_custom_str = Utils.event_roles[RelLib.EventRef.CUSTOM] + rolenames = filter(lambda x: x != role_custom_str, + Utils.event_roles.values()) + evalues = [ # Title Sort Col Size, Type Argument - (_('Event'), NOSORT, 100, COMBO, eventnames, self.set_type), - (_('Description'), NOSORT, 140, TEXT, None, self.set_description), - (_('Date'), NOSORT, 100, TEXT, None, self.set_date), - (_('Place'), NOSORT, 100, TEXT, None, self.set_place), - (_('Source'), NOSORT, 50, TOGGLE, None, None), - (_('Note'), NOSORT, 50, TOGGLE, None, None), + (_('Event'), NOSORT, 100, COMBO, eventnames, self.set_type), + (_('Description'), NOSORT, 140, TEXT, None, self.set_description), + (_('Date'), NOSORT, 100, TEXT, None, self.set_date), + (_('Place'), NOSORT, 100, TEXT, None, self.set_place), + (_('Role'), NOSORT, 100, COMBO, rolenames, self.set_role), + (_('Source'), NOSORT, 50, TOGGLE, None, None), + (_('Note'), NOSORT, 50, TOGGLE, None, None), ] ReorderListBox.__init__(self, parent, person, obj, label, button_list, evalues, DdTargets.EVENT) - self.build_maps(RelLib.Event.CUSTOM,Utils.personal_events) + self.ev_name_map,self.ev_val_map = self.build_maps( + RelLib.Event.CUSTOM,Utils.personal_events) + self.ref_name_map,self.ref_val_map = self.build_maps( + RelLib.EventRef.CUSTOM,Utils.personal_events) def set_type(self,index,value): - val = self.name_map.get(value,self.custom) - if val == self.custom: + val = self.ev_name_map.get(value,RelLib.Event.CUSTOM) + if val == RelLib.Event.CUSTOM: self.data[index][1].set_type((val,value)) else: - self.data[index][1].set_type((val,self.val_map[val])) + self.data[index][1].set_type((val,self.ev_val_map[val])) + self.change_list.add(self.data[index]) + + def set_role(self,index,value): + val = self.ref_name_map.get(value,RelLib.EventRef.CUSTOM) + if val == RelLib.EventRef.CUSTOM: + self.data[index][0].set_role((val,value)) + else: + self.data[index][0].set_role((val,self.ref_val_map[val])) self.change_list.add(self.data[index]) def set_description(self,index,value): @@ -343,15 +360,19 @@ class EventListBox(ReorderListBox): Creates eventref for an existing event. """ # select existing event - event = RelLiv.Event() - EventEdit.EventRefEditor(event,None,self.person,self.parent.db, - self.edit_callback,self.parent) + import SelectEvent + sel_event = SelectEvent.SelectEvent(self.db,_('Select Event'), + self.parent.window) + event = sel_event.run() + if event: + EventEdit.EventRefEditor(event,None,self.person,self.parent.db, + self.edit_callback,self.parent) def update(self,obj): store,node = self.list_model.get_selected() if not node: return - event,event_ref = self.list_model.get_object(node) + event_ref,event = self.list_model.get_object(node) EventEdit.EventRefEditor(event,event_ref,self.person,self.parent.db, self.edit_callback,self.parent) # self.parent, self.name, Utils.personal_events, @@ -373,49 +394,9 @@ class EventListBox(ReorderListBox): name = etype[1] else: name = Utils.personal_events[etype[0]] - return [name, event.get_description(), event.get_date(), - pname, has_source, has_note] - - def unpickle(self, data): - foo = pickle.loads(data); - for src in foo.get_source_references(): - base_handle = src.get_base_handle() - newbase = self.db.get_source_from_handle(base_handle) - src.set_base_handle(newbase.get_handle()) - place = foo.get_place_handle() - if place: - foo.set_place_handle(place.get_handle()) - self.data.insert(row,foo.get_handle()) - -## def edit_callback(self,data): -## self.changed = True -## self.change_list.add(data) -## if data not in self.data: -## self.data.append(data) -## self.redraw() -## try: -## self.list_model.select_iter(self.node_map[data]) -## except: -## print "Edit callback failed" -## self.changed = True -## changed = False -## event_ref,event = data -## if event.handle == -## for val in self.data: -## if data.handle == val[1].handle: -## self.change_list.add(val) -## changed = True -## if not changed: -## ref = RelLib.EventRef() -## ref.ref = data.handle -## new_data = (ref,data) -## self.change_list.add(new_data) -## self.data.append(new_data) -## self.redraw() -## try: -## self.list_model.select_iter(self.node_map[new_data]) -## except: -## print "Edit callback failed" + ref_role = event_ref.get_role() + if ref_role[0] == RelLib.EventRef.CUSTOM \ + or not Utils.event_roles.has_key(ref_role[0]): class NameListBox(ReorderListBox): @@ -442,14 +423,15 @@ class NameListBox(ReorderListBox): ReorderListBox.__init__(self, parent, person, obj, label, button_list, titles, DdTargets.NAME) - self.build_maps(RelLib.Name.CUSTOM,Utils.name_types) + self.name_name_map,self.name_val_map = self.build_maps( + RelLib.Name.CUSTOM,Utils.name_types) def set_type(self,index,value): - val = self.name_map.get(value,self.custom) - if val == self.custom: + val = self.name_name_map.get(value,RelLib.Name.CUSTOM) + if val == RelLib.Name.CUSTOM: self.data[index].set_type((val,value)) else: - self.data[index].set_type((val,self.val_map[val])) + self.data[index].set_type((val,self.name_val_map[val])) self.change_list.add(self.data[index]) def set_name(self,index,value): diff --git a/src/Makefile.am b/src/Makefile.am index 3d5e723ca..d2a3020ed 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -121,7 +121,8 @@ gdir_PYTHON = \ ReportOptions.py\ ReadGrdb.py\ WriteGrdb.py\ - EventView.py + EventView.py\ + SelectEvent.py # Could use GNU make's ':=' syntax for nice wildcard use. # If not using GNU make, then list all files individually diff --git a/src/ReadGrdb.py b/src/ReadGrdb.py index e3a001545..cc7a5eb20 100644 --- a/src/ReadGrdb.py +++ b/src/ReadGrdb.py @@ -165,7 +165,11 @@ def importData(database, filename, callback=None,cl=0,use_trans=True): for event_handle in other_database.event_map.keys(): event = other_database.get_event_from_handle(event_handle) - # Events don't have gramps IDs, so we don't need to check here + # Then we check gramps_id for conflicts and change it if needed + gramps_id = str(event.get_gramps_id()) + if database.eid_trans.has_key(gramps_id): + gramps_id = database.find_next_event_gramps_id() + event.set_gramps_id(gramps_id) database.add_event(event,trans) database.transaction_commit(trans,_("Import database")) diff --git a/src/SelectChild.py b/src/SelectChild.py index be83ca7f2..90a168002 100644 --- a/src/SelectChild.py +++ b/src/SelectChild.py @@ -115,7 +115,7 @@ class SelectChild: opt_menu.add_attribute(cell,'text',0) store = gtk.ListStore(str) - for val in const.child_rel_list: + for val in Utils.child_relations.values(): store.append(row=[val]) opt_menu.set_model(store) opt_menu.set_active(sel) diff --git a/src/SelectEvent.py b/src/SelectEvent.py new file mode 100644 index 000000000..0a0635bf8 --- /dev/null +++ b/src/SelectEvent.py @@ -0,0 +1,119 @@ +# +# Gramps - a GTK+/GNOME based genealogy program +# +# Copyright (C) 2003-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$ + +#------------------------------------------------------------------------- +# +# internationalization +# +#------------------------------------------------------------------------- +from gettext import gettext as _ + +#------------------------------------------------------------------------- +# +# GTK/Gnome modules +# +#------------------------------------------------------------------------- + +import gtk +import gtk.glade + +#------------------------------------------------------------------------- +# +# gramps modules +# +#------------------------------------------------------------------------- +import const +import Utils +import ListModel +import RelLib + +#------------------------------------------------------------------------- +# +# SelectEvent +# +#------------------------------------------------------------------------- +class SelectEvent: + + def __init__(self,db,title,parent_window=None): + + self.db = db + self.glade = gtk.glade.XML(const.gladeFile,"select_person","gramps") + self.top = self.glade.get_widget('select_person') + title_label = self.glade.get_widget('title') + self.elist = self.glade.get_widget('plist') + + Utils.set_titles(self.top,title_label,title) + + titles = [(_('Description'),4,150), (_('ID'),1,50), + (_('Type'),2,70), (_('Date'),3,50), (_('Place'),3,150), + (_('Cause'),3,50), ('',4,0) ] + self.ncols = len(titles) + + self.model = ListModel.ListModel(self.elist,titles) + + self.redraw() + self.top.show() + + if parent_window: + self.top.set_transient_for(parent_window) + + def redraw(self): + self.model.clear() + self.model.new_model() + + for handle in self.db.get_event_handles(): + event = self.db.get_event_from_handle(handle) + desc = event.get_description() + etype = event.get_type() + if etype[0] == RelLib.Event.CUSTOM \ + or not Utils.personal_events.has_key(etype[0]): + name = etype[1] + else: + name = Utils.personal_events[etype[0]] + the_id = event.get_gramps_id() + place_handle = event.get_place_handle() + if place_handle: + pname = self.db.get_place_from_handle(place_handle).get_title() + else: + pname = u'' + date = event.get_date() + cause = event.get_cause() + self.model.add([desc,the_id,name,date,pname,cause],handle) + + self.model.connect_model() + + def run(self): + val = self.top.run() + + if val == gtk.RESPONSE_OK: + store,node = self.model.get_selected() + if node: + data = self.model.get_data(node,range(self.ncols)) + handle = data[6] + return_value = self.db.get_event_from_handle(handle) + else: + return_value = None + self.top.destroy() + return return_value + else: + self.top.destroy() + return None diff --git a/src/edit_person.glade b/src/edit_person.glade index d1dbfc037..032da62d3 100644 --- a/src/edit_person.glade +++ b/src/edit_person.glade @@ -739,7 +739,7 @@ Unknown True - Select an existing media object from the database and place it in this gallery + Select an existing event object from the database and add a reference for this person True GTK_RELIEF_NORMAL True @@ -768,7 +768,7 @@ Unknown True False - Edit the selected name + Edit the selected event reference True GTK_RELIEF_NORMAL True @@ -796,7 +796,7 @@ Unknown True False - Delete the selected name + Delete the selected event reference True GTK_RELIEF_NORMAL True diff --git a/src/gramps.glade b/src/gramps.glade index 39db8b473..b74c172c1 100644 --- a/src/gramps.glade +++ b/src/gramps.glade @@ -20127,12 +20127,13 @@ Very High GTK_WINDOW_TOPLEVEL - GTK_WIN_POS_NONE + GTK_WIN_POS_CENTER_ON_PARENT True 500 450 True False + gramps.png True False False