implement roster iter cache to speed iter search.

This commit is contained in:
Yann Leboulanger 2010-07-24 00:12:16 +02:00
parent 2d9c32c16e
commit e70fd78d20
1 changed files with 83 additions and 92 deletions

View File

@ -98,43 +98,50 @@ class RosterWindow:
name -- the account name name -- the account name
model -- the data model (default TreeFilterModel) model -- the data model (default TreeFilterModel)
""" """
if not model: if model is None:
model = self.modelfilter model = self.modelfilter
if model is None: if model is None:
return return
account_iter = model.get_iter_root()
if self.regroup: if self.regroup:
return account_iter if 'account' not in self._iters:
while account_iter: return None
account_name = model[account_iter][C_ACCOUNT] it = self._iters['account']
if account_name and name == account_name.decode('utf-8'): else:
break it = self._iters[name]['account']
account_iter = model.iter_next(account_iter)
return account_iter if model == self.model or it is None:
return it
try:
return self.modelfilter.convert_child_iter_to_iter(it)
except RuntimeError:
return None
def _get_group_iter(self, name, account, account_iter=None, model=None): def _get_group_iter(self, name, account, model=None):
""" """
Return the gtk.TreeIter of the given group or None if not found Return the gtk.TreeIter of the given group or None if not found
Keyword arguments: Keyword arguments:
name -- the group name name -- the group name
account -- the account name account -- the account name
account_iter -- the iter of the account the model (default None)
model -- the data model (default TreeFilterModel) model -- the data model (default TreeFilterModel)
""" """
if not model: if model is None:
model = self.modelfilter model = self.modelfilter
if not account_iter: if model is None:
account_iter = self._get_account_iter(account, model) return
group_iter = model.iter_children(account_iter)
# C_NAME column contacts the pango escaped group name if name not in self._iters[account]['groups']:
while group_iter: return None
group_name = model[group_iter][C_JID].decode('utf-8')
if name == group_name: it = self._iters[account]['groups'][name]
break if model == self.model or it is None:
group_iter = model.iter_next(group_iter) return it
return group_iter try:
return self.modelfilter.convert_child_iter_to_iter(it)
except RuntimeError:
return None
def _get_self_contact_iter(self, account, model=None): def _get_self_contact_iter(self, account, model=None):
@ -145,19 +152,10 @@ class RosterWindow:
account -- the account of SelfContact account -- the account of SelfContact
model -- the data model (default TreeFilterModel) model -- the data model (default TreeFilterModel)
""" """
if not model: jid = gajim.get_jid_from_account(account)
model = self.modelfilter its = self._get_contact_iter(jid, account, model=model)
iterAcct = self._get_account_iter(account, model) if its:
iterC = model.iter_children(iterAcct) return its[0]
# There might be several SelfContacts in merged account view
while iterC:
if model[iterC][C_TYPE] != 'self_contact':
break
iter_account = model[iterC][C_ACCOUNT]
if account == iter_account.decode('utf-8'):
return iterC
iterC = model.iter_next(iterC)
return None return None
@ -171,61 +169,36 @@ class RosterWindow:
contact -- the contact (default None) contact -- the contact (default None)
model -- the data model (default TreeFilterModel) model -- the data model (default TreeFilterModel)
""" """
if not model: if model is None:
model = self.modelfilter model = self.modelfilter
# when closing Gajim model can be none (async pbs?) # when closing Gajim model can be none (async pbs?)
if model is None: if model is None:
return [] return []
if jid == gajim.get_jid_from_account(account):
contact_iter = self._get_self_contact_iter(account, model)
if contact_iter:
return [contact_iter]
else:
return []
if not contact: if not contact:
contact = gajim.contacts.get_first_contact_from_jid(account, jid) contact = gajim.contacts.get_first_contact_from_jid(account, jid)
if not contact: if not contact:
# We don't know this contact # We don't know this contact
return [] return []
acct = self._get_account_iter(account, model) if jid not in self._iters[account]['contacts']:
found = [] # the contact iters. One per group return []
for group in contact.get_shown_groups():
group_iter = self._get_group_iter(group, account, acct, model)
contact_iter = model.iter_children(group_iter)
while contact_iter: its = self._iters[account]['contacts'][jid]
# Loop over all contacts in this group
iter_jid = model[contact_iter][C_JID] if not its:
if iter_jid and jid == iter_jid.decode('utf-8') and \ return []
account == model[contact_iter][C_ACCOUNT].decode('utf-8'):
# only one iter per group if model == self.model:
found.append(contact_iter) return its
contact_iter = None
elif model.iter_has_child(contact_iter): its2 = []
# it's a big brother and has children for it in its:
contact_iter = model.iter_children(contact_iter) try:
else: its2.append(self.modelfilter.convert_child_iter_to_iter(it))
# try to find next contact: except RuntimeError:
# other contact in this group or pass
# brother contact return its2
next_contact_iter = model.iter_next(contact_iter)
if next_contact_iter:
contact_iter = next_contact_iter
else:
# It's the last one.
# Go up if we are big brother
parent_iter = model.iter_parent(contact_iter)
if parent_iter and model[parent_iter][C_TYPE] == \
'contact':
contact_iter = model.iter_next(parent_iter)
else:
# we tested all
# contacts in this group
contact_iter = None
return found
def _iter_is_separator(self, model, titer): def _iter_is_separator(self, model, titer):
@ -278,10 +251,11 @@ class RosterWindow:
if self.regroup: if self.regroup:
# Merged accounts view # Merged accounts view
show = helpers.get_global_show() show = helpers.get_global_show()
self.model.append(None, [ it = self.model.append(None, [
gajim.interface.jabber_state_images['16'][show], gajim.interface.jabber_state_images['16'][show],
_('Merged accounts'), 'account', '', 'all', _('Merged accounts'), 'account', '', 'all', None, None, None,
None, None, None, None, None, None]) None, None, None])
self._iters['account'] = it
else: else:
show = gajim.SHOW_LIST[gajim.connections[account].connected] show = gajim.SHOW_LIST[gajim.connections[account].connected]
our_jid = gajim.get_jid_from_account(account) our_jid = gajim.get_jid_from_account(account)
@ -293,11 +267,11 @@ class RosterWindow:
gtk.STOCK_DIALOG_AUTHENTICATION, gtk.STOCK_DIALOG_AUTHENTICATION,
gtk.ICON_SIZE_MENU) gtk.ICON_SIZE_MENU)
self.model.append(None, [ it = self.model.append(None, [
gajim.interface.jabber_state_images['16'][show], gajim.interface.jabber_state_images['16'][show],
gobject.markup_escape_text(account), 'account', gobject.markup_escape_text(account), 'account', our_jid,
our_jid, account, None, None, None, None, None, account, None, None, None, None, None, tls_pixbuf])
tls_pixbuf]) self._iters[account]['account'] = it
self.draw_account(account) self.draw_account(account)
@ -362,13 +336,17 @@ class RosterWindow:
contact.get_shown_name(), 'contact', contact.jid, account, contact.get_shown_name(), 'contact', contact.jid, account,
None, None, None, None, None, None)) None, None, None, None, None, None))
added_iters.append(it) added_iters.append(it)
if contact.jid in self._iters[account]['contacts']:
self._iters[account]['contacts'][contact.jid].append(it)
else:
self._iters[account]['contacts'][contact.jid] = [it]
else: else:
# We are a normal contact. Add us to our groups. # We are a normal contact. Add us to our groups.
if not groups: if not groups:
groups = contact.get_shown_groups() groups = contact.get_shown_groups()
for group in groups: for group in groups:
child_iterG = self._get_group_iter(group, account, child_iterG = self._get_group_iter(group, account,
model = self.model) model=self.model)
if not child_iterG: if not child_iterG:
# Group is not yet in roster, add it! # Group is not yet in roster, add it!
child_iterA = self._get_account_iter(account, self.model) child_iterA = self._get_account_iter(account, self.model)
@ -378,6 +356,7 @@ class RosterWindow:
'group', group, account, None, None, None, None, None, 'group', group, account, None, None, None, None, None,
None]) None])
self.draw_group(group, account) self.draw_group(group, account)
self._iters[account]['groups'][group] = child_iterG
if contact.is_transport(): if contact.is_transport():
typestr = 'agent' typestr = 'agent'
@ -393,6 +372,10 @@ class RosterWindow:
contact.jid, account, None, None, None, contact.jid, account, None, None, None,
None, None, None)) None, None, None))
added_iters.append(i_) added_iters.append(i_)
if contact.jid in self._iters[account]['contacts']:
self._iters[account]['contacts'][contact.jid].append(i_)
else:
self._iters[account]['contacts'][contact.jid] = [i_]
# Restore the group expand state # Restore the group expand state
if account + group in self.collapsed_rows: if account + group in self.collapsed_rows:
@ -455,8 +438,10 @@ class RosterWindow:
if group in gajim.groups[account]: if group in gajim.groups[account]:
del gajim.groups[account][group] del gajim.groups[account][group]
self.model.remove(parent_i) self.model.remove(parent_i)
del self._iters[account]['groups'][group]
else: else:
self.model.remove(i) self.model.remove(i)
del self._iters[account]['contacts'][contact.jid]
return True return True
def _add_metacontact_family(self, family, account): def _add_metacontact_family(self, family, account):
@ -633,8 +618,9 @@ class RosterWindow:
self.model)) == 0, 'Self contact %s already in roster' % jid self.model)) == 0, 'Self contact %s already in roster' % jid
child_iterA = self._get_account_iter(account, self.model) child_iterA = self._get_account_iter(account, self.model)
self.model.append(child_iterA, (None, gajim.nicks[account], self._iters[account]['contacts'][jid] = [self.model.append(child_iterA,
'self_contact', jid, account, None, None, None, None, None, None)) (None, gajim.nicks[account], 'self_contact', jid, account, None,
None, None, None, None, None))]
self.draw_completely(jid, account) self.draw_completely(jid, account)
self.draw_account(account) self.draw_account(account)
@ -1398,7 +1384,9 @@ class RosterWindow:
self.on_modelfilter_row_has_child_toggled) self.on_modelfilter_row_has_child_toggled)
self.tree.set_model(self.modelfilter) self.tree.set_model(self.modelfilter)
self._iters = {}
for acct in gajim.contacts.get_accounts(): for acct in gajim.contacts.get_accounts():
self._iters[acct] = {'account': None, 'groups': {}, 'contacts': {}}
self.add_account(acct) self.add_account(acct)
self.add_account_contacts(acct) self.add_account_contacts(acct)
# Recalculate column width for ellipsizing # Recalculate column width for ellipsizing
@ -1729,6 +1717,8 @@ class RosterWindow:
# Most of the logic SHOULD NOT be done at GUI level # Most of the logic SHOULD NOT be done at GUI level
if account not in gajim.contacts.get_accounts(): if account not in gajim.contacts.get_accounts():
gajim.contacts.add_account(account) gajim.contacts.add_account(account)
self._iters[account] = {'account': None, 'groups': {},
'contacts': {}}
if account not in gajim.groups: if account not in gajim.groups:
gajim.groups[account] = {} gajim.groups[account] = {}
if gajim.config.get('show_self_contact') == 'always': if gajim.config.get('show_self_contact') == 'always':
@ -5854,6 +5844,7 @@ class RosterWindow:
# sel.connect('changed', # sel.connect('changed',
# self.on_treeview_selection_changed) # self.on_treeview_selection_changed)
self._iters = {}
# holds a list of (jid, account) tupples # holds a list of (jid, account) tupples
self._last_selected_contact = [] self._last_selected_contact = []
self.transports_state_images = {'16': {}, '32': {}, 'opened': {}, self.transports_state_images = {'16': {}, '32': {}, 'opened': {},