summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/core.py18
-rw-r--r--src/roster.py12
-rw-r--r--src/windows.py53
3 files changed, 61 insertions, 22 deletions
diff --git a/src/core.py b/src/core.py
index 1d946df3..4c1566bd 100644
--- a/src/core.py
+++ b/src/core.py
@@ -152,6 +152,7 @@ class Core(object):
self.plugin_manager = PluginManager(self)
self.events = events.EventHandler()
+
# global commands, available from all tabs
# a command is tuple of the form:
# (the function executing the command. Takes a string as argument,
@@ -298,6 +299,8 @@ class Core(object):
log.debug("Reloading the config…")
config.__init__(config.file_name)
log.debug("Config reloaded.")
+ # in case some roster options have changed
+ roster.modified()
def exit_from_signal(self, *args, **kwargs):
"""
@@ -2060,6 +2063,8 @@ class Core(object):
elif option == 'plugins_conf_dir':
path = os.path.expanduser(value)
self.plugin_manager.on_plugins_conf_dir_change(path)
+ # in case some roster options have changed
+ roster.modified()
self.call_for_resize()
self.information(*info)
@@ -2791,6 +2796,7 @@ class Core(object):
contact = roster[message['from'].bare]
if not contact:
return
+ roster.modified()
item = message['pubsub_event']['items']['item']
old_mood = contact.mood
if item.xml.find('{http://jabber.org/protocol/mood}mood'):
@@ -2820,6 +2826,7 @@ class Core(object):
contact = roster[message['from'].bare]
if not contact:
return
+ roster.modified()
item = message['pubsub_event']['items']['item']
old_activity = contact.activity
if item.xml.find('{http://jabber.org/protocol/activity}activity'):
@@ -2855,6 +2862,7 @@ class Core(object):
contact = roster[message['from'].bare]
if not contact:
return
+ roster.modified()
item = message['pubsub_event']['items']['item']
old_tune = contact.tune
if item.xml.find('{http://jabber.org/protocol/tune}tune'):
@@ -3085,6 +3093,7 @@ class Core(object):
contact.pending_in = True
self.information('%s wants to subscribe to your presence' % jid, 'Roster')
self.get_tab_by_number(0).state = 'highlight'
+ roster.modified()
if isinstance(self.current_tab(), tabs.RosterInfoTab):
self.refresh_window()
@@ -3096,6 +3105,9 @@ class Core(object):
self.information('%s accepted your contact proposal' % jid, 'Roster')
if contact.pending_out:
contact.pending_out = False
+
+ roster.modified()
+
if isinstance(self.current_tab(), tabs.RosterInfoTab):
self.refresh_window()
@@ -3105,6 +3117,7 @@ class Core(object):
contact = roster[jid]
if not contact:
return
+ roster.modified()
self.information('%s does not want to receive your status anymore.' % jid, 'Roster')
self.get_tab_by_number(0).state = 'highlight'
if isinstance(self.current_tab(), tabs.RosterInfoTab):
@@ -3116,6 +3129,7 @@ class Core(object):
contact = roster[jid]
if not contact:
return
+ roster.modified()
if contact.pending_out:
self.information('%s rejected your contact proposal' % jid, 'Roster')
contact.pending_out = False
@@ -3137,6 +3151,7 @@ class Core(object):
tab.unlock()
if contact is None:
return
+ roster.modified()
contact.error = None
self.events.trigger('normal_presence', presence, contact[jid.full])
tab = self.get_conversation_by_jid(jid, create=False)
@@ -3151,6 +3166,7 @@ class Core(object):
contact = roster[jid.bare]
if not contact:
return
+ roster.modified()
contact.error = presence['error']['type'] + ': ' + presence['error']['condition']
def on_got_offline(self, presence):
@@ -3168,6 +3184,7 @@ class Core(object):
self.add_information_message_to_conversation_tab(jid.full, '\x195}%s is \x191}offline' % (jid.full))
self.add_information_message_to_conversation_tab(jid.bare, '\x195}%s is \x191}offline' % (jid.bare))
self.information('\x193}%s \x195}is \x191}offline' % (jid.bare), 'Roster')
+ roster.modified()
if isinstance(self.current_tab(), tabs.RosterInfoTab):
self.refresh_window()
@@ -3182,6 +3199,7 @@ class Core(object):
if contact is None:
# Todo, handle presence coming from contacts not in roster
return
+ roster.modified()
if not logger.log_roster_change(jid.bare, 'got online'):
self.information(_('Unable to write in the log file'), 'Error')
resource = Resource(jid.full, {
diff --git a/src/roster.py b/src/roster.py
index b0f3cf65..5ddbdbb2 100644
--- a/src/roster.py
+++ b/src/roster.py
@@ -17,6 +17,7 @@ from contact import Contact
from roster_sorting import SORTING_METHODS, GROUP_SORTING_METHODS
from os import path as p
+from datetime import datetime
from common import safeJID
from sleekxmpp import JID
from sleekxmpp.exceptions import IqError, IqTimeout
@@ -43,6 +44,17 @@ class Roster(object):
self.groups = {}
self.contacts = {}
+ # Used for caching roster infos
+ self.last_built = datetime.now()
+ self.last_modified = datetime.now()
+
+ def modified(self):
+ self.last_modified = datetime.now()
+
+ @property
+ def needs_rebuild(self):
+ return self.last_modified >= self.last_built
+
def __getitem__(self, key):
"""Get a Contact from his bare JID"""
key = safeJID(key).bare
diff --git a/src/windows.py b/src/windows.py
index 49e76ff5..0040ee0c 100644
--- a/src/windows.py
+++ b/src/windows.py
@@ -1830,34 +1830,43 @@ class RosterWin(Win):
self.start_pos = 1
return self.start_pos != pos
+ def build_roster_cache(self, roster):
+ """
+ Regenerates the roster cache if needed
+ """
+ with g_lock:
+ if roster.needs_rebuild:
+ log.debug('The roster has changed, rebuilding the cache…')
+ show_offline = config.get('roster_show_offline', 'false') == 'true'
+ sort = config.get('roster_sort', 'jid:show') or 'jid:show'
+ group_sort = config.get('roster_group_sort', 'name') or 'name'
+ self.roster_cache = []
+ # build the cache
+ for group in roster.get_groups(group_sort):
+ contacts_filtered = group.get_contacts(roster.contact_filter)
+ if (not show_offline and group.get_nb_connected_contacts() == 0) or not contacts_filtered:
+ continue # Ignore empty groups
+ self.roster_cache.append(group)
+ if group.folded:
+ continue # ignore folded groups
+ for contact in group.get_contacts(roster.contact_filter, sort):
+ if not show_offline and len(contact) == 0:
+ continue # ignore offline contacts
+ self.roster_cache.append(contact)
+ if not contact.folded(group.name):
+ for resource in contact.get_resources():
+ self.roster_cache.append(resource)
+
def refresh(self, roster):
"""
- We get the roster object
+ We display a number of lines from the roster cache
+ (and rebuild it if needed)
"""
log.debug('Refresh: %s',self.__class__.__name__)
- self.roster_cache = []
- show_offline = config.get('roster_show_offline', 'false') == 'true'
- sort = config.get('roster_sort', 'jid:show') or 'jid:show'
- group_sort = config.get('roster_group_sort', 'name') or 'name'
- # build the cache
- for group in roster.get_groups(group_sort):
- contacts_filtered = group.get_contacts(roster.contact_filter)
- if (not show_offline and group.get_nb_connected_contacts() == 0) or not contacts_filtered:
- continue # Ignore empty groups
- self.roster_cache.append(group)
- if group.folded:
- continue # ignore folded groups
- for contact in group.get_contacts(roster.contact_filter, sort):
- if not show_offline and len(contact) == 0:
- continue # ignore offline contacts
- self.roster_cache.append(contact)
- if not contact.folded(group.name):
- for resource in contact.get_resources():
- self.roster_cache.append(resource)
-
+ self.build_roster_cache(roster)
with g_lock:
self.roster_len = len(roster);
- self.move_cursor_up(self.roster_len - self.pos if self.pos >= self.roster_len else 0)
+ self.move_cursor_up(self.roster_len + self.pos if self.pos >= self.roster_len else 0)
self._win.erase()
self._win.move(0, 0)
self.draw_roster_information(roster)