moved files to DataViews
svn: r6071
This commit is contained in:
168
src/DataViews/EventView.py
Normal file
168
src/DataViews/EventView.py
Normal file
@@ -0,0 +1,168 @@
|
||||
# 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$
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
#
|
||||
# GTK/Gnome modules
|
||||
#
|
||||
#-------------------------------------------------------------------------
|
||||
import gtk
|
||||
import gtk.gdk
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
#
|
||||
# gramps modules
|
||||
#
|
||||
#-------------------------------------------------------------------------
|
||||
import RelLib
|
||||
import PageView
|
||||
import DisplayModels
|
||||
import const
|
||||
import Utils
|
||||
from QuestionDialog import QuestionDialog, ErrorDialog
|
||||
from Editors import EditEvent, DelEventQuery
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
#
|
||||
# internationalization
|
||||
#
|
||||
#-------------------------------------------------------------------------
|
||||
from gettext import gettext as _
|
||||
|
||||
column_names = [
|
||||
_('Description'),
|
||||
_('ID'),
|
||||
_('Type'),
|
||||
_('Date'),
|
||||
_('Place'),
|
||||
_('Cause'),
|
||||
_('Last Changed'),
|
||||
]
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
#
|
||||
# EventView
|
||||
#
|
||||
#-------------------------------------------------------------------------
|
||||
class EventView(PageView.ListView):
|
||||
def __init__(self,dbstate,uistate):
|
||||
|
||||
signal_map = {
|
||||
'event-add' : self.row_add,
|
||||
'event-update' : self.row_update,
|
||||
'event-delete' : self.row_delete,
|
||||
'event-rebuild' : self.build_tree,
|
||||
}
|
||||
|
||||
PageView.ListView.__init__(self,'Event View',dbstate,uistate,
|
||||
column_names,len(column_names),
|
||||
DisplayModels.EventModel,
|
||||
signal_map)
|
||||
|
||||
def column_order(self):
|
||||
return self.dbstate.db.get_event_column_order()
|
||||
|
||||
def get_stock(self):
|
||||
return 'gramps-event'
|
||||
|
||||
def ui_definition(self):
|
||||
return '''<ui>
|
||||
<menubar name="MenuBar">
|
||||
<menu action="ViewMenu">
|
||||
<menuitem action="Filter"/>
|
||||
</menu>
|
||||
<menu action="EditMenu">
|
||||
<placeholder name="CommonEdit">
|
||||
<menuitem action="Add"/>
|
||||
<menuitem action="Edit"/>
|
||||
<menuitem action="Remove"/>
|
||||
</placeholder>
|
||||
</menu>
|
||||
</menubar>
|
||||
<toolbar name="ToolBar">
|
||||
<placeholder name="CommonEdit">
|
||||
<toolitem action="Add"/>
|
||||
<toolitem action="Edit"/>
|
||||
<toolitem action="Remove"/>
|
||||
</placeholder>
|
||||
</toolbar>
|
||||
<popup name="Popup">
|
||||
<menuitem action="Add"/>
|
||||
<menuitem action="Edit"/>
|
||||
<menuitem action="Remove"/>
|
||||
</popup>
|
||||
</ui>'''
|
||||
|
||||
def on_double_click(self,obj,event):
|
||||
handle = self.first_selected()
|
||||
the_event = self.dbstate.db.get_event_from_handle(handle)
|
||||
try:
|
||||
EditEvent(the_event,self.dbstate, self.uistate, [])
|
||||
except Errors.WindowActiveError:
|
||||
pass
|
||||
|
||||
def add(self,obj):
|
||||
try:
|
||||
EditEvent(RelLib.Event(),self.dbstate, self.uistate, [])
|
||||
except Errors.WindowActiveError:
|
||||
pass
|
||||
|
||||
def remove(self,obj):
|
||||
for event_handle in self.selected_handles():
|
||||
db = self.dbstate.db
|
||||
person_list = [ handle for handle in
|
||||
db.get_person_handles(False)
|
||||
if db.get_person_from_handle(handle).has_handle_reference('Event',event_handle) ]
|
||||
family_list = [ handle for handle in
|
||||
db.get_family_handles()
|
||||
if db.get_family_from_handle(handle).has_handle_reference('Event',event_handle) ]
|
||||
|
||||
event = db.get_event_from_handle(event_handle)
|
||||
|
||||
ans = DelEventQuery(event,db,
|
||||
person_list,family_list)
|
||||
|
||||
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.')
|
||||
else:
|
||||
msg = _('Deleting event will remove it from the database.')
|
||||
|
||||
msg = "%s %s" % (msg,Utils.data_recover_msg)
|
||||
descr = event.get_description()
|
||||
if descr == "":
|
||||
descr = event.get_gramps_id()
|
||||
|
||||
QuestionDialog(_('Delete %s?') % descr, msg,
|
||||
_('_Delete Event'),ans.query_response)
|
||||
|
||||
def edit(self,obj):
|
||||
mlist = []
|
||||
self.selection.selected_foreach(self.blist,mlist)
|
||||
|
||||
for handle in mlist:
|
||||
event = self.dbstate.db.get_event_from_handle(handle)
|
||||
try:
|
||||
EditEvent(event, self.dbstate, self.uistate)
|
||||
except Errors.WindowActiveError:
|
||||
pass
|
||||
|
136
src/DataViews/FamilyList.py
Normal file
136
src/DataViews/FamilyList.py
Normal file
@@ -0,0 +1,136 @@
|
||||
# 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$
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
#
|
||||
# GTK/Gnome modules
|
||||
#
|
||||
#-------------------------------------------------------------------------
|
||||
import gtk
|
||||
import gtk.gdk
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
#
|
||||
# gramps modules
|
||||
#
|
||||
#-------------------------------------------------------------------------
|
||||
import RelLib
|
||||
import PageView
|
||||
import DisplayModels
|
||||
import const
|
||||
import Utils
|
||||
import Errors
|
||||
from QuestionDialog import QuestionDialog, ErrorDialog
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
#
|
||||
# internationalization
|
||||
#
|
||||
#-------------------------------------------------------------------------
|
||||
from gettext import gettext as _
|
||||
|
||||
column_names = [
|
||||
_('ID'),
|
||||
_('Father'),
|
||||
_('Mother'),
|
||||
_('Relationship'),
|
||||
_('Last Changed'),
|
||||
]
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
#
|
||||
# FamilyListView
|
||||
#
|
||||
#-------------------------------------------------------------------------
|
||||
class FamilyListView(PageView.ListView):
|
||||
def __init__(self,dbstate,uistate):
|
||||
|
||||
signal_map = {
|
||||
'family-add' : self.row_add,
|
||||
'family-update' : self.row_update,
|
||||
'family-delete' : self.row_delete,
|
||||
'family-rebuild' : self.build_tree,
|
||||
}
|
||||
|
||||
PageView.ListView.__init__(self,'Family List View',dbstate,uistate,
|
||||
column_names,len(column_names),
|
||||
DisplayModels.FamilyModel,
|
||||
signal_map)
|
||||
|
||||
def column_order(self):
|
||||
return self.dbstate.db.get_family_list_column_order()
|
||||
|
||||
def get_stock(self):
|
||||
return 'gramps-family-list'
|
||||
|
||||
def ui_definition(self):
|
||||
return '''<ui>
|
||||
<menubar name="MenuBar">
|
||||
<menu action="EditMenu">
|
||||
<placeholder name="CommonEdit">
|
||||
<menuitem action="Add"/>
|
||||
<menuitem action="Edit"/>
|
||||
<menuitem action="Remove"/>
|
||||
</placeholder>
|
||||
</menu>
|
||||
<menu action="ViewMenu">
|
||||
<menuitem action="Filter"/>
|
||||
</menu>
|
||||
</menubar>
|
||||
<toolbar name="ToolBar">
|
||||
<placeholder name="CommonEdit">
|
||||
<toolitem action="Add"/>
|
||||
<toolitem action="Edit"/>
|
||||
<toolitem action="Remove"/>
|
||||
</placeholder>
|
||||
</toolbar>
|
||||
<popup name="Popup">
|
||||
<menuitem action="Add"/>
|
||||
<menuitem action="Edit"/>
|
||||
<menuitem action="Remove"/>
|
||||
</popup>
|
||||
</ui>'''
|
||||
|
||||
def on_double_click(self,obj,event):
|
||||
return
|
||||
|
||||
def add(self,obj):
|
||||
from Editors import EditFamily
|
||||
family = RelLib.Family()
|
||||
try:
|
||||
EditFamily(self.dbstate,self.uistate,[],family)
|
||||
except Errors.WindowActiveError:
|
||||
pass
|
||||
|
||||
def remove(self,obj):
|
||||
return
|
||||
|
||||
def edit(self,obj):
|
||||
mlist = []
|
||||
self.selection.selected_foreach(self.blist,mlist)
|
||||
|
||||
for handle in mlist:
|
||||
from Editors import EditFamily
|
||||
family = self.dbstate.db.get_family_from_handle(handle)
|
||||
try:
|
||||
EditFamily(self.dbstate,self.uistate,[],family)
|
||||
except Errors.WindowActiveError:
|
||||
pass
|
598
src/DataViews/FamilyView.py
Normal file
598
src/DataViews/FamilyView.py
Normal file
@@ -0,0 +1,598 @@
|
||||
#-------------------------------------------------------------------------
|
||||
#
|
||||
# Python modules
|
||||
#
|
||||
#-------------------------------------------------------------------------
|
||||
from gettext import gettext as _
|
||||
import gc
|
||||
import re
|
||||
import cgi
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
#
|
||||
# GTK/Gnome modules
|
||||
#
|
||||
#-------------------------------------------------------------------------
|
||||
import gobject
|
||||
import gtk
|
||||
import pango
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
#
|
||||
# Gramps Modules
|
||||
#
|
||||
#-------------------------------------------------------------------------
|
||||
import RelLib
|
||||
import PageView
|
||||
import NameDisplay
|
||||
import Utils
|
||||
import DateHandler
|
||||
import ImgManip
|
||||
import ReportUtils
|
||||
import Config
|
||||
import GrampsWidgets
|
||||
import Errors
|
||||
|
||||
_GenderCode = {
|
||||
RelLib.Person.MALE : u'\u2642',
|
||||
RelLib.Person.FEMALE : u'\u2640',
|
||||
RelLib.Person.UNKNOWN : u'\u2650',
|
||||
}
|
||||
|
||||
_NAME_START = 0
|
||||
_LABEL_START = 1
|
||||
_LABEL_STOP = 2
|
||||
_DATA_START = _LABEL_STOP
|
||||
_DATA_STOP = _DATA_START+1
|
||||
_BTN_START = _DATA_STOP
|
||||
_BTN_STOP = _BTN_START+2
|
||||
_PLABEL_START = 2
|
||||
_PLABEL_STOP = _PLABEL_START+1
|
||||
_PDATA_START = _PLABEL_STOP
|
||||
_PDATA_STOP = _PDATA_START+2
|
||||
_PDTLS_START = _PLABEL_STOP
|
||||
_PDTLS_STOP = _PDTLS_START+2
|
||||
_CLABEL_START = _PLABEL_START+1
|
||||
_CLABEL_STOP = _CLABEL_START+1
|
||||
_CDATA_START = _CLABEL_STOP
|
||||
_CDATA_STOP = _CDATA_START+1
|
||||
_CDTLS_START = _CDATA_START
|
||||
_CDTLS_STOP = _CDTLS_START+1
|
||||
_ALABEL_START = 1
|
||||
_ALABEL_STOP = _ALABEL_START+1
|
||||
_ADATA_START = _ALABEL_STOP
|
||||
_ADATA_STOP = _ADATA_START+3
|
||||
_SDATA_START = 3
|
||||
_SDATA_STOP = 5
|
||||
|
||||
class AttachList:
|
||||
|
||||
def __init__(self):
|
||||
self.list = []
|
||||
self.max_x = 0
|
||||
self.max_y = 0
|
||||
|
||||
def attach(self,widget,x0,x1,y0,y1,xoptions=gtk.EXPAND|gtk.FILL,
|
||||
yoptions=gtk.EXPAND|gtk.FILL):
|
||||
assert(x1>x0)
|
||||
self.list.append((widget,x0,x1,y0,y1,xoptions,yoptions))
|
||||
self.max_x = max(self.max_x,x1)
|
||||
self.max_y = max(self.max_y,y1)
|
||||
|
||||
class FamilyView(PageView.PersonNavView):
|
||||
|
||||
def __init__(self,dbstate,uistate):
|
||||
PageView.PersonNavView.__init__(self,'Relationship View',dbstate,uistate)
|
||||
dbstate.connect('database-changed',self.change_db)
|
||||
dbstate.connect('active-changed',self.change_person)
|
||||
self.show_siblings = Config.get_family_siblings()
|
||||
if self.show_siblings == None:
|
||||
self.show_siblings = True
|
||||
self.show_details = Config.get_family_details()
|
||||
if self.show_details == None:
|
||||
self.show_details = True
|
||||
|
||||
def get_stock(self):
|
||||
"""
|
||||
Returns the name of the stock icon to use for the display.
|
||||
This assumes that this icon has already been registered with
|
||||
GNOME as a stock icon.
|
||||
"""
|
||||
return 'gramps-family'
|
||||
|
||||
def build_widget(self):
|
||||
self.scroll = gtk.ScrolledWindow()
|
||||
self.scroll.set_policy(gtk.POLICY_AUTOMATIC,gtk.POLICY_AUTOMATIC)
|
||||
self.scroll.show()
|
||||
self.vbox = gtk.VBox()
|
||||
self.vbox.show()
|
||||
self.child = None
|
||||
self.scroll.add_with_viewport(self.vbox)
|
||||
return self.scroll
|
||||
|
||||
def ui_definition(self):
|
||||
"""
|
||||
Specifies the UIManager XML code that defines the menus and buttons
|
||||
associated with the interface.
|
||||
"""
|
||||
return '''<ui>
|
||||
<menubar name="MenuBar">
|
||||
<menu action="GoMenu">
|
||||
<placeholder name="CommonGo">
|
||||
<menuitem action="Back"/>
|
||||
<menuitem action="Forward"/>
|
||||
<separator/>
|
||||
<menuitem action="HomePerson"/>
|
||||
<separator/>
|
||||
</placeholder>
|
||||
</menu>
|
||||
<menu action="ViewMenu">
|
||||
<menuitem action="Siblings"/>
|
||||
<menuitem action="Details"/>
|
||||
</menu>
|
||||
</menubar>
|
||||
<toolbar name="ToolBar">
|
||||
<placeholder name="CommonNavigation">
|
||||
<toolitem action="Back"/>
|
||||
<toolitem action="Forward"/>
|
||||
<toolitem action="HomePerson"/>
|
||||
</placeholder>
|
||||
</toolbar>
|
||||
<popup name="Popup">
|
||||
<menuitem action="Back"/>
|
||||
<menuitem action="Forward"/>
|
||||
<menuitem action="HomePerson"/>
|
||||
<separator/>
|
||||
</popup>
|
||||
</ui>'''
|
||||
|
||||
def define_actions(self):
|
||||
PageView.PersonNavView.define_actions(self)
|
||||
|
||||
self.add_toggle_action('Details', None, _('Show details'),
|
||||
None, None, self.details_toggle,
|
||||
self.show_details)
|
||||
self.add_toggle_action('Siblings', None, _('Show siblings'),
|
||||
None, None, self.siblings_toggle,
|
||||
self.show_siblings)
|
||||
|
||||
def siblings_toggle(self,obj):
|
||||
self.show_siblings = obj.get_active()
|
||||
self.change_person(self.dbstate.active.handle)
|
||||
Config.save_family_siblings(self.show_siblings)
|
||||
|
||||
def details_toggle(self,obj):
|
||||
self.show_details = obj.get_active()
|
||||
self.change_person(self.dbstate.active.handle)
|
||||
Config.save_family_details(self.show_details)
|
||||
|
||||
def change_db(self,db):
|
||||
if self.child:
|
||||
self.vbox.remove(self.child)
|
||||
self.child = None
|
||||
|
||||
def get_name(self,handle,use_gender=False):
|
||||
if handle:
|
||||
p = self.dbstate.db.get_person_from_handle(handle)
|
||||
name = NameDisplay.displayer.display(p)
|
||||
if use_gender:
|
||||
gender = _GenderCode[p.gender]
|
||||
else:
|
||||
gender = ""
|
||||
return (name,gender)
|
||||
else:
|
||||
return (_(u"Unknown"),"")
|
||||
|
||||
def change_person(self,obj):
|
||||
if self.child:
|
||||
self.vbox.remove(self.child)
|
||||
self.attach = AttachList()
|
||||
|
||||
person = self.dbstate.db.get_person_from_handle(obj)
|
||||
if not person:
|
||||
return
|
||||
|
||||
self.row = 5
|
||||
family_handle_list = person.get_parent_family_handle_list()
|
||||
if family_handle_list:
|
||||
for (family_handle,mrel,frel) in family_handle_list:
|
||||
if family_handle:
|
||||
self.write_parents(family_handle)
|
||||
else:
|
||||
self.write_label("%s:" % _('Parents'),None)
|
||||
self.row += 1
|
||||
|
||||
family_handle_list = person.get_family_handle_list()
|
||||
if family_handle_list:
|
||||
for family_handle in family_handle_list:
|
||||
if family_handle:
|
||||
self.write_family(family_handle)
|
||||
else:
|
||||
self.write_label("%s:" % _('Family'),None)
|
||||
self.row += 1
|
||||
|
||||
self.row = 1
|
||||
self.write_title(person)
|
||||
|
||||
# Here it is necessary to beat GTK into submission. For some
|
||||
# bizzare reason, if you have an empty column that is spanned,
|
||||
# you lose the appropriate FILL handling. So, we need to see if
|
||||
# column 3 is unused (usually if there is no siblings or children.
|
||||
# If so, we need to subtract one index of each x coord > 3.
|
||||
|
||||
found = False
|
||||
for d in self.attach.list:
|
||||
if d[1] == 4 or d[2] == 4:
|
||||
found = True
|
||||
|
||||
if found:
|
||||
cols = self.attach.max_x
|
||||
else:
|
||||
cols = self.attach.max_x-1
|
||||
|
||||
self.child = gtk.Table(self.attach.max_y,cols)
|
||||
self.child.set_border_width(12)
|
||||
self.child.set_col_spacings(12)
|
||||
self.child.set_row_spacings(6)
|
||||
|
||||
for d in self.attach.list:
|
||||
x0 = d[1]
|
||||
x1 = d[2]
|
||||
if not found:
|
||||
if x0 > 4:
|
||||
x0 -= 1
|
||||
if x1 > 4:
|
||||
x1 -= 1
|
||||
self.child.attach(d[0],x0,x1,d[3],d[4],d[5],d[6])
|
||||
|
||||
self.child.show_all()
|
||||
self.vbox.pack_start(self.child,False)
|
||||
|
||||
def write_title(self,person):
|
||||
|
||||
# name and edit button
|
||||
name = NameDisplay.displayer.display(person)
|
||||
text = '<span size="larger" weight="bold">%s %s</span>' % (cgi.escape(name),
|
||||
_GenderCode[person.gender])
|
||||
label = GrampsWidgets.MarkupLabel(text)
|
||||
button = GrampsWidgets.IconButton(self.edit_button_press,person.handle)
|
||||
|
||||
hbox = GrampsWidgets.LinkBox(label,button)
|
||||
|
||||
# GRAMPS ID
|
||||
self.row = 1
|
||||
|
||||
self.write_person_data("%s:" % _('ID'),person.gramps_id)
|
||||
|
||||
# birth/death events
|
||||
|
||||
birth_ref = person.get_birth_ref()
|
||||
if birth_ref:
|
||||
birth = self.dbstate.db.get_event_from_handle(birth_ref.ref)
|
||||
else:
|
||||
birth = None
|
||||
self.write_person_event("%s:" % _('Birth'),birth)
|
||||
|
||||
death_ref = person.get_death_ref()
|
||||
if death_ref:
|
||||
death = self.dbstate.db.get_event_from_handle(death_ref.ref)
|
||||
else:
|
||||
death = None
|
||||
self.write_person_event("%s:" % _('Death'),death)
|
||||
|
||||
# separator
|
||||
end = self.attach.max_x
|
||||
sep = gtk.HSeparator()
|
||||
sep.show()
|
||||
self.attach.attach(hbox,_NAME_START,end,0,1,gtk.FILL|gtk.EXPAND)
|
||||
|
||||
# image
|
||||
image_list = person.get_media_list()
|
||||
if image_list:
|
||||
mobj = self.dbstate.db.get_object_from_handle(image_list[0].ref)
|
||||
if mobj.get_mime_type()[0:5] == "image":
|
||||
pixbuf = ImgManip.get_thumbnail_image(mobj.get_path())
|
||||
image = gtk.Image()
|
||||
image.set_from_pixbuf(pixbuf)
|
||||
image.show()
|
||||
self.attach.attach(image,end,end+1,0,4,xoptions=gtk.SHRINK|gtk.FILL)
|
||||
|
||||
self.attach.attach(sep,0,self.attach.max_x,4,5)
|
||||
|
||||
def write_person_event(self, ename, event):
|
||||
if event:
|
||||
dobj = event.get_date_object()
|
||||
phandle = event.get_place_handle()
|
||||
if phandle:
|
||||
pname = self.place_name(phandle)
|
||||
else:
|
||||
pname = None
|
||||
date_str = DateHandler.displayer.display(dobj)
|
||||
|
||||
value = {
|
||||
'date' : DateHandler.displayer.display(dobj),
|
||||
'place' : pname,
|
||||
}
|
||||
else:
|
||||
pname = None
|
||||
dobj = None
|
||||
|
||||
if dobj:
|
||||
if pname:
|
||||
self.write_person_data(ename,
|
||||
_('%(date)s in %(place)s') % value)
|
||||
else:
|
||||
self.write_person_data(ename,'%(date)s' % value)
|
||||
elif pname:
|
||||
self.write_person_data(ename,pname)
|
||||
else:
|
||||
self.write_person_data(ename,'')
|
||||
|
||||
def write_person_data(self,title,data):
|
||||
self.attach.attach(GrampsWidgets.BasicLabel(title),_ALABEL_START,
|
||||
_ALABEL_STOP,self.row,self.row+1,
|
||||
xoptions=gtk.FILL|gtk.SHRINK)
|
||||
self.attach.attach(GrampsWidgets.BasicLabel(data),_ADATA_START,_ADATA_STOP,
|
||||
self.row,self.row+1)
|
||||
self.row += 1
|
||||
|
||||
def write_label(self,title,family):
|
||||
msg = "<i><b>%s</b></i>" % cgi.escape(title)
|
||||
self.attach.attach(GrampsWidgets.MarkupLabel(msg),_LABEL_START,_LABEL_STOP,
|
||||
self.row,self.row+1,gtk.SHRINK|gtk.FILL)
|
||||
|
||||
if family:
|
||||
value = family.gramps_id
|
||||
else:
|
||||
value = ""
|
||||
self.attach.attach(GrampsWidgets.BasicLabel(value),_DATA_START,_DATA_STOP,
|
||||
self.row,self.row+1,gtk.SHRINK|gtk.FILL)
|
||||
|
||||
hbox = gtk.HBox()
|
||||
hbox.set_spacing(6)
|
||||
add = GrampsWidgets.IconButton(self.add_family,None,gtk.STOCK_ADD)
|
||||
hbox.pack_start(add,False)
|
||||
if family:
|
||||
edit = GrampsWidgets.IconButton(self.edit_family,family.handle,gtk.STOCK_EDIT)
|
||||
hbox.pack_start(edit,False)
|
||||
delete = GrampsWidgets.IconButton(self.delete_family,family.handle,gtk.STOCK_REMOVE)
|
||||
hbox.pack_start(delete,False)
|
||||
self.attach.attach(hbox,_BTN_START,_BTN_STOP,self.row,self.row+1)
|
||||
self.row += 1
|
||||
|
||||
######################################################################
|
||||
|
||||
def write_parents(self,family_handle):
|
||||
family = self.dbstate.db.get_family_from_handle(family_handle)
|
||||
self.write_label("%s:" % _('Parents'),family),
|
||||
self.write_person(_('Father'),family.get_father_handle())
|
||||
if self.show_details:
|
||||
value = self.info_string(family.get_father_handle())
|
||||
if value:
|
||||
self.attach.attach(GrampsWidgets.BasicLabel(value),_PDTLS_START,
|
||||
_PDTLS_STOP,self.row, self.row+1)
|
||||
self.row += 1
|
||||
self.write_person(_('Mother'),family.get_mother_handle())
|
||||
if self.show_details:
|
||||
value = self.info_string(family.get_mother_handle())
|
||||
if value:
|
||||
self.attach.attach(GrampsWidgets.BasicLabel(value),_PDTLS_START,
|
||||
_PDTLS_STOP, self.row, self.row+1)
|
||||
self.row += 1
|
||||
|
||||
if self.show_siblings:
|
||||
active = self.dbstate.active.handle
|
||||
|
||||
child_list = [handle for handle in family.get_child_handle_list()\
|
||||
if handle != active]
|
||||
label = _("Siblings")
|
||||
if child_list:
|
||||
for child in child_list:
|
||||
self.write_child(label,child)
|
||||
label = u""
|
||||
self.row += 1
|
||||
|
||||
def write_person(self,title,handle):
|
||||
if title:
|
||||
format = '<span weight="bold">%s: </span>'
|
||||
else:
|
||||
format = "%s"
|
||||
|
||||
label = GrampsWidgets.MarkupLabel(format % cgi.escape(title))
|
||||
self.attach.attach(label,_PLABEL_START,_PLABEL_STOP,self.row,self.row+1,
|
||||
xoptions=gtk.FILL|gtk.SHRINK)
|
||||
|
||||
link_label = GrampsWidgets.LinkLabel(self.get_name(handle,True),
|
||||
self.button_press,handle)
|
||||
button = GrampsWidgets.IconButton(self.edit_button_press,handle)
|
||||
self.attach.attach(GrampsWidgets.LinkBox(link_label,button),_PDATA_START,
|
||||
_PDATA_STOP,self.row,self.row+1)
|
||||
self.row += 1
|
||||
|
||||
def write_child(self,title,handle):
|
||||
if title:
|
||||
format = '<span weight="bold">%s: </span>'
|
||||
else:
|
||||
format = "%s"
|
||||
|
||||
label = GrampsWidgets.MarkupLabel(format % cgi.escape(title))
|
||||
self.attach.attach(label,_CLABEL_START,_CLABEL_STOP,self.row,self.row+1,
|
||||
xoptions=gtk.FILL|gtk.SHRINK)
|
||||
|
||||
link_label = GrampsWidgets.LinkLabel(self.get_name(handle,True),
|
||||
self.button_press,handle)
|
||||
button = GrampsWidgets.IconButton(self.edit_button_press,handle)
|
||||
self.attach.attach(GrampsWidgets.LinkBox(link_label,button),_CDATA_START,
|
||||
_CDATA_STOP,self.row,self.row+1,
|
||||
xoptions=gtk.EXPAND|gtk.FILL)
|
||||
|
||||
self.row += 1
|
||||
|
||||
if self.show_details:
|
||||
value = self.info_string(handle)
|
||||
if value:
|
||||
self.attach.attach(GrampsWidgets.BasicLabel(value),_CDTLS_START,
|
||||
_CDTLS_STOP,self.row, self.row+1)
|
||||
self.row += 1
|
||||
|
||||
def write_data(self,title,start_col=_SDATA_START,stop_col=_SDATA_STOP):
|
||||
self.attach.attach(GrampsWidgets.BasicLabel(title),start_col,stop_col,
|
||||
self.row, self.row+1, xoptions=gtk.EXPAND|gtk.FILL)
|
||||
self.row += 1
|
||||
|
||||
def info_string(self,handle):
|
||||
child = self.dbstate.db.get_person_from_handle(handle)
|
||||
if not child:
|
||||
return None
|
||||
birth_ref = child.get_birth_ref()
|
||||
death_ref = child.get_death_ref()
|
||||
value = None
|
||||
if birth_ref or death_ref:
|
||||
info = ReportUtils.get_birth_death_strings(self.dbstate.db,child)
|
||||
bdate = info[0]
|
||||
ddate = info[4]
|
||||
if bdate and ddate:
|
||||
value = _("b. %s, d. %s") % (bdate,ddate)
|
||||
elif bdate:
|
||||
value = _("b. %s") % (bdate)
|
||||
elif ddate:
|
||||
value = _("d. %s") % (ddate)
|
||||
return value
|
||||
|
||||
def button_press(self,obj,event,handle):
|
||||
if event.type == gtk.gdk.BUTTON_PRESS and event.button == 1:
|
||||
self.dbstate.change_active_handle(handle)
|
||||
|
||||
def write_relationship(self,family):
|
||||
rtype = family.get_relationship()
|
||||
if type(rtype) == tuple:
|
||||
if rtype[0] == RelLib.Family.CUSTOM:
|
||||
rel_text = rtype[1]
|
||||
else:
|
||||
rel_text = Utils.family_relations[rtype[0]]
|
||||
else:
|
||||
rel_text = Utils.family_relations[rtype]
|
||||
self.write_data(_('Relationship type: %s') % rel_text)
|
||||
|
||||
def place_name(self,handle):
|
||||
p = self.dbstate.db.get_place_from_handle(handle)
|
||||
return p.get_title()
|
||||
|
||||
def write_marriage(self,family):
|
||||
value = False
|
||||
for event_ref in family.get_event_ref_list():
|
||||
handle = event_ref.ref
|
||||
event = self.dbstate.db.get_event_from_handle(handle)
|
||||
etype = event.get_type()
|
||||
if etype[0] == RelLib.Event.MARRIAGE:
|
||||
self.write_event_ref(_('Marriage'),event)
|
||||
value = True
|
||||
return value
|
||||
|
||||
def write_event_ref(self, ename, event,start_col=_SDATA_START,stop_col=_SDATA_STOP):
|
||||
if event:
|
||||
dobj = event.get_date_object()
|
||||
phandle = event.get_place_handle()
|
||||
if phandle:
|
||||
pname = self.place_name(phandle)
|
||||
else:
|
||||
pname = None
|
||||
date_str = DateHandler.displayer.display(dobj)
|
||||
|
||||
value = {
|
||||
'date' : DateHandler.displayer.display(dobj),
|
||||
'place' : pname,
|
||||
'event_type' : ename,
|
||||
}
|
||||
else:
|
||||
pname = None
|
||||
dobj = None
|
||||
value = {
|
||||
'event_type' : ename,
|
||||
}
|
||||
|
||||
if dobj:
|
||||
if pname:
|
||||
self.write_data(_('%(event_type)s: %(date)s in %(place)s') %
|
||||
value,start_col,stop_col)
|
||||
else:
|
||||
self.write_data(_('%(event_type)s: %(date)s') % value,
|
||||
start_col, stop_col)
|
||||
elif pname:
|
||||
self.write_data(_('%(event_type)s: %(place)s') % value,
|
||||
start_col,stop_col)
|
||||
else:
|
||||
self.write_data(_('%(event_type)s:') % value,
|
||||
start_col, stop_col)
|
||||
|
||||
def write_family(self,family_handle):
|
||||
family = self.dbstate.db.get_family_from_handle(family_handle)
|
||||
father_handle = family.get_father_handle()
|
||||
mother_handle = family.get_mother_handle()
|
||||
if self.dbstate.active.handle == father_handle:
|
||||
handle = mother_handle
|
||||
else:
|
||||
handle = father_handle
|
||||
|
||||
self.write_label("%s:" % _('Family'),family),
|
||||
if handle:
|
||||
self.write_person(_('Spouse'),handle)
|
||||
|
||||
value = self.info_string(handle)
|
||||
if value:
|
||||
self.attach.attach(GrampsWidgets.BasicLabel(value),_PDTLS_START,
|
||||
_PDTLS_STOP,self.row, self.row+1)
|
||||
self.row += 1
|
||||
if not self.write_marriage(family):
|
||||
self.write_relationship(family)
|
||||
|
||||
child_list = family.get_child_handle_list()
|
||||
label = _("Children")
|
||||
if child_list:
|
||||
for child in child_list:
|
||||
self.write_child(label,child)
|
||||
label = u""
|
||||
|
||||
self.row += 1
|
||||
|
||||
def edit_button_press(self, obj, event, handle):
|
||||
if event.type == gtk.gdk.BUTTON_PRESS and event.button == 1:
|
||||
from Editors import EditPerson
|
||||
person = self.dbstate.db.get_person_from_handle(handle)
|
||||
try:
|
||||
EditPerson(self.dbstate, self.uistate, [], person)
|
||||
except Errors.WindowActiveError:
|
||||
pass
|
||||
|
||||
def edit_person(self,obj,handle):
|
||||
from Editors import EditPerson
|
||||
person = self.dbstate.db.get_person_from_handle(handle)
|
||||
try:
|
||||
EditPerson(self.dbstate, self.uistate, [], person)
|
||||
except Errors.WindowActiveError:
|
||||
pass
|
||||
|
||||
def edit_family(self,obj,event,handle):
|
||||
if event.type == gtk.gdk.BUTTON_PRESS and event.button == 1:
|
||||
from Editors import EditFamily
|
||||
family = self.dbstate.db.get_family_from_handle(handle)
|
||||
try:
|
||||
EditFamily(self.dbstate,self.uistate,[],family)
|
||||
except Errors.WindowActiveError:
|
||||
pass
|
||||
|
||||
def add_family(self,obj,event,handle):
|
||||
if event.type == gtk.gdk.BUTTON_PRESS and event.button == 1:
|
||||
from Editors import EditFamily
|
||||
family = RelLib.Family()
|
||||
try:
|
||||
EditFamily(self.dbstate,self.uistate,[],family)
|
||||
except Errors.WindowActiveError:
|
||||
pass
|
||||
|
||||
def delete_family(self,obj,event,handle):
|
||||
if event.type == gtk.gdk.BUTTON_PRESS and event.button == 1:
|
||||
print "Delete Family",handle
|
||||
|
||||
def change_to(self,obj,handle):
|
||||
self.dbstate.change_active_handle(handle)
|
28
src/DataViews/Makefile.am
Normal file
28
src/DataViews/Makefile.am
Normal file
@@ -0,0 +1,28 @@
|
||||
# This is the src/DataViews level Makefile for Gramps
|
||||
# We could use GNU make's ':=' syntax for nice wildcard use,
|
||||
# but that is not necessarily portable.
|
||||
# If not using GNU make, then list all .py files individually
|
||||
|
||||
pkgdatadir = $(datadir)/@PACKAGE@/DataViews
|
||||
|
||||
pkgdata_PYTHON = \
|
||||
__init__.py\
|
||||
PersonView.py\
|
||||
FamilyView.py\
|
||||
FamilyList.py\
|
||||
PedView.py\
|
||||
EventView.py\
|
||||
SourceView.py\
|
||||
PlaceView.py\
|
||||
MediaView.py\
|
||||
MapView.py\
|
||||
RepositoryView.py
|
||||
|
||||
pkgpyexecdir = @pkgpyexecdir@/DataViews
|
||||
pkgpythondir = @pkgpythondir@/DataViews
|
||||
|
||||
GRAMPS_PY_MODPATH = "../"
|
||||
|
||||
pycheck:
|
||||
(export PYTHONPATH=$(GRAMPS_PY_MODPATH); \
|
||||
pychecker $(pkgdata_PYTHON));
|
486
src/DataViews/MapView.py
Normal file
486
src/DataViews/MapView.py
Normal file
@@ -0,0 +1,486 @@
|
||||
#
|
||||
# Gramps - a GTK+/GNOME based genealogy program
|
||||
#
|
||||
# Copyright (C) 2001-2006 Donald N. Allingham
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 2 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
#
|
||||
|
||||
# $Id$
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
#
|
||||
# Python modules
|
||||
#
|
||||
#-------------------------------------------------------------------------
|
||||
from gettext import gettext as _
|
||||
import gc
|
||||
import re
|
||||
import logging
|
||||
import os
|
||||
|
||||
log = logging.getLogger(".")
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
#
|
||||
# GTK/Gnome modules
|
||||
#
|
||||
#-------------------------------------------------------------------------
|
||||
import gobject
|
||||
import gtk
|
||||
import gtk.gdk
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
#
|
||||
# Gramps Modules
|
||||
#
|
||||
#-------------------------------------------------------------------------
|
||||
import RelLib
|
||||
import PageView
|
||||
import const
|
||||
|
||||
glob_loc_data = [ # (Name, longitude, latitude)
|
||||
("_Center", 0,0),
|
||||
("_North",0,90),
|
||||
("_South",0,-90),
|
||||
("_West",-180,0),
|
||||
("_East",180,0),
|
||||
("Chicago",-87.75,41.83),
|
||||
("Berlin",13.42,52.53),
|
||||
("Honolulu",-157.83,21.32),
|
||||
("Madrid",-3.72,40.42),
|
||||
("Moscow",37.70,55.75),
|
||||
("Vienna",16.37,48.22),
|
||||
("Sidney",151.17,-33.92),
|
||||
("Rio de Janeiro",-43.28,-22.88),
|
||||
("Tokyo",139.75,35.67),
|
||||
("Cape Town",18.47,-33.93),
|
||||
("Anchorage",-150.00,61.17)]
|
||||
|
||||
|
||||
# Draws a map image and tries to allocate space in the correct aspect ratio
|
||||
class GuideMap(gtk.DrawingArea):
|
||||
def __init__(self, map_pixbuf):
|
||||
gtk.DrawingArea.__init__(self)
|
||||
self.map_pixbuf = map_pixbuf
|
||||
self.connect("expose-event", self.expose_cb)
|
||||
self.connect("size-allocate", self.size_allocate_cb)
|
||||
self.gc = None
|
||||
self.current_area = None
|
||||
self.old_size = (-1,-1)
|
||||
|
||||
# Set hightlight region
|
||||
def hightlight_area( self, area):
|
||||
self.current_area = area
|
||||
self.queue_draw()
|
||||
|
||||
# Redraw the image
|
||||
def expose_cb(self,widget,event):
|
||||
if not self.gc:
|
||||
self.gc = self.window.new_gc()
|
||||
self.gc.set_foreground( self.get_colormap().alloc_color("red"))
|
||||
self.gc.set_background( self.get_colormap().alloc_color("blue"))
|
||||
if self.backbuf and self.gc:
|
||||
self.window.draw_pixbuf( self.gc, self.backbuf, 0,0, 0,0, -1,-1)
|
||||
if self.current_area:
|
||||
r = self.map_to_screen(self.current_area[0],
|
||||
self.current_area[1],
|
||||
self.current_area[2],
|
||||
self.current_area[3])
|
||||
self.window.draw_rectangle( self.gc, False,
|
||||
r[0],r[1],r[2],r[3])
|
||||
|
||||
# Scale backbuffer
|
||||
def size_allocate_cb(self,widget,allocation):
|
||||
# Always request a height, that is half of the width
|
||||
w = max( 128,allocation.width)
|
||||
self.set_size_request(-1,w/2)
|
||||
|
||||
# only create new backbuffer if size is different
|
||||
new_size = (allocation.width,allocation.height)
|
||||
if new_size is not self.old_size:
|
||||
self.old_size = new_size
|
||||
self.backbuf = self.map_pixbuf.scale_simple(
|
||||
self.old_size[0],
|
||||
self.old_size[1],
|
||||
gtk.gdk.INTERP_BILINEAR)
|
||||
gc.collect()
|
||||
|
||||
def map_to_screen( self, x,y,w,h):
|
||||
px = int((float(x) + 180.0) / 360.0 * self.backbuf.get_width())
|
||||
py = int((90-float(y)) / 180.0 * self.backbuf.get_height())
|
||||
pw = int(float(w) / 360.0 * self.backbuf.get_width())
|
||||
ph = int(float(h) / 180.0 * self.backbuf.get_height())
|
||||
|
||||
return (px,py,pw,ph)
|
||||
|
||||
# Zoomable map image
|
||||
class ZoomMap( gtk.DrawingArea):
|
||||
def __init__(self, map_pixbuf, place_marker_pixbuf,
|
||||
hightlight_marker_pixbuf):
|
||||
gtk.DrawingArea.__init__(self)
|
||||
self.map_pixbuf = map_pixbuf
|
||||
self.place_marker_pixbuf = place_marker_pixbuf
|
||||
self.hightlight_marker_pixbuf = hightlight_marker_pixbuf
|
||||
self.connect("expose-event", self.expose_cb)
|
||||
self.connect("size-allocate", self.size_allocate_cb)
|
||||
self.gc = None
|
||||
self.old_size = (-1,-1)
|
||||
self.zoom_pos = (0,0)
|
||||
self.current_area = (0,0,0,0)
|
||||
self.magnifer = 0.5
|
||||
self.guide = None
|
||||
self.textlayout = self.create_pango_layout("")
|
||||
|
||||
# Set the guide map that should follow the zoom area
|
||||
def set_guide( self, guide):
|
||||
self.guide = guide
|
||||
|
||||
def set_location_model( self, model, idx_name, idx_long, idx_lat):
|
||||
self.location_model = model
|
||||
self.idx_name = idx_name
|
||||
self.idx_long = idx_long
|
||||
self.idx_lat = idx_lat
|
||||
|
||||
# Redraw the image
|
||||
def expose_cb(self,widget,event):
|
||||
if not self.gc:
|
||||
self.gc = self.window.new_gc()
|
||||
self.gc.set_foreground( self.get_colormap().alloc_color("red"))
|
||||
self.gc.set_background( self.get_colormap().alloc_color("blue"))
|
||||
if not self.backbuf:
|
||||
self.size_allocate_cb( self,self.get_allocation())
|
||||
if self.backbuf and self.gc:
|
||||
self.window.draw_pixbuf( self.gc, self.backbuf, 0,0, 0,0, -1,-1)
|
||||
|
||||
# draw all available locations
|
||||
if self.location_model:
|
||||
iter = self.location_model.get_iter_first()
|
||||
while iter:
|
||||
(n,x,y) = self.location_model.get( iter, self.idx_name, self.idx_long, self.idx_lat)
|
||||
(px,py) = self.map_to_screen( x, y)
|
||||
if px > 0 and py > 0 and px < self.backbuf.get_width() and py < self.backbuf.get_height():
|
||||
# draw only visible markers
|
||||
#self.window.draw_pixbuf(
|
||||
# self.gc,
|
||||
# self.place_marker_pixbuf,
|
||||
# 0,0,
|
||||
# px-self.place_marker_pixbuf.get_width()/2,
|
||||
# py-self.place_marker_pixbuf.get_height()/2,
|
||||
# -1,-1)
|
||||
self.textlayout.set_text(n)
|
||||
self.window.draw_layout(
|
||||
self.gc,
|
||||
px,py,
|
||||
self.textlayout)
|
||||
iter = self.location_model.iter_next( iter)
|
||||
|
||||
# hightlight current location
|
||||
(px,py) = self.map_to_screen( self.zoom_pos[0], self.zoom_pos[1])
|
||||
self.window.draw_pixbuf(
|
||||
self.gc,
|
||||
self.hightlight_marker_pixbuf,
|
||||
0,0,
|
||||
px-self.hightlight_marker_pixbuf.get_width()/2,
|
||||
py-self.hightlight_marker_pixbuf.get_height()/2,
|
||||
-1,-1)
|
||||
#self.window.draw_rectangle( self.gc, False, px-3,py-3, 6,6)
|
||||
|
||||
def map_to_screen( self, long, lat):
|
||||
px = int(self.backbuf.get_width() / self.current_map_area[2] *
|
||||
(float(long) - self.current_map_area[0]))
|
||||
py = int(self.backbuf.get_height() / self.current_map_area[3] *
|
||||
(-float(lat) + self.current_map_area[1]))
|
||||
return( px, py)
|
||||
|
||||
# Scale backbuffer
|
||||
def size_allocate_cb(self,widget,allocation):
|
||||
# only create new backbuffer if size is different
|
||||
new_size = (allocation.width,allocation.height)
|
||||
if new_size is not self.old_size or not self.backbuf:
|
||||
self.old_size = new_size
|
||||
|
||||
# Desired midpoint in map
|
||||
pw = int(self.old_size[0]*self.magnifer)
|
||||
ph = int(self.old_size[1]*self.magnifer)
|
||||
|
||||
px = int((float(self.zoom_pos[0]) + 180.0) / 360.0
|
||||
* self.map_pixbuf.get_width())
|
||||
py = int((90-float(self.zoom_pos[1])) / 180.0
|
||||
* self.map_pixbuf.get_height())
|
||||
|
||||
px = max( pw/2, px)
|
||||
py = max( ph/2, py)
|
||||
|
||||
px = min( px, self.map_pixbuf.get_width()-1-pw/2)
|
||||
py = min( py, self.map_pixbuf.get_height()-1-ph/2)
|
||||
|
||||
zoomebuf = self.map_pixbuf.subpixbuf( max(0,int(px-pw/2)),max(0,int(py-ph/2)),
|
||||
min(self.map_pixbuf.get_width(),pw),
|
||||
min(self.map_pixbuf.get_height(),ph))
|
||||
self.backbuf = zoomebuf.scale_simple(self.old_size[0],
|
||||
self.old_size[1],
|
||||
gtk.gdk.INTERP_BILINEAR)
|
||||
gc.collect()
|
||||
mx = 360.0 / self.map_pixbuf.get_width() * (px-pw/2.0) - 180.0
|
||||
my = 90.0 - 180.0 / self.map_pixbuf.get_height() * (py-ph/2.0)
|
||||
mw = 360.0 / self.map_pixbuf.get_width() * pw
|
||||
mh = 180.0 / self.map_pixbuf.get_height() * ph
|
||||
self.current_area = (px-pw/2, py-ph/2, pw,ph)
|
||||
self.current_map_area = (mx, my, mw, mh)
|
||||
if self.guide:
|
||||
self.guide.hightlight_area( (mx,my,mw,mh))
|
||||
|
||||
# Scroll to requested position
|
||||
def scroll_to( self, long, lat):
|
||||
self.zoom_pos = ( min(180,(max(-180,long))), min(90,(max(-90,lat))))
|
||||
self.backbuf = None
|
||||
self.queue_draw()
|
||||
|
||||
def zoom_out(self):
|
||||
self.magnifer = min( 10, self.magnifer * 1.5)
|
||||
self.backbuf = None
|
||||
self.queue_draw()
|
||||
|
||||
def zoom_in(self):
|
||||
self.magnifer = max( 0.1, self.magnifer * 0.75)
|
||||
self.backbuf = None
|
||||
self.queue_draw()
|
||||
|
||||
def zoom_normal(self):
|
||||
self.magnifer = 1
|
||||
self.backbuf = None
|
||||
self.queue_draw()
|
||||
|
||||
def zoom_fit(self):
|
||||
self.magnifer = 2
|
||||
self.backbuf = None
|
||||
self.queue_draw()
|
||||
|
||||
|
||||
# Place list widget
|
||||
class MapPlacesList(gtk.TreeView):
|
||||
def __init__(self, data):
|
||||
self.lstore = gtk.ListStore(
|
||||
gobject.TYPE_STRING,
|
||||
gobject.TYPE_FLOAT,
|
||||
gobject.TYPE_FLOAT)
|
||||
|
||||
self.change_data( data)
|
||||
|
||||
gtk.TreeView.__init__(self, self.lstore)
|
||||
self.set_rules_hint(True)
|
||||
self.set_search_column(0)
|
||||
|
||||
column = gtk.TreeViewColumn('Place', gtk.CellRendererText(), text=0)
|
||||
column.set_sort_column_id(0)
|
||||
self.append_column(column)
|
||||
|
||||
column = gtk.TreeViewColumn('Lat', gtk.CellRendererText(), text=1)
|
||||
column.set_sort_column_id(1)
|
||||
self.append_column(column)
|
||||
|
||||
column = gtk.TreeViewColumn('Long', gtk.CellRendererText(),text=2)
|
||||
column.set_sort_column_id(2)
|
||||
self.append_column(column)
|
||||
|
||||
def change_data( self, data):
|
||||
self.lstore.clear()
|
||||
for item in data:
|
||||
iter = self.lstore.append()
|
||||
self.lstore.set(iter,
|
||||
0, item[0],
|
||||
1, item[1],
|
||||
2, item[2])
|
||||
|
||||
|
||||
|
||||
# Map View main class
|
||||
class MapView(PageView.PageView):
|
||||
def __init__(self,dbstate,uistate):
|
||||
PageView.PageView.__init__(self,'Map View',dbstate,uistate)
|
||||
dbstate.connect('database-changed',self.change_db)
|
||||
self.current_marker = None
|
||||
|
||||
def navigation_type(self):
|
||||
return PageView.NAVIGATION_NONE
|
||||
|
||||
def define_actions(self):
|
||||
self.add_action('ZoomIn',gtk.STOCK_ZOOM_IN,
|
||||
"Zoom _In",callback=self.zoom_in_cb)
|
||||
self.add_action('ZoomOut',gtk.STOCK_ZOOM_OUT,
|
||||
"Zoom _Out",callback=self.zoom_out_cb)
|
||||
self.add_action('ZoomNormal',gtk.STOCK_ZOOM_100,
|
||||
"_Normal Size", callback=self.zoom_100_cb)
|
||||
self.add_action('ZoomFit',gtk.STOCK_ZOOM_FIT,
|
||||
"Best _Fit",callback=self.zoom_fit_cb)
|
||||
|
||||
def get_stock(self):
|
||||
"""
|
||||
Returns the name of the stock icon to use for the display.
|
||||
This assumes that this icon has already been registered with
|
||||
GNOME as a stock icon.
|
||||
"""
|
||||
return 'gramps-map'
|
||||
|
||||
|
||||
# For debugging: Reads in location from xearth
|
||||
def get_xearth_markers(self):
|
||||
data = []
|
||||
try:
|
||||
f = open("/etc/xearth/xearth.markers")
|
||||
l = f.readline()
|
||||
#linere = re.compile('[^0-9.-]*(-?[0-9]+\.[0-9]+)[^0-9.-]*(-?[0-9]+\.[0-9]+).*"([^"])".*', "I")
|
||||
while l:
|
||||
if not l[0] == "#":
|
||||
l = l.strip().replace('"',"").replace(" "," ").replace(" "," ").replace(" "," ").replace(" # ",", ")
|
||||
m = l.split( None, 2)
|
||||
if len(m) == 3:
|
||||
data.append( (m[2],float(m[1]),float(m[0])))
|
||||
l = f.readline()
|
||||
except IOError:
|
||||
pass
|
||||
return data
|
||||
|
||||
# Reads in locations from current GRAMPS database
|
||||
def get_markers_from_database(self, db):
|
||||
data = []
|
||||
for place_handle in db.get_place_handles():
|
||||
place = db.get_place_from_handle( place_handle)
|
||||
if place:
|
||||
try:
|
||||
data.append( (place.get_title(),float(place.get_longitude()),float(place.get_latitude())))
|
||||
except (TypeError, ValueError):
|
||||
# ignore places that dont have usable data
|
||||
pass
|
||||
return data
|
||||
|
||||
# Reads in textfiles from NIMA:
|
||||
# http://earth-info.nga.mil/gns/html/cntry_files.html
|
||||
def parse_nima_countryfile(self, filename):
|
||||
import csv
|
||||
data = []
|
||||
try:
|
||||
csvreader = csv.reader(open(filename), "excel-tab")
|
||||
l = csvreader.next() # skip header
|
||||
l = csvreader.next()
|
||||
line = 1
|
||||
while l:
|
||||
if l[17] == "N" and l[9] == "P":
|
||||
city = l[22]
|
||||
lat = float( l[3])
|
||||
lon = float( l[4])
|
||||
|
||||
if line % 10 == 0:
|
||||
data.append( (city, lon, lat))
|
||||
l = csvreader.next()
|
||||
line = line + 1
|
||||
except (IOError,StopIteration):
|
||||
pass
|
||||
return data
|
||||
|
||||
def build_widget(self):
|
||||
hbox = gtk.HBox( False, 4)
|
||||
hbox.set_border_width( 4)
|
||||
|
||||
no = gtk.Image()
|
||||
# The large zoomable map
|
||||
self.zoom_map = ZoomMap(
|
||||
gtk.gdk.pixbuf_new_from_file(os.path.join(const.image_dir,"land_shallow_topo_2048.jpg")),
|
||||
gtk.gdk.pixbuf_new_from_file(os.path.join(const.image_dir,"bad.png")),
|
||||
gtk.gdk.pixbuf_new_from_file(os.path.join(const.image_dir,"good.png")))
|
||||
self.zoom_map.set_size_request(300,300)
|
||||
hbox.pack_start( self.zoom_map, True, True, 0)
|
||||
|
||||
# On the right side
|
||||
vbox = gtk.VBox( False, 4)
|
||||
hbox.pack_start( vbox, False, False, 0)
|
||||
|
||||
# The small guide map
|
||||
self.guide_map = GuideMap(
|
||||
gtk.gdk.pixbuf_new_from_file(os.path.join(const.image_dir,"land_shallow_topo_350.jpg")))
|
||||
self.guide_map.set_size_request(128,64)
|
||||
vbox.pack_start( self.guide_map, False, True, 0)
|
||||
|
||||
self.zoom_map.set_guide(self.guide_map)
|
||||
|
||||
# and the place list
|
||||
self.place_list_view = MapPlacesList( [])
|
||||
self.zoom_map.set_location_model(self.place_list_view.get_model(), 0,1,2)
|
||||
self.place_list_view.connect("cursor-changed", self.entry_select_cb)
|
||||
self.place_list_view.set_size_request(128,-1)
|
||||
vport = gtk.ScrolledWindow()
|
||||
vbox.pack_start(vport,True,True,0)
|
||||
vport.add( self.place_list_view)
|
||||
|
||||
self.rebuild_places()
|
||||
|
||||
return hbox
|
||||
|
||||
def ui_definition(self):
|
||||
"""
|
||||
Specifies the UIManager XML code that defines the menus and buttons
|
||||
associated with the interface.
|
||||
"""
|
||||
return '''<ui>
|
||||
<toolbar name="ToolBar">
|
||||
<toolitem action="ZoomIn"/>
|
||||
<toolitem action="ZoomOut"/>
|
||||
<toolitem action="ZoomNormal"/>
|
||||
<toolitem action="ZoomFit"/>
|
||||
</toolbar>
|
||||
</ui>'''
|
||||
|
||||
def change_db(self,db):
|
||||
"""
|
||||
Callback associated with DbState. Whenenver the database
|
||||
changes, this task is called. In this case, we rebuild the
|
||||
columns, and connect signals to the connected database. Tere
|
||||
is no need to store the database, since we will get the value
|
||||
from self.state.db
|
||||
"""
|
||||
db.connect('place-rebuild',self.rebuild_places)
|
||||
db.connect('place-update',self.rebuild_places)
|
||||
|
||||
def rebuild_places(self,handle_list=None):
|
||||
d = glob_loc_data
|
||||
try:
|
||||
d = d + self.get_xearth_markers()
|
||||
#d = self.parse_nima_countryfile("/tmp/gm.txt")
|
||||
d = d + self.get_markers_from_database( self.dbstate.db)
|
||||
except:
|
||||
log.error("Failed to rebuild places.", exc_info=True)
|
||||
self.place_list_view.change_data( d)
|
||||
|
||||
def entry_select_cb(self,treeview):
|
||||
s = treeview.get_selection()
|
||||
(model,sel) = s.get_selected_rows()
|
||||
for path in sel:
|
||||
iter = model.get_iter(path)
|
||||
self.zoom_map.scroll_to(model.get_value(iter,1),
|
||||
model.get_value(iter,2))
|
||||
break
|
||||
|
||||
def zoom_in_cb(self,obj):
|
||||
self.zoom_map.zoom_in()
|
||||
|
||||
def zoom_out_cb(self,obj):
|
||||
self.zoom_map.zoom_out()
|
||||
|
||||
def zoom_100_cb(self,obj):
|
||||
self.zoom_map.zoom_normal()
|
||||
|
||||
def zoom_fit_cb(self,obj):
|
||||
self.zoom_map.zoom_fit()
|
227
src/DataViews/MediaView.py
Normal file
227
src/DataViews/MediaView.py
Normal file
@@ -0,0 +1,227 @@
|
||||
# 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$
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
#
|
||||
# GTK/Gnome modules
|
||||
#
|
||||
#-------------------------------------------------------------------------
|
||||
import gtk
|
||||
import gtk.gdk
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
#
|
||||
# gramps modules
|
||||
#
|
||||
#-------------------------------------------------------------------------
|
||||
import PageView
|
||||
import DisplayModels
|
||||
import ImgManip
|
||||
import const
|
||||
import Utils
|
||||
from QuestionDialog import QuestionDialog, ErrorDialog
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
#
|
||||
# internationalization
|
||||
#
|
||||
#-------------------------------------------------------------------------
|
||||
from gettext import gettext as _
|
||||
|
||||
column_names = [
|
||||
_('Title'),
|
||||
_('ID'),
|
||||
_('Type'),
|
||||
_('Path'),
|
||||
_('Last Changed'),
|
||||
_('Date'),
|
||||
]
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
#
|
||||
# MediaView
|
||||
#
|
||||
#-------------------------------------------------------------------------
|
||||
class MediaView(PageView.ListView):
|
||||
def __init__(self,dbstate,uistate):
|
||||
|
||||
signal_map = {
|
||||
'media-add' : self.row_add,
|
||||
'media-update' : self.row_update,
|
||||
'media-delete' : self.row_delete,
|
||||
'media-rebuild' : self.build_tree,
|
||||
}
|
||||
|
||||
PageView.ListView.__init__(self,'Media View',dbstate,uistate,
|
||||
column_names,len(column_names),
|
||||
DisplayModels.MediaModel,
|
||||
signal_map)
|
||||
|
||||
def column_order(self):
|
||||
return self.dbstate.db.get_media_column_order()
|
||||
|
||||
def get_stock(self):
|
||||
return 'gramps-media'
|
||||
|
||||
def build_widget(self):
|
||||
base = PageView.ListView.build_widget(self)
|
||||
vbox = gtk.VBox()
|
||||
vbox.set_border_width(4)
|
||||
vbox.set_spacing(4)
|
||||
|
||||
self.image = gtk.Image()
|
||||
self.image.set_size_request(int(const.thumbScale),
|
||||
int(const.thumbScale))
|
||||
# label = gtk.Label('<b>%s</b>' % _('Preview'))
|
||||
# label.set_use_markup(True)
|
||||
# frame = gtk.Frame()
|
||||
# frame.set_label_widget(label)
|
||||
# frame.add(self.image)
|
||||
vbox.pack_start(self.image,False)
|
||||
vbox.pack_start(base,True)
|
||||
|
||||
self.selection.connect('changed',self.row_change)
|
||||
return vbox
|
||||
|
||||
def row_change(self,obj):
|
||||
handle = self.first_selected()
|
||||
if not handle:
|
||||
return
|
||||
obj = self.dbstate.db.get_object_from_handle(handle)
|
||||
pix = ImgManip.get_thumbnail_image(obj.get_path())
|
||||
self.image.set_from_pixbuf(pix)
|
||||
|
||||
def ui_definition(self):
|
||||
return '''<ui>
|
||||
<menubar name="MenuBar">
|
||||
<menu action="EditMenu">
|
||||
<placeholder name="CommonEdit">
|
||||
<menuitem action="Add"/>
|
||||
<menuitem action="Edit"/>
|
||||
<menuitem action="Remove"/>
|
||||
</placeholder>
|
||||
</menu>
|
||||
</menubar>
|
||||
<toolbar name="ToolBar">
|
||||
<placeholder name="CommonEdit">
|
||||
<toolitem action="Add"/>
|
||||
<toolitem action="Edit"/>
|
||||
<toolitem action="Remove"/>
|
||||
</placeholder>
|
||||
</toolbar>
|
||||
<popup name="Popup">
|
||||
<menuitem action="Add"/>
|
||||
<menuitem action="Edit"/>
|
||||
<menuitem action="Remove"/>
|
||||
</popup>
|
||||
</ui>'''
|
||||
|
||||
def on_double_click(self,obj,event):
|
||||
handle = self.first_selected()
|
||||
if handle:
|
||||
place = self.dbstate.db.get_place_from_handle(handle)
|
||||
#EditPlace.EditPlace(place,self.dbstate, self.uistate)
|
||||
|
||||
def add(self,obj):
|
||||
"""Add a new media object to the media list"""
|
||||
import AddMedia
|
||||
am = AddMedia.AddMediaObject(self.dbstate.db)
|
||||
am.run()
|
||||
|
||||
def remove(self,obj):
|
||||
handle = self.first_selected()
|
||||
if not handle:
|
||||
return
|
||||
the_lists = Utils.get_media_referents(handle,self.dbstate.db)
|
||||
|
||||
ans = DeleteMediaQuery(handle,self.dbstate.db,the_lists)
|
||||
if filter(None,the_lists): # quick test for non-emptiness
|
||||
msg = _('This media object is currently being used. '
|
||||
'If you delete this object, it will be removed from '
|
||||
'the database and from all records that reference it.')
|
||||
else:
|
||||
msg = _('Deleting media object will remove it from the database.')
|
||||
|
||||
msg = "%s %s" % (msg,Utils.data_recover_msg)
|
||||
QuestionDialog(_('Delete Media Object?'),msg,
|
||||
_('_Delete Media Object'),ans.query_response)
|
||||
|
||||
def edit(self,obj):
|
||||
handle = self.first_selected()
|
||||
if not handle:
|
||||
return
|
||||
|
||||
obj = self.dbstate.db.get_object_from_handle(handle)
|
||||
from Editors import EditMedia
|
||||
EditMedia(self.dbstate,self.uistate, [], obj)
|
||||
|
||||
class DeleteMediaQuery:
|
||||
|
||||
def __init__(self,media_handle,db,the_lists):
|
||||
self.db = db
|
||||
self.media_handle = media_handle
|
||||
self.the_lists = the_lists
|
||||
|
||||
def query_response(self):
|
||||
trans = self.db.transaction_begin()
|
||||
self.db.disable_signals()
|
||||
|
||||
(person_list,family_list,event_list,
|
||||
place_list,source_list) = self.the_lists
|
||||
|
||||
for handle in person_list:
|
||||
person = self.db.get_person_from_handle(handle)
|
||||
new_list = [ photo for photo in person.get_media_list() \
|
||||
if photo.get_reference_handle() != self.media_handle ]
|
||||
person.set_media_list(new_list)
|
||||
self.db.commit_person(person,trans)
|
||||
|
||||
for handle in family_list:
|
||||
family = self.db.get_family_from_handle(handle)
|
||||
new_list = [ photo for photo in family.get_media_list() \
|
||||
if photo.get_reference_handle() != self.media_handle ]
|
||||
family.set_media_list(new_list)
|
||||
self.db.commit_family(family,trans)
|
||||
|
||||
for handle in event_list:
|
||||
event = self.db.get_event_from_handle(handle)
|
||||
new_list = [ photo for photo in event.get_media_list() \
|
||||
if photo.get_reference_handle() != self.media_handle ]
|
||||
event.set_media_list(new_list)
|
||||
self.db.commit_event(event,trans)
|
||||
|
||||
for handle in place_list:
|
||||
place = self.db.get_place_from_handle(handle)
|
||||
new_list = [ photo for photo in place.get_media_list() \
|
||||
if photo.get_reference_handle() != self.media_handle ]
|
||||
place.set_media_list(new_list)
|
||||
self.db.commit_place(place,trans)
|
||||
|
||||
for handle in source_list:
|
||||
source = self.db.get_source_from_handle(handle)
|
||||
new_list = [ photo for photo in source.get_media_list() \
|
||||
if photo.get_reference_handle() != self.media_handle ]
|
||||
source.set_media_list(new_list)
|
||||
self.db.commit_source(source,trans)
|
||||
|
||||
self.db.enable_signals()
|
||||
self.db.remove_object(self.media_handle,trans)
|
||||
self.db.transaction_commit(trans,_("Remove Media Object"))
|
1493
src/DataViews/PedView.py
Normal file
1493
src/DataViews/PedView.py
Normal file
File diff suppressed because it is too large
Load Diff
628
src/DataViews/PersonView.py
Normal file
628
src/DataViews/PersonView.py
Normal file
@@ -0,0 +1,628 @@
|
||||
# -*- 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 _
|
||||
import cPickle as pickle
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
#
|
||||
# gtk
|
||||
#
|
||||
#-------------------------------------------------------------------------
|
||||
import gtk
|
||||
import pango
|
||||
from gtk.gdk import ACTION_COPY, BUTTON1_MASK
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
#
|
||||
# GRAMPS modules
|
||||
#
|
||||
#-------------------------------------------------------------------------
|
||||
import RelLib
|
||||
import PeopleModel
|
||||
import PageView
|
||||
import GenericFilter
|
||||
import NameDisplay
|
||||
import Utils
|
||||
import QuestionDialog
|
||||
import TreeTips
|
||||
import Errors
|
||||
from Editors import EditPerson
|
||||
|
||||
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.PersonNavView):
|
||||
|
||||
def __init__(self,dbstate,uistate):
|
||||
PageView.PersonNavView.__init__(self,'Person View',dbstate,uistate)
|
||||
self.inactive = False
|
||||
dbstate.connect('database-changed',self.change_db)
|
||||
dbstate.connect('active-changed',self.goto_active_person)
|
||||
self.handle_col = PeopleModel.COLUMN_INT_ID
|
||||
|
||||
def change_page(self):
|
||||
self.generic_filter_widget.on_filter_name_changed(None)
|
||||
|
||||
def define_actions(self):
|
||||
"""
|
||||
Required define_actions function for PageView. Builds the action
|
||||
group information required. We extend beyond the normal here,
|
||||
since we want to have more than one action group for the PersonView.
|
||||
Most PageViews really won't care about this.
|
||||
|
||||
Special action groups for Forward and Back are created to allow the
|
||||
handling of navigation buttons. Forward and Back allow the user to
|
||||
advance or retreat throughout the history, and we want to have these
|
||||
be able to toggle these when you are at the end of the history or
|
||||
at the beginning of the history.
|
||||
"""
|
||||
|
||||
PageView.PersonNavView.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('Jump', None, "_Jump",
|
||||
accel="<control>j",callback=self.jumpto)
|
||||
|
||||
self.add_toggle_action('Filter', None, '_Filter', None, None,
|
||||
self.filter_toggle)
|
||||
|
||||
def get_stock(self):
|
||||
"""
|
||||
Returns the name of the stock icon to use for the display.
|
||||
This assumes that this icon has already been registered with
|
||||
GNOME as a stock icon.
|
||||
"""
|
||||
return 'gramps-person'
|
||||
|
||||
def build_widget(self):
|
||||
"""
|
||||
Builds the interface and returns a gtk.Container type that
|
||||
contains the interface. This containter will be inserted into
|
||||
a gtk.Notebook page.
|
||||
"""
|
||||
self.vbox = gtk.VBox()
|
||||
self.vbox.set_border_width(4)
|
||||
self.vbox.set_spacing(4)
|
||||
|
||||
self.generic_filter_widget = GenericFilter.FilterWidget( self.uistate, self.build_tree, self.goto_active_person)
|
||||
filter_box = self.generic_filter_widget.build()
|
||||
|
||||
|
||||
self.tree = gtk.TreeView()
|
||||
self.tree.set_rules_hint(True)
|
||||
self.tree.set_headers_visible(True)
|
||||
self.tree.connect('key-press-event',self.key_press)
|
||||
|
||||
scrollwindow = gtk.ScrolledWindow()
|
||||
scrollwindow.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
|
||||
scrollwindow.set_shadow_type(gtk.SHADOW_ETCHED_IN)
|
||||
scrollwindow.add(self.tree)
|
||||
scrollwindow.show_all()
|
||||
|
||||
self.vbox.pack_start(filter_box,False)
|
||||
self.vbox.pack_start(scrollwindow,True)
|
||||
|
||||
self.renderer = gtk.CellRendererText()
|
||||
self.renderer.set_property('ellipsize',pango.ELLIPSIZE_END)
|
||||
self.inactive = False
|
||||
|
||||
self.columns = []
|
||||
self.build_columns()
|
||||
self.tree.connect('button-press-event', self.button_press)
|
||||
self.tree.connect('drag_data_get', self.drag_data_get)
|
||||
|
||||
|
||||
self.selection = self.tree.get_selection()
|
||||
self.selection.set_mode(gtk.SELECTION_MULTIPLE)
|
||||
self.selection.connect('changed',self.row_changed)
|
||||
|
||||
#self.vbox.set_focus_chain([self.tree, self.filter_list,
|
||||
# self.filter_text, self.filter_invert,
|
||||
# self.filter_button])
|
||||
|
||||
self.setup_filter()
|
||||
return self.vbox
|
||||
|
||||
def ui_definition(self):
|
||||
"""
|
||||
Specifies the UIManager XML code that defines the menus and buttons
|
||||
associated with the interface.
|
||||
"""
|
||||
return '''<ui>
|
||||
<accelerator action="Jump"/>
|
||||
<menubar name="MenuBar">
|
||||
<menu action="ViewMenu">
|
||||
<menuitem action="Filter"/>
|
||||
</menu>
|
||||
<menu action="GoMenu">
|
||||
<placeholder name="CommonGo">
|
||||
<menuitem action="Back"/>
|
||||
<menuitem action="Forward"/>
|
||||
<separator/>
|
||||
<menuitem action="HomePerson"/>
|
||||
<separator/>
|
||||
</placeholder>
|
||||
</menu>
|
||||
<menu action="EditMenu">
|
||||
<placeholder name="CommonEdit">
|
||||
<menuitem action="Add"/>
|
||||
<menuitem action="Edit"/>
|
||||
<menuitem action="Remove"/>
|
||||
</placeholder>
|
||||
<menuitem action="SetActive"/>
|
||||
</menu>
|
||||
</menubar>
|
||||
<toolbar name="ToolBar">
|
||||
<placeholder name="CommonNavigation">
|
||||
<toolitem action="Back"/>
|
||||
<toolitem action="Forward"/>
|
||||
<toolitem action="HomePerson"/>
|
||||
</placeholder>
|
||||
<placeholder name="CommonEdit">
|
||||
<toolitem action="Add"/>
|
||||
<toolitem action="Edit"/>
|
||||
<toolitem action="Remove"/>
|
||||
</placeholder>
|
||||
</toolbar>
|
||||
<popup name="Popup">
|
||||
<menuitem action="Back"/>
|
||||
<menuitem action="Forward"/>
|
||||
<menuitem action="HomePerson"/>
|
||||
<separator/>
|
||||
<menuitem action="Add"/>
|
||||
<menuitem action="Edit"/>
|
||||
<menuitem action="Remove"/>
|
||||
</popup>
|
||||
</ui>'''
|
||||
|
||||
def change_db(self,db):
|
||||
"""
|
||||
Callback associated with DbState. Whenenver the database
|
||||
changes, this task is called. In this case, we rebuild the
|
||||
columns, and connect signals to the connected database. Tere
|
||||
is no need to store the database, since we will get the value
|
||||
from self.state.db
|
||||
"""
|
||||
self.build_columns()
|
||||
self.db = db
|
||||
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.build_tree)
|
||||
self.build_tree()
|
||||
self.generic_filter_widget.apply_filter()
|
||||
|
||||
def goto_active_person(self,obj=None):
|
||||
self.goto_active_person_2(None)
|
||||
|
||||
def goto_active_person_2(self,obj=None):
|
||||
"""
|
||||
Callback (and usable function) that selects the active person
|
||||
in the display tree.
|
||||
|
||||
We have a bit of a problem due to the nature of how GTK works.
|
||||
We have unselect the previous path and select the new path. However,
|
||||
these cause a row change, which calls the row_change callback, which
|
||||
can end up calling change_active_person, which can call
|
||||
goto_active_person, causing a bit of recusion. Confusing, huh?
|
||||
|
||||
Unforunately, we row_change has to be able to call change_active_person,
|
||||
because the can occur from the interface in addition to programatically.
|
||||
|
||||
TO handle this, we set the self.inactive variable that we can check
|
||||
in row_change to look for this particular condition.
|
||||
"""
|
||||
|
||||
# if there is no active person, or if we have been marked inactive,
|
||||
# simply return
|
||||
|
||||
if not self.dbstate.active or self.inactive:
|
||||
return
|
||||
|
||||
# mark inactive to prevent recusion
|
||||
self.inactive = True
|
||||
|
||||
# select the active person in the person view
|
||||
p = self.dbstate.active
|
||||
try:
|
||||
path = self.model.on_get_path(p.get_handle())
|
||||
group_name = p.get_primary_name().get_group_name()
|
||||
top_name = self.dbstate.db.get_name_group_mapping(group_name)
|
||||
top_path = self.model.on_get_path(top_name)
|
||||
self.tree.expand_row(top_path,0)
|
||||
|
||||
current = self.model.on_get_iter(path)
|
||||
selected = self.selection.path_is_selected(path)
|
||||
if current != p.get_handle() or not selected:
|
||||
self.selection.unselect_all()
|
||||
self.selection.select_path(path)
|
||||
self.tree.scroll_to_cell(path,None,1,0.5,0)
|
||||
except KeyError:
|
||||
self.selection.unselect_all()
|
||||
self.uistate.push_message(_("Active person not visible"))
|
||||
self.dbstate.active = p
|
||||
|
||||
# disable the inactive flag
|
||||
self.inactive = False
|
||||
|
||||
# update history
|
||||
self.handle_history(p.handle)
|
||||
|
||||
def setup_filter(self):
|
||||
"""
|
||||
Builds the default filters and add them to the filter menu.
|
||||
"""
|
||||
default_filters = [
|
||||
[GenericFilter.Everyone, []],
|
||||
[GenericFilter.IsFemale, []],
|
||||
[GenericFilter.IsMale, []],
|
||||
[GenericFilter.HasUnknownGender, []],
|
||||
[GenericFilter.Disconnected, []],
|
||||
[GenericFilter.SearchName, ['']],
|
||||
[GenericFilter.HaveAltFamilies, []],
|
||||
[GenericFilter.HavePhotos, []],
|
||||
[GenericFilter.IncompleteNames, []],
|
||||
[GenericFilter.HaveChildren, []],
|
||||
[GenericFilter.NeverMarried, []],
|
||||
[GenericFilter.MultipleMarriages, []],
|
||||
[GenericFilter.NoBirthdate, []],
|
||||
[GenericFilter.PersonWithIncompleteEvent, []],
|
||||
[GenericFilter.FamilyWithIncompleteEvent, []],
|
||||
[GenericFilter.ProbablyAlive, ['']],
|
||||
[GenericFilter.PeoplePrivate, []],
|
||||
[GenericFilter.IsWitness, ['','']],
|
||||
[GenericFilter.HasTextMatchingSubstringOf, ['',0,0]],
|
||||
[GenericFilter.HasTextMatchingRegexpOf, ['',0,1]],
|
||||
[GenericFilter.HasNote, []],
|
||||
[GenericFilter.HasNoteMatchingSubstringOf, ['']],
|
||||
[GenericFilter.IsFemale, []],
|
||||
]
|
||||
self.generic_filter_widget.setup_filter( default_filters, "person")
|
||||
|
||||
def build_tree(self):
|
||||
"""
|
||||
Creates a new PeopleModel instance. Essentially creates a complete
|
||||
rebuild of the data.
|
||||
"""
|
||||
if self.active:
|
||||
self.model = PeopleModel.PeopleModel(
|
||||
self.dbstate.db, self.generic_filter_widget.get_filter(),
|
||||
self.generic_filter_widget.inverted())
|
||||
self.tree.set_model(self.model)
|
||||
|
||||
if self.model.tooltip_column != None:
|
||||
self.tooltips = TreeTips.TreeTips(self.tree,self.model.tooltip_column,True)
|
||||
self.build_columns()
|
||||
self.dirty = False
|
||||
else:
|
||||
self.dirty = True
|
||||
|
||||
def filter_toggle(self,obj):
|
||||
if obj.get_active():
|
||||
self.generic_filter_widget.show()
|
||||
else:
|
||||
self.generic_filter_widget.hide()
|
||||
|
||||
def add(self,obj):
|
||||
person = RelLib.Person()
|
||||
try:
|
||||
EditPerson(self.dbstate, self.uistate, [], person)
|
||||
except Errors.WindowActiveError:
|
||||
pass
|
||||
|
||||
def edit(self,obj):
|
||||
if self.dbstate.active:
|
||||
try:
|
||||
EditPerson(self.dbstate, self.uistate, [],
|
||||
self.dbstate.active)
|
||||
except Errors.WindowActiveError:
|
||||
pass
|
||||
|
||||
def remove(self,obj):
|
||||
mlist = self.get_selected_objects()
|
||||
if len(mlist) == 0:
|
||||
return
|
||||
|
||||
for sel in mlist:
|
||||
p = self.dbstate.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.dbstate.db.transaction_begin()
|
||||
|
||||
n = NameDisplay.displayer.display(self.active_person)
|
||||
|
||||
if self.dbstate.db.get_default_person() == self.active_person:
|
||||
self.dbstate.db.set_default_person_handle(None)
|
||||
|
||||
for family_handle in self.active_person.get_family_handle_list():
|
||||
if not family_handle:
|
||||
continue
|
||||
family = self.dbstate.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.dbstate.db.get_person_from_handle(child_handle)
|
||||
child.remove_parent_family_handle(family_handle)
|
||||
self.dbstate.db.commit_person(child,trans)
|
||||
self.dbstate.db.remove_family(family_handle,trans)
|
||||
else:
|
||||
self.dbstate.db.commit_family(family,trans)
|
||||
|
||||
for (family_handle,mrel,frel) in self.active_person.get_parent_family_handle_list():
|
||||
if family_handle:
|
||||
family = self.dbstate.db.get_family_from_handle(family_handle)
|
||||
family.remove_child_handle(self.active_person.get_handle())
|
||||
self.dbstate.db.commit_family(family,trans)
|
||||
|
||||
handle = self.active_person.get_handle()
|
||||
|
||||
person = self.active_person
|
||||
self.remove_from_person_list(person)
|
||||
#self.remove_from_history(handle)
|
||||
self.dbstate.db.remove_person(handle, trans)
|
||||
|
||||
self.uistate.phistory.back()
|
||||
self.dbstate.db.transaction_commit(trans,_("Delete Person (%s)") % n)
|
||||
|
||||
def build_columns(self):
|
||||
for column in self.columns:
|
||||
self.tree.remove_column(column)
|
||||
try:
|
||||
column = gtk.TreeViewColumn(_('Name'), self.renderer,text=0,
|
||||
background=self.model.marker_color_column)
|
||||
except AttributeError:
|
||||
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.tree.append_column(column)
|
||||
self.columns = [column]
|
||||
|
||||
for pair in self.dbstate.db.get_person_column_order():
|
||||
if not pair[0]:
|
||||
continue
|
||||
name = column_names[pair[1]]
|
||||
try:
|
||||
column = gtk.TreeViewColumn(name, self.renderer, markup=pair[1],
|
||||
background=self.model.marker_color_column)
|
||||
except AttributeError:
|
||||
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.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()
|
||||
if not self.inactive:
|
||||
try:
|
||||
person = self.dbstate.db.get_person_from_handle(selected_ids[0])
|
||||
self.dbstate.change_active_person(person)
|
||||
except:
|
||||
self.dbstate.change_active_person(None)
|
||||
|
||||
if len(selected_ids) == 1:
|
||||
self.tree.drag_source_set(BUTTON1_MASK,
|
||||
[DdTargets.PERSON_LINK.target()],
|
||||
ACTION_COPY)
|
||||
elif len(selected_ids) > 1:
|
||||
self.tree.drag_source_set(BUTTON1_MASK,
|
||||
[DdTargets.PERSON_LINK_LIST.target()],
|
||||
ACTION_COPY)
|
||||
self.uistate.modify_statusbar()
|
||||
|
||||
def 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 person_added(self,handle_list):
|
||||
self.model.clear_cache()
|
||||
for node in handle_list:
|
||||
person = self.dbstate.db.get_person_from_handle(node)
|
||||
top = person.get_primary_name().get_group_name()
|
||||
self.model.rebuild_data()
|
||||
if not self.model.is_visable(node):
|
||||
continue
|
||||
if (not self.model.sname_sub.has_key(top) or
|
||||
len(self.model.sname_sub[top]) == 1):
|
||||
path = self.model.on_get_path(top)
|
||||
pnode = self.model.get_iter(path)
|
||||
self.model.row_inserted(path,pnode)
|
||||
path = self.model.on_get_path(node)
|
||||
pnode = self.model.get_iter(path)
|
||||
self.model.row_inserted(path,pnode)
|
||||
|
||||
def person_removed(self,handle_list):
|
||||
self.model.clear_cache()
|
||||
self.build_tree()
|
||||
# for node in handle_list:
|
||||
# person = self.dbstate.db.get_person_from_handle(node)
|
||||
# top = person.get_primary_name().get_group_name()
|
||||
# mylist = self.model.sname_sub.get(top,[])
|
||||
# self.model.calculate_data()
|
||||
# if mylist:
|
||||
# try:
|
||||
# path = self.model.on_get_path(node)
|
||||
# self.model.row_deleted(path)
|
||||
# if len(mylist) == 1:
|
||||
# path = self.model.on_get_path(top)
|
||||
# self.model.row_deleted(path)
|
||||
# except KeyError:
|
||||
# pass
|
||||
# self.model.assign_data()
|
||||
|
||||
def person_updated(self,handle_list):
|
||||
self.model.clear_cache()
|
||||
for node in handle_list:
|
||||
person = self.dbstate.db.get_person_from_handle(node)
|
||||
try:
|
||||
oldpath = self.model.iter2path[node]
|
||||
except:
|
||||
return
|
||||
pathval = self.model.on_get_path(node)
|
||||
pnode = self.model.get_iter(pathval)
|
||||
|
||||
# calculate the new data
|
||||
|
||||
if person.primary_name.group_as:
|
||||
surname = person.primary_name.group_as
|
||||
else:
|
||||
base = person.primary_name.surname
|
||||
surname = self.dbstate.db.get_name_group_mapping(base)
|
||||
|
||||
if oldpath[0] == surname:
|
||||
self.model.build_sub_entry(surname)
|
||||
else:
|
||||
self.model.calculate_data(self.DataFilter)
|
||||
|
||||
# find the path of the person in the new data build
|
||||
newpath = self.model.temp_iter2path[node]
|
||||
|
||||
# if paths same, just issue row changed signal
|
||||
|
||||
if oldpath == newpath:
|
||||
self.model.row_changed(pathval,pnode)
|
||||
else:
|
||||
# paths different, get the new surname list
|
||||
|
||||
mylist = self.model.temp_sname_sub.get(oldpath[0],[])
|
||||
path = self.model.on_get_path(node)
|
||||
|
||||
# delete original
|
||||
self.model.row_deleted(pathval)
|
||||
|
||||
# delete top node of original if necessar
|
||||
if len(mylist)==0:
|
||||
self.model.row_deleted(pathval[0])
|
||||
|
||||
# determine if we need to insert a new top node',
|
||||
insert = not self.model.sname_sub.has_key(newpath[0])
|
||||
|
||||
# assign new data
|
||||
self.model.assign_data()
|
||||
|
||||
# insert new row if needed
|
||||
if insert:
|
||||
path = self.model.on_get_path(newpath[0])
|
||||
pnode = self.model.get_iter(path)
|
||||
self.model.row_inserted(path,pnode)
|
||||
|
||||
# insert new person
|
||||
path = self.model.on_get_path(node)
|
||||
pnode = self.model.get_iter(path)
|
||||
self.model.row_inserted(path,pnode)
|
||||
self.goto_active_person()
|
||||
|
||||
def get_selected_objects(self):
|
||||
(mode,paths) = self.selection.get_selected_rows()
|
||||
mlist = []
|
||||
for path in paths:
|
||||
node = self.model.on_get_iter(path)
|
||||
handle = self.model.on_get_value(node, PeopleModel.COLUMN_INT_ID)
|
||||
mlist.append(handle)
|
||||
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.model.on_get_path(person.get_handle())
|
||||
(col,row) = path
|
||||
if row > 0:
|
||||
self.selection.select_path((col,row-1))
|
||||
elif row == 0 and self.model.on_get_iter(path):
|
||||
self.selection.select_path(path)
|
||||
|
||||
def button_press(self,obj,event):
|
||||
if event.type == gtk.gdk._2BUTTON_PRESS and event.button == 1:
|
||||
handle = self.first_selected()
|
||||
person = self.dbstate.db.get_person_from_handle(handle)
|
||||
if person:
|
||||
try:
|
||||
EditPerson(self.dbstate, self.uistate, [], person)
|
||||
except Errors.WindowActiveError:
|
||||
pass
|
||||
return True
|
||||
elif event.type == gtk.gdk.BUTTON_PRESS and event.button == 3:
|
||||
menu = self.uistate.uimanager.get_widget('/Popup')
|
||||
if menu:
|
||||
menu.popup(None,None,None,event.button,event.time)
|
||||
return True
|
||||
return False
|
173
src/DataViews/PlaceView.py
Normal file
173
src/DataViews/PlaceView.py
Normal file
@@ -0,0 +1,173 @@
|
||||
# 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$
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
#
|
||||
# GTK/Gnome modules
|
||||
#
|
||||
#-------------------------------------------------------------------------
|
||||
import gtk
|
||||
import gtk.gdk
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
#
|
||||
# gramps modules
|
||||
#
|
||||
#-------------------------------------------------------------------------
|
||||
import RelLib
|
||||
import PageView
|
||||
import DisplayModels
|
||||
import const
|
||||
import Utils
|
||||
import Errors
|
||||
from Editors import EditPlace, DeletePlaceQuery
|
||||
from QuestionDialog import QuestionDialog, ErrorDialog
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
#
|
||||
# internationalization
|
||||
#
|
||||
#-------------------------------------------------------------------------
|
||||
from gettext import gettext as _
|
||||
|
||||
column_names = [
|
||||
_('Place Name'),
|
||||
_('ID'),
|
||||
_('Church Parish'),
|
||||
_('ZIP/Postal Code'),
|
||||
_('City'),
|
||||
_('County'),
|
||||
_('State'),
|
||||
_('Country'),
|
||||
_('Longitude'),
|
||||
_('Latitude'),
|
||||
_('Last Changed'),
|
||||
]
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
#
|
||||
# PlaceView
|
||||
#
|
||||
#-------------------------------------------------------------------------
|
||||
class PlaceView(PageView.ListView):
|
||||
def __init__(self,dbstate,uistate):
|
||||
|
||||
signal_map = {
|
||||
'place-add' : self.row_add,
|
||||
'place-update' : self.row_update,
|
||||
'place-delete' : self.row_delete,
|
||||
'place-rebuild' : self.build_tree,
|
||||
}
|
||||
|
||||
PageView.ListView.__init__(self,'Place View',dbstate,uistate,
|
||||
column_names,len(column_names),
|
||||
DisplayModels.PlaceModel,
|
||||
signal_map)
|
||||
|
||||
def column_order(self):
|
||||
return self.dbstate.db.get_place_column_order()
|
||||
|
||||
def get_stock(self):
|
||||
return 'gramps-place'
|
||||
|
||||
def ui_definition(self):
|
||||
return '''<ui>
|
||||
<menubar name="MenuBar">
|
||||
<menu action="ViewMenu">
|
||||
<menuitem action="Filter"/>
|
||||
</menu>
|
||||
<menu action="EditMenu">
|
||||
<placeholder name="CommonEdit">
|
||||
<menuitem action="Add"/>
|
||||
<menuitem action="Edit"/>
|
||||
<menuitem action="Remove"/>
|
||||
</placeholder>
|
||||
</menu>
|
||||
</menubar>
|
||||
<toolbar name="ToolBar">
|
||||
<placeholder name="CommonEdit">
|
||||
<toolitem action="Add"/>
|
||||
<toolitem action="Edit"/>
|
||||
<toolitem action="Remove"/>
|
||||
</placeholder>
|
||||
</toolbar>
|
||||
<popup name="Popup">
|
||||
<menuitem action="Add"/>
|
||||
<menuitem action="Edit"/>
|
||||
<menuitem action="Remove"/>
|
||||
</popup>
|
||||
</ui>'''
|
||||
|
||||
def on_double_click(self,obj,event):
|
||||
handle = self.first_selected()
|
||||
place = self.dbstate.db.get_place_from_handle(handle)
|
||||
try:
|
||||
EditPlace(self.dbstate,self.uistate,[],place)
|
||||
except Errors.WindowActiveError:
|
||||
pass
|
||||
|
||||
def add(self,obj):
|
||||
try:
|
||||
EditPlace(self.dbstate,self.uistate,[],RelLib.Place())
|
||||
except Errors.WindowActiveError:
|
||||
pass
|
||||
|
||||
def remove(self,obj):
|
||||
for event_handle in self.selected_handles():
|
||||
db = self.dbstate.db
|
||||
person_list = [ handle for handle in
|
||||
db.get_person_handles(False)
|
||||
if db.get_person_from_handle(handle).has_handle_reference('Place',event_handle) ]
|
||||
family_list = [ handle for handle in
|
||||
db.get_family_handles()
|
||||
if db.get_family_from_handle(handle).has_handle_reference('Place',event_handle) ]
|
||||
|
||||
event = db.get_event_from_handle(event_handle)
|
||||
|
||||
ans = DeletePlaceQuery(event,db,
|
||||
person_list,family_list)
|
||||
|
||||
if len(person_list) + len(family_list) > 0:
|
||||
msg = _('This place is currently being used. Deleting it '
|
||||
'will remove it from the database and from all '
|
||||
'people and families that reference it.')
|
||||
else:
|
||||
msg = _('Deleting place will remove it from the database.')
|
||||
|
||||
msg = "%s %s" % (msg,Utils.data_recover_msg)
|
||||
descr = event.get_description()
|
||||
if descr == "":
|
||||
descr = event.get_gramps_id()
|
||||
|
||||
QuestionDialog(_('Delete %s?') % descr, msg,
|
||||
_('_Delete Place'),ans.query_response)
|
||||
|
||||
def edit(self,obj):
|
||||
mlist = []
|
||||
self.selection.selected_foreach(self.blist,mlist)
|
||||
|
||||
for handle in mlist:
|
||||
place = self.dbstate.db.get_place_from_handle(handle)
|
||||
try:
|
||||
EditPlace(self.dbstate,self.uistate,[],place)
|
||||
except Errors.WindowActiveError:
|
||||
pass
|
||||
|
164
src/DataViews/RepositoryView.py
Normal file
164
src/DataViews/RepositoryView.py
Normal file
@@ -0,0 +1,164 @@
|
||||
# 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$
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
#
|
||||
# GTK/Gnome modules
|
||||
#
|
||||
#-------------------------------------------------------------------------
|
||||
import gtk
|
||||
import gtk.gdk
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
#
|
||||
# gramps modules
|
||||
#
|
||||
#-------------------------------------------------------------------------
|
||||
import RelLib
|
||||
import PageView
|
||||
import DisplayModels
|
||||
import const
|
||||
import Utils
|
||||
from Editors import EditRepository, DelRepositoryQuery
|
||||
|
||||
from QuestionDialog import QuestionDialog, ErrorDialog
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
#
|
||||
# internationalization
|
||||
#
|
||||
#-------------------------------------------------------------------------
|
||||
from gettext import gettext as _
|
||||
|
||||
column_names = [
|
||||
_('Name'),
|
||||
_('ID'),
|
||||
_('Type'),
|
||||
_('Home URL'),
|
||||
_('Street'),
|
||||
_('ZIP/Postal Code'),
|
||||
_('City'),
|
||||
_('County'),
|
||||
_('State'),
|
||||
_('Country'),
|
||||
_('Email'),
|
||||
_('Search URL'),
|
||||
]
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
#
|
||||
# RepositoryView
|
||||
#
|
||||
#-------------------------------------------------------------------------
|
||||
class RepositoryView(PageView.ListView):
|
||||
def __init__(self,dbstate,uistate):
|
||||
|
||||
signal_map = {
|
||||
'repository-add' : self.row_add,
|
||||
'repository-update' : self.row_update,
|
||||
'repository-delete' : self.row_delete,
|
||||
'repository-rebuild' : self.build_tree,
|
||||
}
|
||||
|
||||
PageView.ListView.__init__(self,'Repository View',dbstate,uistate,
|
||||
column_names,len(column_names),
|
||||
DisplayModels.RepositoryModel,
|
||||
signal_map)
|
||||
|
||||
|
||||
def column_order(self):
|
||||
return self.dbstate.db.get_repository_column_order()
|
||||
|
||||
|
||||
def get_stock(self):
|
||||
return 'gramps-repository'
|
||||
|
||||
def ui_definition(self):
|
||||
return '''<ui>
|
||||
<menubar name="MenuBar">
|
||||
<menu action="ViewMenu">
|
||||
<menuitem action="Filter"/>
|
||||
</menu>
|
||||
<menu action="EditMenu">
|
||||
<placeholder name="CommonEdit">
|
||||
<menuitem action="Add"/>
|
||||
<menuitem action="Edit"/>
|
||||
<menuitem action="Remove"/>
|
||||
</placeholder>
|
||||
</menu>
|
||||
</menubar>
|
||||
<toolbar name="ToolBar">
|
||||
<placeholder name="CommonEdit">
|
||||
<toolitem action="Add"/>
|
||||
<toolitem action="Edit"/>
|
||||
<toolitem action="Remove"/>
|
||||
</placeholder>
|
||||
</toolbar>
|
||||
<popup name="Popup">
|
||||
<menuitem action="Add"/>
|
||||
<menuitem action="Edit"/>
|
||||
<menuitem action="Remove"/>
|
||||
</popup>
|
||||
</ui>'''
|
||||
|
||||
def on_double_click(self,obj,event):
|
||||
handle = self.first_selected()
|
||||
repos = self.dbstate.db.get_repository_from_handle(handle)
|
||||
EditRepository(self.dbstate, self.uistate,[],repos)
|
||||
|
||||
def add(self,obj):
|
||||
EditRepository(self.dbstate, self.uistate,[],RelLib.Repository())
|
||||
|
||||
def remove(self,obj):
|
||||
db = self.dbstate.db
|
||||
mlist = []
|
||||
self.selection.selected_foreach(self.blist,mlist)
|
||||
|
||||
for repos_handle in mlist:
|
||||
|
||||
source_list = [ src_handle for src_handle \
|
||||
in db.get_source_handles() \
|
||||
if db.get_source_from_handle(src_handle).has_repo_reference(repos_handle)]
|
||||
|
||||
repository = db.get_repository_from_handle(repos_handle)
|
||||
|
||||
ans = DelRepositoryQuery(repository,db,source_list)
|
||||
|
||||
if len(source_list) > 0:
|
||||
msg = _('This repository is currently being used. Deleting it '
|
||||
'will remove it from the database and from all '
|
||||
'sources that reference it.')
|
||||
else:
|
||||
msg = _('Deleting repository will remove it from the database.')
|
||||
|
||||
msg = "%s %s" % (msg,Utils.data_recover_msg)
|
||||
QuestionDialog(_('Delete %s?') % repository.get_name(), msg,
|
||||
_('_Delete Repository'),ans.query_response)
|
||||
|
||||
|
||||
def edit(self,obj):
|
||||
mlist = []
|
||||
self.selection.selected_foreach(self.blist,mlist)
|
||||
|
||||
for handle in mlist:
|
||||
repos = self.dbstate.db.get_repository_from_handle(handle)
|
||||
EditRepository(self.dbstate, self.uistate, [], repos)
|
||||
|
153
src/DataViews/SourceView.py
Normal file
153
src/DataViews/SourceView.py
Normal file
@@ -0,0 +1,153 @@
|
||||
# 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$
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
#
|
||||
# GTK/Gnome modules
|
||||
#
|
||||
#-------------------------------------------------------------------------
|
||||
import gtk
|
||||
import gtk.gdk
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
#
|
||||
# gramps modules
|
||||
#
|
||||
#-------------------------------------------------------------------------
|
||||
import RelLib
|
||||
import PageView
|
||||
import DisplayModels
|
||||
import const
|
||||
import Utils
|
||||
from Editors import EditSource, DelSrcQuery
|
||||
|
||||
from QuestionDialog import QuestionDialog, ErrorDialog
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
#
|
||||
# internationalization
|
||||
#
|
||||
#-------------------------------------------------------------------------
|
||||
from gettext import gettext as _
|
||||
|
||||
column_names = [
|
||||
_('Title'),
|
||||
_('ID'),
|
||||
_('Author'),
|
||||
_('Abbreviation'),
|
||||
_('Publication Information'),
|
||||
_('Last Changed'),
|
||||
]
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
#
|
||||
# SourceView
|
||||
#
|
||||
#-------------------------------------------------------------------------
|
||||
class SourceView(PageView.ListView):
|
||||
def __init__(self,dbstate,uistate):
|
||||
|
||||
signal_map = {
|
||||
'source-add' : self.row_add,
|
||||
'source-update' : self.row_update,
|
||||
'source-delete' : self.row_delete,
|
||||
'source-rebuild' : self.build_tree,
|
||||
}
|
||||
|
||||
PageView.ListView.__init__(self,'Source View',dbstate,uistate,
|
||||
column_names,len(column_names),
|
||||
DisplayModels.SourceModel,
|
||||
signal_map)
|
||||
|
||||
def column_order(self):
|
||||
return self.dbstate.db.get_source_column_order()
|
||||
|
||||
def get_stock(self):
|
||||
return 'gramps-source'
|
||||
|
||||
def ui_definition(self):
|
||||
return '''<ui>
|
||||
<menubar name="MenuBar">
|
||||
<menu action="ViewMenu">
|
||||
<menuitem action="Filter"/>
|
||||
</menu>
|
||||
<menu action="EditMenu">
|
||||
<placeholder name="CommonEdit">
|
||||
<menuitem action="Add"/>
|
||||
<menuitem action="Edit"/>
|
||||
<menuitem action="Remove"/>
|
||||
</placeholder>
|
||||
</menu>
|
||||
</menubar>
|
||||
<toolbar name="ToolBar">
|
||||
<placeholder name="CommonEdit">
|
||||
<toolitem action="Add"/>
|
||||
<toolitem action="Edit"/>
|
||||
<toolitem action="Remove"/>
|
||||
</placeholder>
|
||||
</toolbar>
|
||||
<popup name="Popup">
|
||||
<menuitem action="Add"/>
|
||||
<menuitem action="Edit"/>
|
||||
<menuitem action="Remove"/>
|
||||
</popup>
|
||||
</ui>'''
|
||||
|
||||
def on_double_click(self,obj,event):
|
||||
handle = self.first_selected()
|
||||
source = self.dbstate.db.get_source_from_handle(handle)
|
||||
EditSource(self.dbstate, self.uistate, [], source)
|
||||
|
||||
def add(self,obj):
|
||||
EditSource(self.dbstate, self.uistate, [], RelLib.Source())
|
||||
|
||||
def remove(self,obj):
|
||||
for source_handle in self.selected_handles():
|
||||
db = self.dbstate.db
|
||||
the_lists = Utils.get_source_referents(source_handle,db)
|
||||
|
||||
source = db.get_source_from_handle(source_handle)
|
||||
|
||||
ans = DelSrcQuery(source,db,the_lists)
|
||||
|
||||
if filter(None,the_lists): # quick test for non-emptiness
|
||||
msg = _('This source is currently being used. Deleting it '
|
||||
'will remove it from the database and from all '
|
||||
'people and families that reference it.')
|
||||
else:
|
||||
msg = _('Deleting source will remove it from the database.')
|
||||
|
||||
msg = "%s %s" % (msg,Utils.data_recover_msg)
|
||||
descr = source.get_title()
|
||||
if descr == "":
|
||||
descr = source.get_gramps_id()
|
||||
|
||||
QuestionDialog(_('Delete %s?') % descr, msg,
|
||||
_('_Delete Source'),ans.query_response)
|
||||
|
||||
def edit(self,obj):
|
||||
mlist = []
|
||||
self.selection.selected_foreach(self.blist,mlist)
|
||||
|
||||
for handle in mlist:
|
||||
source = self.dbstate.db.get_source_from_handle(handle)
|
||||
EditSource(self.dbstate, self.uistate, [], source)
|
||||
|
36
src/DataViews/__init__.py
Normal file
36
src/DataViews/__init__.py
Normal file
@@ -0,0 +1,36 @@
|
||||
# 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: __init__.py 6067 2006-03-04 05:24:16Z dallingham $
|
||||
|
||||
from PersonView import PersonView
|
||||
from FamilyView import FamilyView
|
||||
from FamilyList import FamilyListView
|
||||
from PedView import PedView
|
||||
from EventView import EventView
|
||||
from SourceView import SourceView
|
||||
from PlaceView import PlaceView
|
||||
from MediaView import MediaView
|
||||
from MapView import MapView
|
||||
from RepositoryView import RepositoryView
|
||||
|
||||
def get_views():
|
||||
return [PersonView, FamilyView, FamilyListView, PedView,
|
||||
EventView, SourceView, PlaceView, MediaView,
|
||||
MapView, RepositoryView]
|
Reference in New Issue
Block a user