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:
Benny Malengier 2007-11-21 23:15:10 +00:00
parent d6deb0c95b
commit 14885c719e
6 changed files with 148 additions and 24 deletions

View File

@ -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>
* src/gen/lib/date.py: added comparison operator for match()
* src/Utils.py: uses new match comparison

View File

@ -314,6 +314,9 @@ class DisplayState(gen.utils.GrampsDBCallback):
self.phistory = History()
self.gwm = ManagedWindow.GrampsWindowManager(uimanager)
self.widget = None
self.disprel_old = ''
self.disprel_defpers = None
self.disprel_active = None
self.warnbtn = warnbtn
self.last_bar = self.status.insert(min_width=15, ralign=True)
self.set_relationship_class()
@ -341,13 +344,30 @@ class DisplayState(gen.utils.GrampsDBCallback):
self.relationship = _PluginMgr.relationship_class()
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()
active = dbstate.get_active_person()
if default_person == None or active == None:
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(
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:
return name
else:

View File

@ -378,13 +378,14 @@ class RelationshipCalculator:
PARTNER_EX_UNKNOWN_REL = 8
def __init__(self):
pass
def get_parents(self, level):
if level>len(_parents_level)-1:
return "distant ancestors (%d generations)" % level
else:
return _parents_level[level]
self.signal_keys = []
self.state_signal_key = None
self.storemap = False
self.dirtymap = True
self.stored_map = None
self.map_handle = None
self.map_meta = None
self.__db_connected = False
DIST_FATHER = "distant %(step)sancestor%(inlaw)s (%(level)d generations)"
@ -534,6 +535,12 @@ class RelationshipCalculator:
# how the siblings are related:
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):
""" method that returns the birthparents of a person as tuple
(mother handle, father handle), if no known birthparent, the
@ -749,13 +756,32 @@ class RelationshipCalculator:
rank = 9999999
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,
stoprecursemap = firstMap)
except RuntimeError:
return (-1,None,-1,[],-1,[] ) , \
[_("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() :
if firstMap.has_key(person_handle) :
com = []
@ -844,6 +870,7 @@ class RelationshipCalculator:
'''
if person == None or not person.handle :
return
if depth > self.__max_depth:
self.__maxDepthReached = True
print 'Maximum ancestor generations ('+str(depth)+') reached', \
@ -1712,6 +1739,55 @@ class RelationshipCalculator:
else:
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):
""" this is a generic test suite for the singular relationship
TRANSLATORS: do NOT translate, use __main__ !

View File

@ -63,7 +63,7 @@ class Leak(Tool.Tool,ManagedWindow.ManagedWindow):
Tool.Tool.__init__(self,dbstate, options_class, name)
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")
window = self.glade.get_widget("top")

View File

@ -36,6 +36,7 @@ from gettext import gettext as _
#
#-------------------------------------------------------------------------
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 '
'tool to work properly.'))
return
self.dbstate = dbstate
self.relationship = relationship_class()
self.relationship.connect_db_signals(dbstate)
base = os.path.dirname(__file__)
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)
self.title = _('Relationship calculator: %(person_name)s'
) % {'person_name' : name}
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'
) % {'person_name' : name },
self.title)
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.tree.set_model(self.model)
@ -111,6 +118,8 @@ class RelCalc(Tool.Tool, ManagedWindow.ManagedWindow):
column.set_min_width(225)
column.set_sizing(gtk.TREE_VIEW_COLUMN_FIXED)
self.tree.append_column(column)
#keep reference of column so garbage collection works
self.columns = [column]
index = 1
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_sizing(gtk.TREE_VIEW_COLUMN_GROW_ONLY)
self.tree.append_column(column)
#keep reference of column so garbage collection works
self.columns.append(column)
index += 1
self.tree.get_selection().connect('changed',self.on_apply_clicked)
self.glade.signal_autoconnect({
"on_close_clicked" : self.close,
})
self.sel = self.tree.get_selection()
self.changedkey = self.sel.connect('changed',self.on_apply_clicked)
self.closebtn = self.glade.get_widget("button5")
self.closebtn.connect('clicked', self.close)
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):
return (_("Relationship Calculator tool"),None)
@ -142,12 +160,9 @@ class RelCalc(Tool.Tool, ManagedWindow.ManagedWindow):
return
handle = model.get_value(node,len(PeopleModel.COLUMN_DEFS)-1)
other_person = self.db.get_person_from_handle(handle)
text1 = self.glade.get_widget("text1").get_buffer()
other_person = self.db.get_person_from_handle(handle)
if other_person is None :
text1.set_text("")
self.textbuffer.set_text("")
return
#now determine the relation, and print it out
@ -205,7 +220,7 @@ class RelCalc(Tool.Tool, ManagedWindow.ManagedWindow):
textval = ""
for val in text:
textval += "%s %s\n" % (val[0], val[1])
text1.set_text(textval)
self.textbuffer.set_text(textval)
#------------------------------------------------------------------------
#

View File

@ -19,6 +19,7 @@
<property name="type_hint">GDK_WINDOW_TYPE_HINT_DIALOG</property>
<property name="gravity">GDK_GRAVITY_NORTH_WEST</property>
<property name="focus_on_map">True</property>
<property name="urgency_hint">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"/>
@ -43,7 +44,6 @@
<property name="relief">GTK_RELIEF_NORMAL</property>
<property name="focus_on_click">True</property>
<property name="response_id">0</property>
<signal name="clicked" handler="on_close_clicked" object="relcalc"/>
</widget>
</child>
</widget>