changeset fbc39b6087e0 in /home/hg/repos/gajim
details:http://hg.gajim.org/gajim?cmd=changeset;node=fbc39b6087e0 description: handle nested roster group. TODO: Improve the way it's displayed in roster. Fixes #1381
diffstat:
src/common/connection.py | 44 ++++++++ src/common/connection_handlers.py | 28 ++-- src/roster_window.py | 191 +++++++++++++++++++++++++++---------- 3 files changed, 197 insertions(+), 66 deletions(-)
diffs (truncated from 463 to 300 lines):
diff -r 53b97cb41c61 -r fbc39b6087e0 src/common/connection.py --- a/src/common/connection.py Sat Dec 11 12:15:55 2010 +0300 +++ b/src/common/connection.py Sat Dec 11 12:57:09 2010 +0100 @@ -161,6 +161,8 @@
self.awaiting_cids = {} # Used for XEP-0231
+ self.nested_group_delimiter = '::' + self.get_config_values_or_default()
def _compute_resource(self): @@ -2103,6 +2105,32 @@ iq4.setData(self.annotations[jid]) self.connection.send(iq)
+ def get_roster_delimiter(self): + """ + Get roster group delimiter from storage as described in XEP 0083 + """ + if not gajim.account_is_connected(self.name): + return + iq = common.xmpp.Iq(typ='get') + iq2 = iq.addChild(name='query', namespace=common.xmpp.NS_PRIVATE) + iq2.addChild(name='roster', namespace='roster:delimiter') + id_ = self.connection.getAnID() + iq.setID(id_) + self.awaiting_answers[id_] = (DELIMITER_ARRIVED, ) + self.connection.send(iq) + + def set_roster_delimiter(self, delimiter='::'): + """ + Set roster group delimiter to the storage namespace + """ + if not gajim.account_is_connected(self.name): + return + iq = common.xmpp.Iq(typ='set') + iq2 = iq.addChild(name='query', namespace=common.xmpp.NS_PRIVATE) + iq3 = iq2.addChild(name='roster', namespace='roster:delimiter') + iq3.setData(delimiter) + + self.connection.send(iq)
def get_metacontacts(self): """ @@ -2136,6 +2164,22 @@ iq3.addChild(name = 'meta', attrs = dict_) self.connection.send(iq)
+ def request_roster(self): + version = None + features = self.connection.Dispatcher.Stream.features + if features and features.getTag('ver', + namespace=common.xmpp.NS_ROSTER_VER): + version = gajim.config.get_per('accounts', self.name, + 'roster_version') + if version and not gajim.contacts.get_contacts_jid_list( + self.name): + gajim.config.set_per('accounts', self.name, 'roster_version', + '') + version = None + + iq_id = self.connection.initRoster(version=version) + self.awaiting_answers[iq_id] = (ROSTER_ARRIVED, ) + def send_agent_status(self, agent, ptype): if not gajim.account_is_connected(self.name): return diff -r 53b97cb41c61 -r fbc39b6087e0 src/common/connection_handlers.py --- a/src/common/connection_handlers.py Sat Dec 11 12:15:55 2010 +0300 +++ b/src/common/connection_handlers.py Sat Dec 11 12:57:09 2010 +0100 @@ -84,6 +84,7 @@ AGENT_REMOVED = 'agent_removed' METACONTACTS_ARRIVED = 'metacontacts_arrived' ROSTER_ARRIVED = 'roster_arrived' +DELIMITER_ARRIVED = 'delimiter_arrived' PRIVACY_ARRIVED = 'privacy_arrived' PEP_CONFIG = 'pep_config' HAS_IDLE = True @@ -525,21 +526,22 @@ else: if iq_obj.getErrorCode() not in ('403', '406', '404'): self.private_storage_supported = False + self.get_roster_delimiter() + elif self.awaiting_answers[id_][0] == DELIMITER_ARRIVED: + if not self.connection: + return + if iq_obj.getType() == 'result': + query = iq_obj.getTag('query') + delimiter = query.getTagData('roster') + if delimiter: + self.nested_group_delimiter = delimiter + else: + self.set_roster_delimiter('::') + else: + self.private_storage_supported = False
# We can now continue connection by requesting the roster - version = None - if con.Stream.features and con.Stream.features.getTag('ver', - namespace=common.xmpp.NS_ROSTER_VER): - version = gajim.config.get_per('accounts', self.name, - 'roster_version') - if version and not gajim.contacts.get_contacts_jid_list( - self.name): - gajim.config.set_per('accounts', self.name, - 'roster_version', '') - version = None - - iq_id = self.connection.initRoster(version=version) - self.awaiting_answers[iq_id] = (ROSTER_ARRIVED, ) + self.request_roster() elif self.awaiting_answers[id_][0] == ROSTER_ARRIVED: if iq_obj.getType() == 'result': if not iq_obj.getTag('query'): diff -r 53b97cb41c61 -r fbc39b6087e0 src/roster_window.py --- a/src/roster_window.py Sat Dec 11 12:15:55 2010 +0300 +++ b/src/roster_window.py Sat Dec 11 12:57:09 2010 +0100 @@ -284,6 +284,36 @@
self.starting = False
+ def _add_group_iter(self, account, group): + """ + Add a group iter in roster and return the newly created iter + """ + if self.regroup: + account_group = 'MERGED' + else: + account_group = account + delimiter = gajim.connections[account].nested_group_delimiter + group_splited = group.split(delimiter) + parent_group = delimiter.join(group_splited[:-1]) + if parent_group in self._iters[account_group]['groups']: + iter_parent = self._iters[account_group]['groups'][parent_group] + elif parent_group: + iter_parent = self._add_group_iter(account, parent_group) + if parent_group not in gajim.groups[account]: + if account + parent_group in self.collapsed_rows: + is_expanded = False + else: + is_expanded = True + gajim.groups[account][parent_group] = {'expand': is_expanded} + else: + iter_parent = self._get_account_iter(account, self.model) + iter_group = self.model.append(iter_parent, + [gajim.interface.jabber_state_images['16']['closed'], + gobject.markup_escape_text(group), 'group', group, account, None, + None, None, None, None, None] + [None] * self.nb_ext_renderers) + self.draw_group(group, account) + self._iters[account_group]['groups'][group] = iter_group + return iter_group
def _add_entity(self, contact, account, groups=None, big_brother_contact=None, big_brother_account=None): @@ -328,23 +358,12 @@ # We are a normal contact. Add us to our groups. if not groups: groups = contact.get_shown_groups() - if self.regroup: - account_group = 'MERGED' - else: - account_group = account for group in groups: child_iterG = self._get_group_iter(group, account, model=self.model) if not child_iterG: # Group is not yet in roster, add it! - child_iterA = self._get_account_iter(account, self.model) - child_iterG = self.model.append(child_iterA, - [gajim.interface.jabber_state_images['16']['closed'], - gobject.markup_escape_text(group), - 'group', group, account, None, None, None, None, None, - None] + [None] * self.nb_ext_renderers) - self.draw_group(group, account) - self._iters[account_group]['groups'][group] = child_iterG + child_iterG = self._add_group_iter(account, group)
if contact.is_transport(): typestr = 'agent' @@ -419,8 +438,10 @@ "Invalidated iters of %s" % contact.jid
parent_i = self.model.iter_parent(i) - - if parent_type == 'group' and \ + parent_type = self.model[parent_i][C_TYPE] + + to_be_removed = i + while parent_type == 'group' and \ self.model.iter_n_children(parent_i) == 1: if self.regroup: account_group = 'MERGED' @@ -429,10 +450,12 @@ group = self.model[parent_i][C_JID].decode('utf-8') if group in gajim.groups[account]: del gajim.groups[account][group] - self.model.remove(parent_i) + to_be_removed = parent_i del self._iters[account_group]['groups'][group] - else: - self.model.remove(i) + parent_i = self.model.iter_parent(parent_i) + parent_type = self.model[parent_i][C_TYPE] + self.model.remove(to_be_removed) + del self._iters[account]['contacts'][contact.jid] return True
@@ -1248,13 +1271,19 @@ if family and not is_big_brother and not self.starting: self.draw_parent_contact(jid, account)
+ delimiter = gajim.connections[account].nested_group_delimiter for group in contact.get_shown_groups(): # We need to make sure that _visible_func is called for # our groups otherwise we might not be shown - iterG = self._get_group_iter(group, account, model=self.model) - if iterG: - # it's not self contact - self.model[iterG][C_JID] = self.model[iterG][C_JID] + group_splited = group.split(delimiter) + i = 1 + while i < len(group_splited) + 1: + g = delimiter.join(group_splited[:i]) + iterG = self._get_group_iter(g, account, model=self.model) + if iterG: + # it's not self contact + self.model[iterG][C_JID] = self.model[iterG][C_JID] + i += 1
gajim.plugin_manager.gui_extension_point('roster_draw_contact', self, jid, account, contact) @@ -1446,16 +1475,21 @@ """ if not self.tree.get_model(): return - iterG = self._get_group_iter(group, account) - if not iterG: - # Group not visible - return - path = self.modelfilter.get_path(iterG) - if account + group in self.collapsed_rows: - self.tree.collapse_row(path) - else: - self.tree.expand_row(path, False) - return False + delimiter = gajim.connections[account].nested_group_delimiter + group_splited = group.split(delimiter) + i = 1 + while i < len(group_splited) + 1: + g = delimiter.join(group_splited[:i]) + iterG = self._get_group_iter(g, account) + if not iterG: + # Group not visible + return + path = self.modelfilter.get_path(iterG) + if account + g in self.collapsed_rows: + self.tree.collapse_row(path) + else: + self.tree.expand_row(path, False) + i += 1
############################################################################## ### Roster and Modelfilter handling @@ -1544,11 +1578,16 @@ else: accounts = [account] for _acc in accounts: + delimiter = gajim.connections[_acc].nested_group_delimiter for contact in gajim.contacts.iter_contacts(_acc): + if not self.contact_is_visible(contact, _acc): + continue # Is this contact in this group? - if group in contact.get_shown_groups(): - if self.contact_is_visible(contact, _acc): - return True + for grp in contact.get_shown_groups(): + while grp: + if group == grp: + return True + grp = delimiter.join(grp.split(delimiter)[:-1]) return False if type_ == 'contact': if gajim.config.get('showoffline'): @@ -2101,7 +2140,7 @@ ctrl = gajim.interface.msg_win_mgr.get_control(contact.jid, account) if ctrl and ctrl.type_id != message_control.TYPE_GC: ctrl.contact = gajim.contacts.get_contact_with_highest_priority( - account, contact.jid) + account, contact.jid) ctrl.update_status_display(name, uf_show, status)
if contact.resource: @@ -2111,7 +2150,7 @@
# Delete pep if needed keep_pep = any(c.show not in ('error', 'offline') for c in - contact_instances) + contact_instances)