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>
|
||||
* src/gen/lib/date.py: added comparison operator for match()
|
||||
* src/Utils.py: uses new match comparison
|
||||
|
@ -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:
|
||||
|
@ -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__ !
|
||||
|
@ -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")
|
||||
|
@ -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)
|
||||
|
||||
#------------------------------------------------------------------------
|
||||
#
|
||||
|
@ -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>
|
||||
|
Loading…
Reference in New Issue
Block a user