Improve the roster search
- now case-insensitive - search in the bare jid instead of userpart only (and still in roster names) - do not display groups when searching - display offline contacts - do not expand resources if they were before the search
This commit is contained in:
parent
2b4c06b6f8
commit
833faa4f37
3 changed files with 72 additions and 53 deletions
|
@ -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'
|
||||
|
|
14
src/tabs.py
14
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):
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
|
Loading…
Reference in a new issue