diff --git a/src/roster.py b/src/roster.py index 5ddbdbb2..8c1b8f3e 100644 --- a/src/roster.py +++ b/src/roster.py @@ -115,8 +115,6 @@ class Roster(object): key=lambda x: x.name.lower() if x.name else '' ) - log.debug("Current groups: %s", group_list) - for sorting in sort.split(':'): if sorting == 'reverse': group_list = list(reversed(group_list)) @@ -145,6 +143,28 @@ class Roster(object): """ return [self[jid] for jid in self.jids()] + def get_contacts_sorted_filtered(self, sort=''): + """ + Return a list of all the contacts sorted with a criteria + """ + contact_list = [] + for contact in self.get_contacts(): + if contact.bare_jid != self.jid: + if self.contact_filter: + if self.contact_filter[0](contact, self.contact_filter[1]): + contact_list.append(contact) + else: + contact_list.append(contact) + contact_list = sorted(contact_list, key=SORTING_METHODS['name']) + + for sorting in sort.split(':'): + if sorting == 'reverse': + contact_list = list(reversed(contact_list)) + else: + method = SORTING_METHODS.get(sorting, lambda x: 0) + contact_list = sorted(contact_list, key=method) + return contact_list + def save_to_config_file(self): """ Save various information to the config file @@ -184,28 +204,11 @@ class Roster(object): def __len__(self): """ - Return the number of line that would be printed - for the whole roster + Return the number of contacts + (used to return the display size, but now we have + the display cache in RosterWin for that) """ - length = 0 - show_offline = config.get('roster_show_offline', 'false') == 'true' - for group in self.groups.values(): - if not show_offline and group.get_nb_connected_contacts() == 0: - continue - before = length - if not group.name in self.folded_groups: - for contact in group.get_contacts(self.contact_filter): - # We do not count the offline contacts (depending on config) - if not show_offline and\ - len(contact) == 0: - continue - length += 1 # One for the contact's line - if not contact.folded(group.name): - # One for each resource, if the contact is unfolded - length += len(contact) - if not self.contact_filter or before != length: - length += 1 # One for the group's line itself if needed - return length + return len(self.contacts) def __repr__(self): ret = '== Roster:\nContacts:\n' diff --git a/src/tabs.py b/src/tabs.py index c0a34f29..fb6b393b 100644 --- a/src/tabs.py +++ b/src/tabs.py @@ -3012,6 +3012,8 @@ class RosterInfoTab(Tab): self.input = windows.CommandInput("[Search]", self.on_search_terminate, self.on_search_terminate, self.set_roster_filter) self.input.resize(1, self.width, self.height-1, 0) self.input.disable_history() + roster.modified() + self.refresh() return True @refresh_wrapper.always @@ -3024,11 +3026,13 @@ class RosterInfoTab(Tab): def set_roster_filter_slow(self, txt): roster.contact_filter = (jid_and_name_match_slow, txt) + roster.modified() self.refresh() return False def set_roster_filter(self, txt): roster.contact_filter = (jid_and_name_match, txt) + roster.modified() self.refresh() return False @@ -3037,6 +3041,7 @@ class RosterInfoTab(Tab): curses.curs_set(0) roster.contact_filter = None self.reset_help_message() + roster.modified() return False def on_close(self): @@ -3851,12 +3856,12 @@ def jid_and_name_match(contact, txt): """ Match jid with text precisely """ - roster.modified() if not txt: return True - if txt in safeJID(contact.bare_jid).user: + txt = txt.lower() + if txt in safeJID(contact.bare_jid).bare.lower(): return True - if txt in contact.name: + if txt in contact.name.lower(): return True return False @@ -3865,10 +3870,9 @@ def jid_and_name_match_slow(contact, txt): A function used to know if a contact in the roster should be shown in the roster """ - roster.modified() if not txt: return True # Everything matches when search is empty - user = safeJID(contact.bare_jid).user + user = safeJID(contact.bare_jid).bare if diffmatch(txt, user): return True if contact.name and diffmatch(txt, contact.name): diff --git a/src/windows.py b/src/windows.py index 66b52f1d..bd348859 100644 --- a/src/windows.py +++ b/src/windows.py @@ -1742,10 +1742,13 @@ class RosterWin(Win): Win.__init__(self) self.pos = 0 # cursor position in the contact list self.start_pos = 1 # position of the start of the display - self.roster_len = 0 self.selected_row = None self.roster_cache = [] + @property + def roster_len(self): + return len(self.roster_cache) + def move_cursor_down(self, number=1): """ Return True if we scrolled, False otherwise @@ -1809,28 +1812,36 @@ class RosterWin(Win): 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 + # This is a search + if roster.contact_filter: + self.roster_cache = [] + sort = config.get('roster_sort', 'jid:show') or 'jid:show' + for contact in roster.get_contacts_sorted_filtered(sort): self.roster_cache.append(contact) - if not contact.folded(group.name): - for resource in contact.get_resources(): - self.roster_cache.append(resource) + else: + show_offline = config.get('roster_show_offline', 'false') == 'true' or roster.contact_filter + 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) roster.last_built = datetime.now() if self.selected_row in self.roster_cache: - self.pos = self.roster_cache.index(self.selected_row) + if self.pos < self.roster_len and self.roster_cache[self.pos] != self.selected_row: + self.pos = self.roster_cache.index(self.selected_row) def refresh(self, roster): """ @@ -1840,16 +1851,17 @@ class RosterWin(Win): log.debug('Refresh: %s',self.__class__.__name__) 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) + # make sure we are within bounds + 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) y = 1 group = "none" + # scroll down if needed + if self.start_pos+self.height <= self.pos+2: + self.scroll_down(self.pos - self.start_pos - self.height + (self.height//2)) # draw the roster from the cache - if self.start_pos+self.height < self.pos: - self.start_pos = self.pos - (self.height//2) for item in self.roster_cache[self.start_pos-1:self.start_pos+self.height]: draw_selected = False @@ -1887,7 +1899,7 @@ class RosterWin(Win): """ self.addstr('Roster: %s/%s contacts' % ( roster.get_nb_connected_contacts(), - len(roster.contacts)) + len(roster)) ,to_curses_attr(get_theme().COLOR_INFORMATION_BAR)) self.finish_line(get_theme().COLOR_INFORMATION_BAR)