2007-11-22 Benny Malengier <benny.malengier@gramps-project.org>
* src/plugins/relcalc.glade: don't do connect in glade, we need key * src/plugins/Leak.py: use os.sep, not + '/' * src/plugins/RelCalc.py: Don't keep recalculating relation map of the active person, do it once. 50% faster. Make sure all objects can be collected by the garbage collector * src/Relationship.py: allow to connect to database. Map of first person is stored, only to be removed if database changed, or it concerns a different person. This reduces calculation with 50% * src/DisplayState.py: don't recalculate home person every time, don't call relationship calc on every click, only call it when the people are different svn: r9383
This commit is contained in:
parent
d6deb0c95b
commit
14885c719e
13
ChangeLog
13
ChangeLog
@ -1,3 +1,16 @@
|
|||||||
|
2007-11-22 Benny Malengier <benny.malengier@gramps-project.org>
|
||||||
|
* src/plugins/relcalc.glade: don't do connect in glade, we need key
|
||||||
|
* src/plugins/Leak.py: use os.sep, not + '/'
|
||||||
|
* src/plugins/RelCalc.py: Don't keep recalculating relation map of the
|
||||||
|
active person, do it once. 50% faster. Make sure all objects can be
|
||||||
|
collected by the garbage collector
|
||||||
|
* src/Relationship.py: allow to connect to database. Map of first
|
||||||
|
person is stored, only to be removed if database changed, or it
|
||||||
|
concerns a different person. This reduces calculation with 50%
|
||||||
|
* src/DisplayState.py: don't recalculate home person every time, don't
|
||||||
|
call relationship calc on every click, only call it when the people
|
||||||
|
are different
|
||||||
|
|
||||||
2007-11-21 Douglas S. Blank <dblank@cs.brynmawr.edu>
|
2007-11-21 Douglas S. Blank <dblank@cs.brynmawr.edu>
|
||||||
* src/gen/lib/date.py: added comparison operator for match()
|
* src/gen/lib/date.py: added comparison operator for match()
|
||||||
* src/Utils.py: uses new match comparison
|
* src/Utils.py: uses new match comparison
|
||||||
|
@ -314,6 +314,9 @@ class DisplayState(gen.utils.GrampsDBCallback):
|
|||||||
self.phistory = History()
|
self.phistory = History()
|
||||||
self.gwm = ManagedWindow.GrampsWindowManager(uimanager)
|
self.gwm = ManagedWindow.GrampsWindowManager(uimanager)
|
||||||
self.widget = None
|
self.widget = None
|
||||||
|
self.disprel_old = ''
|
||||||
|
self.disprel_defpers = None
|
||||||
|
self.disprel_active = None
|
||||||
self.warnbtn = warnbtn
|
self.warnbtn = warnbtn
|
||||||
self.last_bar = self.status.insert(min_width=15, ralign=True)
|
self.last_bar = self.status.insert(min_width=15, ralign=True)
|
||||||
self.set_relationship_class()
|
self.set_relationship_class()
|
||||||
@ -341,13 +344,30 @@ class DisplayState(gen.utils.GrampsDBCallback):
|
|||||||
self.relationship = _PluginMgr.relationship_class()
|
self.relationship = _PluginMgr.relationship_class()
|
||||||
|
|
||||||
def display_relationship(self, dbstate):
|
def display_relationship(self, dbstate):
|
||||||
|
''' Construct the relationship in order to show it in the statusbar
|
||||||
|
This can be a time intensive calculation, so we only want to do
|
||||||
|
it if persons are different than before.
|
||||||
|
Eg: select a person, then double click, will result in calling
|
||||||
|
three times to construct build the statusbar. We only want
|
||||||
|
to obtain relationship once!
|
||||||
|
This means the relationship part of statusbar only changes on
|
||||||
|
change of row.
|
||||||
|
'''
|
||||||
|
self.relationship.connect_db_signals(dbstate)
|
||||||
default_person = dbstate.db.get_default_person()
|
default_person = dbstate.db.get_default_person()
|
||||||
active = dbstate.get_active_person()
|
active = dbstate.get_active_person()
|
||||||
if default_person == None or active == None:
|
if default_person == None or active == None:
|
||||||
return u''
|
return u''
|
||||||
|
if default_person.handle == self.disprel_defpers and \
|
||||||
|
active.handle == self.disprel_active :
|
||||||
|
return self.disprel_old
|
||||||
|
|
||||||
name = self.relationship.get_one_relationship(
|
name = self.relationship.get_one_relationship(
|
||||||
dbstate.db, default_person, active)
|
dbstate.db, default_person, active)
|
||||||
|
#store present call data
|
||||||
|
self.disprel_old = name
|
||||||
|
self.disprel_defpers = default_person.handle
|
||||||
|
self.disprel_active = active.handle
|
||||||
if name:
|
if name:
|
||||||
return name
|
return name
|
||||||
else:
|
else:
|
||||||
|
@ -378,13 +378,14 @@ class RelationshipCalculator:
|
|||||||
PARTNER_EX_UNKNOWN_REL = 8
|
PARTNER_EX_UNKNOWN_REL = 8
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
pass
|
self.signal_keys = []
|
||||||
|
self.state_signal_key = None
|
||||||
def get_parents(self, level):
|
self.storemap = False
|
||||||
if level>len(_parents_level)-1:
|
self.dirtymap = True
|
||||||
return "distant ancestors (%d generations)" % level
|
self.stored_map = None
|
||||||
else:
|
self.map_handle = None
|
||||||
return _parents_level[level]
|
self.map_meta = None
|
||||||
|
self.__db_connected = False
|
||||||
|
|
||||||
DIST_FATHER = "distant %(step)sancestor%(inlaw)s (%(level)d generations)"
|
DIST_FATHER = "distant %(step)sancestor%(inlaw)s (%(level)d generations)"
|
||||||
|
|
||||||
@ -534,6 +535,12 @@ class RelationshipCalculator:
|
|||||||
# how the siblings are related:
|
# how the siblings are related:
|
||||||
return self.UNKNOWN_SIB
|
return self.UNKNOWN_SIB
|
||||||
|
|
||||||
|
def get_parents(self, level):
|
||||||
|
if level>len(_parents_level)-1:
|
||||||
|
return "distant ancestors (%d generations)" % level
|
||||||
|
else:
|
||||||
|
return _parents_level[level]
|
||||||
|
|
||||||
def _get_birth_parents(self, db, person):
|
def _get_birth_parents(self, db, person):
|
||||||
""" method that returns the birthparents of a person as tuple
|
""" method that returns the birthparents of a person as tuple
|
||||||
(mother handle, father handle), if no known birthparent, the
|
(mother handle, father handle), if no known birthparent, the
|
||||||
@ -749,13 +756,32 @@ class RelationshipCalculator:
|
|||||||
rank = 9999999
|
rank = 9999999
|
||||||
|
|
||||||
try:
|
try:
|
||||||
self.__apply_filter(db, orig_person, '', [], firstMap)
|
if (self.storemap and self.stored_map is not None
|
||||||
|
and self.map_handle == orig_person.handle
|
||||||
|
and not self.dirtymap):
|
||||||
|
firstMap = self.stored_map
|
||||||
|
self.__maxDepthReached, self.__loopDetected, \
|
||||||
|
self.__max_depth, self.__all_families,\
|
||||||
|
self.__all_dist, self.__only_birth,\
|
||||||
|
self.__crosslinks, self.__msg = self.map_meta
|
||||||
|
else:
|
||||||
|
self.__apply_filter(db, orig_person, '', [], firstMap)
|
||||||
|
self.map_meta = (self.__maxDepthReached,
|
||||||
|
self.__loopDetected,
|
||||||
|
self.__max_depth, self.__all_families,
|
||||||
|
self.__all_dist, self.__only_birth,
|
||||||
|
self.__crosslinks, self.__msg)
|
||||||
self.__apply_filter(db, other_person, '', [], secondMap,
|
self.__apply_filter(db, other_person, '', [], secondMap,
|
||||||
stoprecursemap = firstMap)
|
stoprecursemap = firstMap)
|
||||||
except RuntimeError:
|
except RuntimeError:
|
||||||
return (-1,None,-1,[],-1,[] ) , \
|
return (-1,None,-1,[],-1,[] ) , \
|
||||||
[_("Relationship loop detected")] + self.__msg
|
[_("Relationship loop detected")] + self.__msg
|
||||||
|
|
||||||
|
if self.storemap:
|
||||||
|
self.stored_map = firstMap
|
||||||
|
self.dirtymap = False
|
||||||
|
self.map_handle = orig_person.handle
|
||||||
|
|
||||||
for person_handle in secondMap.keys() :
|
for person_handle in secondMap.keys() :
|
||||||
if firstMap.has_key(person_handle) :
|
if firstMap.has_key(person_handle) :
|
||||||
com = []
|
com = []
|
||||||
@ -844,6 +870,7 @@ class RelationshipCalculator:
|
|||||||
'''
|
'''
|
||||||
if person == None or not person.handle :
|
if person == None or not person.handle :
|
||||||
return
|
return
|
||||||
|
|
||||||
if depth > self.__max_depth:
|
if depth > self.__max_depth:
|
||||||
self.__maxDepthReached = True
|
self.__maxDepthReached = True
|
||||||
print 'Maximum ancestor generations ('+str(depth)+') reached', \
|
print 'Maximum ancestor generations ('+str(depth)+') reached', \
|
||||||
@ -1712,6 +1739,55 @@ class RelationshipCalculator:
|
|||||||
else:
|
else:
|
||||||
return _("gender unknown,unknown relation|former partner")
|
return _("gender unknown,unknown relation|former partner")
|
||||||
|
|
||||||
|
def connect_db_signals(self, dbstate):
|
||||||
|
""" We can save work by storing a map, however, if database changes
|
||||||
|
this map must be regenerated.
|
||||||
|
Before close, the calling app must call disconnect_db_signals
|
||||||
|
"""
|
||||||
|
if self.__db_connected:
|
||||||
|
return
|
||||||
|
assert(len(self.signal_keys)==0)
|
||||||
|
self.state_signal_key = dbstate.connect('database-changed',
|
||||||
|
self._dbchange_callback)
|
||||||
|
self.__connect_db_signals(dbstate.db)
|
||||||
|
|
||||||
|
def __connect_db_signals(self, db):
|
||||||
|
signals = ['person-add', 'person-update', 'person-delete',
|
||||||
|
'person-rebuild', 'family-add', 'family-update',
|
||||||
|
'family-delete', 'family-rebuild', 'database-changed']
|
||||||
|
for name in signals:
|
||||||
|
self.signal_keys.append(db.connect(name,
|
||||||
|
self._datachange_callback))
|
||||||
|
self.storemap = True
|
||||||
|
self.__db_connected = True
|
||||||
|
|
||||||
|
def disconnect_db_signals(self, dbstate):
|
||||||
|
""" Method to disconnect to all signals the relationship calculator is
|
||||||
|
subscribed
|
||||||
|
"""
|
||||||
|
dbstate.disconnect(self.state_signal_key)
|
||||||
|
for key in self.signal_keys:
|
||||||
|
dbstate.db.disconnect(key)
|
||||||
|
self.storemap = False
|
||||||
|
self.stored_map = None
|
||||||
|
|
||||||
|
def _dbchange_callback(self, db):
|
||||||
|
""" When database changes, the map can no longer be used.
|
||||||
|
Connects must be remade
|
||||||
|
"""
|
||||||
|
self.dirtymap = True
|
||||||
|
#signals are disconnected on close of old database, connect to new
|
||||||
|
self.__connect_db_signals(db)
|
||||||
|
|
||||||
|
def _datachange_callback(self, list=[]):
|
||||||
|
""" When data in database changes, the map can no longer be used.
|
||||||
|
As the map might be in use or might be generated at the moment,
|
||||||
|
this method sets a dirty flag. Before reusing the map, this flag
|
||||||
|
will be checked
|
||||||
|
"""
|
||||||
|
self.dirtymap = True
|
||||||
|
|
||||||
|
|
||||||
def _test(rc, onlybirth, inlawa, inlawb, printrelstr):
|
def _test(rc, onlybirth, inlawa, inlawb, printrelstr):
|
||||||
""" this is a generic test suite for the singular relationship
|
""" this is a generic test suite for the singular relationship
|
||||||
TRANSLATORS: do NOT translate, use __main__ !
|
TRANSLATORS: do NOT translate, use __main__ !
|
||||||
|
@ -63,7 +63,7 @@ class Leak(Tool.Tool,ManagedWindow.ManagedWindow):
|
|||||||
Tool.Tool.__init__(self,dbstate, options_class, name)
|
Tool.Tool.__init__(self,dbstate, options_class, name)
|
||||||
ManagedWindow.ManagedWindow.__init__(self,uistate,[],self.__class__)
|
ManagedWindow.ManagedWindow.__init__(self,uistate,[],self.__class__)
|
||||||
|
|
||||||
glade_file = "%s/%s" % (os.path.dirname(__file__),"leak.glade")
|
glade_file = os.path.dirname(__file__) + os.sep + "leak.glade"
|
||||||
self.glade = gtk.glade.XML(glade_file,"top","gramps")
|
self.glade = gtk.glade.XML(glade_file,"top","gramps")
|
||||||
|
|
||||||
window = self.glade.get_widget("top")
|
window = self.glade.get_widget("top")
|
||||||
|
@ -36,6 +36,7 @@ from gettext import gettext as _
|
|||||||
#
|
#
|
||||||
#-------------------------------------------------------------------------
|
#-------------------------------------------------------------------------
|
||||||
import gtk.glade
|
import gtk.glade
|
||||||
|
from gtk import TextBuffer
|
||||||
|
|
||||||
#-------------------------------------------------------------------------
|
#-------------------------------------------------------------------------
|
||||||
#
|
#
|
||||||
@ -85,23 +86,29 @@ class RelCalc(Tool.Tool, ManagedWindow.ManagedWindow):
|
|||||||
_('You must select an active person for this '
|
_('You must select an active person for this '
|
||||||
'tool to work properly.'))
|
'tool to work properly.'))
|
||||||
return
|
return
|
||||||
|
|
||||||
|
self.dbstate = dbstate
|
||||||
self.relationship = relationship_class()
|
self.relationship = relationship_class()
|
||||||
|
self.relationship.connect_db_signals(dbstate)
|
||||||
|
|
||||||
base = os.path.dirname(__file__)
|
base = os.path.dirname(__file__)
|
||||||
glade_file = base + os.sep + "relcalc.glade"
|
glade_file = base + os.sep + "relcalc.glade"
|
||||||
self.glade = gtk.glade.XML(glade_file,"relcalc","gramps")
|
self.glade = gtk.glade.XML(glade_file, "relcalc", "gramps")
|
||||||
|
|
||||||
name = name_displayer.display(self.person)
|
name = name_displayer.display(self.person)
|
||||||
self.title = _('Relationship calculator: %(person_name)s'
|
self.title = _('Relationship calculator: %(person_name)s'
|
||||||
) % {'person_name' : name}
|
) % {'person_name' : name}
|
||||||
window = self.glade.get_widget('relcalc')
|
window = self.glade.get_widget('relcalc')
|
||||||
self.set_window(window,self.glade.get_widget('title'),
|
self.titlelabel = self.glade.get_widget('title')
|
||||||
|
self.set_window(window, self.titlelabel,
|
||||||
_('Relationship to %(person_name)s'
|
_('Relationship to %(person_name)s'
|
||||||
) % {'person_name' : name },
|
) % {'person_name' : name },
|
||||||
self.title)
|
self.title)
|
||||||
|
|
||||||
self.tree = self.glade.get_widget("peopleList")
|
self.tree = self.glade.get_widget("peopleList")
|
||||||
|
self.text = self.glade.get_widget("text1")
|
||||||
|
self.textbuffer = TextBuffer()
|
||||||
|
self.text.set_buffer(self.textbuffer)
|
||||||
|
|
||||||
self.model = PeopleModel(self.db,None)
|
self.model = PeopleModel(self.db,None)
|
||||||
self.tree.set_model(self.model)
|
self.tree.set_model(self.model)
|
||||||
@ -111,6 +118,8 @@ class RelCalc(Tool.Tool, ManagedWindow.ManagedWindow):
|
|||||||
column.set_min_width(225)
|
column.set_min_width(225)
|
||||||
column.set_sizing(gtk.TREE_VIEW_COLUMN_FIXED)
|
column.set_sizing(gtk.TREE_VIEW_COLUMN_FIXED)
|
||||||
self.tree.append_column(column)
|
self.tree.append_column(column)
|
||||||
|
#keep reference of column so garbage collection works
|
||||||
|
self.columns = [column]
|
||||||
|
|
||||||
index = 1
|
index = 1
|
||||||
for pair in self.db.get_person_column_order():
|
for pair in self.db.get_person_column_order():
|
||||||
@ -123,16 +132,25 @@ class RelCalc(Tool.Tool, ManagedWindow.ManagedWindow):
|
|||||||
column.set_min_width(60)
|
column.set_min_width(60)
|
||||||
column.set_sizing(gtk.TREE_VIEW_COLUMN_GROW_ONLY)
|
column.set_sizing(gtk.TREE_VIEW_COLUMN_GROW_ONLY)
|
||||||
self.tree.append_column(column)
|
self.tree.append_column(column)
|
||||||
|
#keep reference of column so garbage collection works
|
||||||
|
self.columns.append(column)
|
||||||
index += 1
|
index += 1
|
||||||
|
|
||||||
self.tree.get_selection().connect('changed',self.on_apply_clicked)
|
self.sel = self.tree.get_selection()
|
||||||
|
self.changedkey = self.sel.connect('changed',self.on_apply_clicked)
|
||||||
self.glade.signal_autoconnect({
|
self.closebtn = self.glade.get_widget("button5")
|
||||||
"on_close_clicked" : self.close,
|
self.closebtn.connect('clicked', self.close)
|
||||||
})
|
|
||||||
|
|
||||||
self.show()
|
self.show()
|
||||||
|
|
||||||
|
def close(self, *obj):
|
||||||
|
''' Close relcalc tool. Remove non-gtk connections so garbage
|
||||||
|
collection can do its magic.
|
||||||
|
'''
|
||||||
|
self.relationship.disconnect_db_signals(self.dbstate)
|
||||||
|
self.sel.disconnect(self.changedkey)
|
||||||
|
ManagedWindow.ManagedWindow.close(self, *obj)
|
||||||
|
|
||||||
def build_menu_names(self,obj):
|
def build_menu_names(self,obj):
|
||||||
return (_("Relationship Calculator tool"),None)
|
return (_("Relationship Calculator tool"),None)
|
||||||
|
|
||||||
@ -142,12 +160,9 @@ class RelCalc(Tool.Tool, ManagedWindow.ManagedWindow):
|
|||||||
return
|
return
|
||||||
|
|
||||||
handle = model.get_value(node,len(PeopleModel.COLUMN_DEFS)-1)
|
handle = model.get_value(node,len(PeopleModel.COLUMN_DEFS)-1)
|
||||||
other_person = self.db.get_person_from_handle(handle)
|
other_person = self.db.get_person_from_handle(handle)
|
||||||
|
|
||||||
text1 = self.glade.get_widget("text1").get_buffer()
|
|
||||||
|
|
||||||
if other_person is None :
|
if other_person is None :
|
||||||
text1.set_text("")
|
self.textbuffer.set_text("")
|
||||||
return
|
return
|
||||||
|
|
||||||
#now determine the relation, and print it out
|
#now determine the relation, and print it out
|
||||||
@ -205,7 +220,7 @@ class RelCalc(Tool.Tool, ManagedWindow.ManagedWindow):
|
|||||||
textval = ""
|
textval = ""
|
||||||
for val in text:
|
for val in text:
|
||||||
textval += "%s %s\n" % (val[0], val[1])
|
textval += "%s %s\n" % (val[0], val[1])
|
||||||
text1.set_text(textval)
|
self.textbuffer.set_text(textval)
|
||||||
|
|
||||||
#------------------------------------------------------------------------
|
#------------------------------------------------------------------------
|
||||||
#
|
#
|
||||||
|
@ -19,6 +19,7 @@
|
|||||||
<property name="type_hint">GDK_WINDOW_TYPE_HINT_DIALOG</property>
|
<property name="type_hint">GDK_WINDOW_TYPE_HINT_DIALOG</property>
|
||||||
<property name="gravity">GDK_GRAVITY_NORTH_WEST</property>
|
<property name="gravity">GDK_GRAVITY_NORTH_WEST</property>
|
||||||
<property name="focus_on_map">True</property>
|
<property name="focus_on_map">True</property>
|
||||||
|
<property name="urgency_hint">False</property>
|
||||||
<property name="has_separator">False</property>
|
<property name="has_separator">False</property>
|
||||||
<signal name="delete_event" handler="on_delete_event" last_modification_time="Tue, 11 May 2004 00:39:37 GMT"/>
|
<signal name="delete_event" handler="on_delete_event" last_modification_time="Tue, 11 May 2004 00:39:37 GMT"/>
|
||||||
|
|
||||||
@ -43,7 +44,6 @@
|
|||||||
<property name="relief">GTK_RELIEF_NORMAL</property>
|
<property name="relief">GTK_RELIEF_NORMAL</property>
|
||||||
<property name="focus_on_click">True</property>
|
<property name="focus_on_click">True</property>
|
||||||
<property name="response_id">0</property>
|
<property name="response_id">0</property>
|
||||||
<signal name="clicked" handler="on_close_clicked" object="relcalc"/>
|
|
||||||
</widget>
|
</widget>
|
||||||
</child>
|
</child>
|
||||||
</widget>
|
</widget>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user