# HG changeset patch # User souliane # Date 1427099746 -3600 # Node ID 3845a086f0b3917cbbfe763762e794875777025a # Parent 90a5a5af2550ff6434e822a24c1dd9139e2da8ca browser_side: update ContactList, Chat, ContactsPanel, ContactBox, ContactLabel to update the display using listeners as it is done in quick_frontend: - Chat uses presence and avatar listener, remove unecessary methods for MUC and contact states - contact list doesn't add unecessary ContactBox (e.g for MUC bare entities) - nick, message alerts are handled directly in ContactLabel diff -r 90a5a5af2550 -r 3845a086f0b3 src/browser/libervia_main.py --- a/src/browser/libervia_main.py Fri Mar 27 00:15:42 2015 +0100 +++ b/src/browser/libervia_main.py Mon Mar 23 09:35:46 2015 +0100 @@ -943,7 +943,7 @@ _dialog.show() def _contactDeletedCb(self, entity): - self.contact_panel.removeContact(entity) + self.contact_panel.removeContactBox(entity) def _newContactCb(self, contact_jid, attributes, groups): self.contact_panel.updateContact(contact_jid, attributes, groups) diff -r 90a5a5af2550 -r 3845a086f0b3 src/browser/sat_browser/chat.py --- a/src/browser/sat_browser/chat.py Fri Mar 27 00:15:42 2015 +0100 +++ b/src/browser/sat_browser/chat.py Mon Mar 23 09:35:46 2015 +0100 @@ -105,6 +105,9 @@ # FIXME: workaround for a pyjamas issue: calling hash on a class method always return a different value if that method is defined directly within the class (with the "def" keyword) self.presenceListener = self.onPresenceUpdate self.host.addListener('presence', self.presenceListener, [C.PROF_KEY_NONE]) + self.avatarListener = self.onAvatarUpdate + host.addListener('avatar', self.avatarListener, [C.PROF_KEY_NONE]) + self._body.add(chat_area) self.content = AbsolutePanel() self.content.setStyleName('chatContent') @@ -150,7 +153,7 @@ # _new_panel.refresh() # return _new_panel - def refresh(self): + def refresh(self): # FIXME: not needed anymore since unibox has been removed """Refresh the display of this widget. If the unibox is disabled, add a message box at the bottom of the panel""" # FIXME: must be checked @@ -200,8 +203,21 @@ @param profile: %(doc_profile)s """ assert self.type == C.CHAT_GROUP - if entity.bare == self.target: - self.occupants_panel.setPresence(entity, show) + if entity.bare != self.target: + return + self.update(entity) + + def onAvatarUpdate(self, entity, hash_, profile): + """Called on avatar update events + + @param jid_: jid of the entity with updated avatar + @param hash_: hash of the avatar + @param profile: %(doc_profile)s + """ + assert self.type == C.CHAT_GROUP + if entity.bare != self.target: + return + self.update(entity) def onQuit(self): libervia_widget.LiberviaWidget.onQuit(self) @@ -209,28 +225,6 @@ self.host.removeListener('presence', self.presenceListener) self.host.bridge.call('mucLeave', None, unicode(self.target.bare)) - def setUserNick(self, nick): - """Set the nick of the user, usefull for e.g. change the color of the user""" - self.nick = nick - - def addUser(self, nick): - """Add user if it is not in the group list""" - QuickChat.addUser(self, nick) - occupant_jid = jid.JID("%s/%s" % (unicode(self.target), nick)) - self.occupants_panel.addContact(occupant_jid) - - def removeUser(self, nick): - """Remove a user from the group list""" - QuickChat.removeUser(self, nick) - occupant_jid = jid.JID("%s/%s" % (unicode(self.target), nick)) - self.occupants_panel.removeContact(occupant_jid) - - def changeUserNick(self, old_nick, new_nick): - assert self.type == C.CHAT_GROUP - # self.occupants_panel.removeOccupant(old_nick) - # self.occupants_panel.addOccupant(new_nick) - self.printInfo(_("%(old_nick)s is now known as %(new_nick)s") % {'old_nick': old_nick, 'new_nick': new_nick}) - # def historyPrint(self, size=C.HISTORY_LIMIT_DEFAULT): # """Print the initial history""" # def getHistoryCB(history): @@ -289,44 +283,36 @@ """Refresh the title of this Chat dialog @param title (unicode): main title or None to use default - @param extra (dict{unicode: unicode}): extra info + @param suffix (unicode): extra title (e.g. for chat states) or None """ if title is None: title = unicode(self.target.bare) if extra: - extra_title = ' '.join([u'({})'.format(value) for value in extra.values()]) - title = '%s %s' % (title, extra_title) + title += ' %s' % extra libervia_widget.LiberviaWidget.setTitle(self, title) - def setConnected(self, jid_s, resource, availability, priority, statuses): - """Set connection status - @param jid_s (unicode): JID userhost as unicode - """ - raise Exception("should not be there") # FIXME - assert(jid_s == self.target.bare) - if self.type != C.CHAT_GROUP: - return - box = self.occupants_panel.getOccupantBox(resource) - if box: - html_tools.setPresenceStyle(box, availability) - - def setOccupantStates(self, occupant_jid, states): - """Set a MUC occupant's states. + def update(self, entity=None): + """Update one or all entities. - @param occupant_jid (jid.JID): occupant to update - @param states (dict{unicode: unicode}): new states + @param entity (jid.JID): entity to update """ - self.occupants_panel.getContactBox(occupant_jid).updateStates(states) - if 'chat_state' in states.keys(): # start/stop sending "composing" state from now - self.chat_state_machine.started = not not states['chat_state'] + states = self.getEntityStates(self.target) + if self.type == C.CHAT_ONE2ONE: # only update the chat title + self.setTitle(extra=' '.join([u'({})'.format(value) for value in states.values()])) + else: + if entity is None: # rebuild all the occupants list + nicks = list(self.occupants) + nicks.sort() + self.occupants_panel.setList([jid.newResource(self.target, nick) for nick in nicks]) + else: # add, remove or update only one occupant + contact_list = self.host.contact_lists[self.profile] + show = contact_list.getCache(entity, C.PRESENCE_SHOW) + if show == C.PRESENCE_UNAVAILABLE or show is None: + self.occupants_panel.removeContactBox(entity) + else: + box = self.occupants_panel.updateContactBox(entity) + box.states.setHTML(u''.join(states.values())) - def setContactStates(self, contact_jid, states): - """Set a one2one contact's states. - - @param contact_jid (jid.JID): contact - @param states (dict{unicode: unicode}): new states - """ - self.setTitle(extra=states) if 'chat_state' in states.keys(): # start/stop sending "composing" state from now self.chat_state_machine.started = not not states['chat_state'] diff -r 90a5a5af2550 -r 3845a086f0b3 src/browser/sat_browser/contact_group.py --- a/src/browser/sat_browser/contact_group.py Fri Mar 27 00:15:42 2015 +0100 +++ b/src/browser/sat_browser/contact_group.py Mon Mar 23 09:35:46 2015 +0100 @@ -224,12 +224,12 @@ contacts = self.all_contacts for contact in contacts: if self.toggle.showAll: - self.contacts.getContactBox(contact).setVisible(True) + self.contacts.updateContactBox(contact).setVisible(True) else: if contact in self.groups.items_remaining: - self.contacts.getContactBox(contact).setVisible(True) + self.contacts.updateContactBox(contact).setVisible(True) else: - self.contacts.getContactBox(contact).setVisible(False) + self.contacts.updateContactBox(contact).setVisible(False) def __close(self): """Remove the widget from parent or close the popup.""" diff -r 90a5a5af2550 -r 3845a086f0b3 src/browser/sat_browser/contact_list.py --- a/src/browser/sat_browser/contact_list.py Fri Mar 27 00:15:42 2015 +0100 +++ b/src/browser/sat_browser/contact_list.py Mon Mar 23 09:35:46 2015 +0100 @@ -176,9 +176,6 @@ self._contacts_panel.setList(to_show) - for jid_ in self._alerts: - self._contacts_panel.getContactBox(jid_).setAlert(True) - def remove(self, entity): # FIXME: SimplePanel and QuickContactList both have a 'remove' method QuickContactList.remove(self, entity) @@ -339,10 +336,14 @@ @param hash_: hash of the avatar @param profile: %(doc_profile)s """ - self._contacts_panel.updateAvatar(jid_, self.host.getAvatarURL(jid_)) + box = self._contacts_panel.getContactBox(jid_) + if box: + box.update() def onNickUpdate(self, jid_, new_nick, profile): - self._contacts_panel.updateNick(jid_, new_nick) + box = self._contacts_panel.getContactBox(jid_) + if box: + box.update() def hasVisibleMembers(self, group): """Tell if the given group actually has visible members @@ -352,7 +353,7 @@ """ raise Exception # FIXME: remove this method for jid_ in self.groups[group]: - if self._contacts_panel.getContactBox(jid_).isVisible(): + if self._contacts_panel.updateContactBox(jid_).isVisible(): return True return False @@ -372,7 +373,9 @@ def onPresenceUpdate(self, entity, show, priority, statuses, profile): QuickContactList.onPresenceUpdate(self, entity, show, priority, statuses, profile) - self._contacts_panel.setPresence(entity, show) + box = self._contacts_panel.getContactBox(entity) + if box: # box doesn't exist for MUC bare entity, don't create it + box.update() # def updateVisibility(self, jids, groups): # """Set the widgets visibility for the given contacts and groups diff -r 90a5a5af2550 -r 3845a086f0b3 src/browser/sat_browser/contact_panel.py --- a/src/browser/sat_browser/contact_panel.py Fri Mar 27 00:15:42 2015 +0100 +++ b/src/browser/sat_browser/contact_panel.py Mon Mar 23 09:35:46 2015 +0100 @@ -92,66 +92,43 @@ self.clear() for contact_jid in jids: assert isinstance(contact_jid, jid.JID) - self.addContact(contact_jid) + self.updateContactBox(contact_jid) def getContactBox(self, contact_jid): - """Get a contact box for a contact, add it if it doesn't exist yet. + """Get the contact box for the given contact. + + @param contact_jid (jid.JID): contact JID + @return: ContactBox or None + """ + try: + return self._contacts[self._key(contact_jid)] + except KeyError: + return None + + def updateContactBox(self, contact_jid): + """Add a contact or update it if it already exists. @param contact_jid (jid.JID): contact JID @return: ContactBox """ - try: - return self._contacts[self._key(contact_jid)] - except KeyError: - box = contact_widget.ContactBox(self.host, contact_jid, + box = self.getContactBox(contact_jid) + if box: + box.update() + else: + entity = contact_jid.bare if self.merge_resources else contact_jid + box = contact_widget.ContactBox(self.host, entity, style_name=self.contacts_style, display=self.contacts_display, plugin_menu_context=self.contacts_menus) self._contacts[self._key(contact_jid)] = box - return box - - def addContact(self, contact_jid): - """Add a contact to the list. + VerticalPanel.append(self, box) + return box - @param contact_jid (jid.JID): contact JID - """ - box = self.getContactBox(contact_jid) - if box not in self.children: - VerticalPanel.append(self, box) - - def removeContact(self, contact_jid): - """Remove a contact from the list. + def removeContactBox(self, contact_jid): + """Remove a contact. @param contact_jid (jid.JID): contact JID """ - box = self._contacts.pop(self._key(contact_jid)) - VerticalPanel.remove(self, box) - - def updateAvatar(self, contact_jid, url): - """Update the avatar of the given contact - - @param contact_jid (jid.JID): contact JID - @param url (unicode): image url - """ - self.getContactBox(contact_jid).updateAvatar(url) - - def updateNick(self, contact_jid, new_nick): - """Update the avatar of the given contact. - - @param contact_jid (jid.JID): contact JID - @param new_nick (unicode): new nick of the contact - """ - self.getContactBox(contact_jid).updateNick(new_nick) - - def setPresence(self, entity, show): - """Update entity's presence. - - @param entity(jid.JID): entity updated - @param show: availability - """ - if self.merge_resources: # we use cache to have the show information of main resource only - clist = self.host.contact_list - show = clist.getCache(entity.bare, C.PRESENCE_SHOW) - if show is None: - show = C.PRESENCE_UNAVAILABLE - html_tools.setPresenceStyle(self.getContactBox(entity).label, show) + box = self._contacts.pop(self._key(contact_jid), None) + if box: + VerticalPanel.remove(self, box) diff -r 90a5a5af2550 -r 3845a086f0b3 src/browser/sat_browser/contact_widget.py --- a/src/browser/sat_browser/contact_widget.py Fri Mar 27 00:15:42 2015 +0100 +++ b/src/browser/sat_browser/contact_widget.py Mon Mar 23 09:35:46 2015 +0100 @@ -50,21 +50,21 @@ HTML.__init__(self) self.host = host self.jid = jid_ - if "nick" in display: - self.nick = self.host.contact_lists[C.PROF_KEY_NONE].getCache(self.jid, "nick") self.display = display self.alert = False - self.refresh() self.setStyleName('contactLabel') - def refresh(self): - alert_html = "(*) " if self.alert else "" + def update(self): + clist = self.host.contact_list + alert_html = "(*) " if self.jid in clist._alerts else "" + contact_raw = None for disp in self.display: if disp == "jid": contact_raw = unicode(self.jid) elif disp == "nick": - contact_raw = self.nick + clist = self.host.contact_list + contact_raw = html_tools.html_sanitize(clist.getCache(self.jid, "nick")) elif disp == "bare": contact_raw = unicode(self.jid.bare) elif disp == "resource": @@ -77,26 +77,11 @@ log.error(u"Could not find a contact display for jid {jid} (display: {display})".format(jid=self.jid, display=self.display)) contact_raw = "UNNAMED" contact_html = html_tools.html_sanitize(contact_raw) + html = "%(alert)s%(contact)s" % {'alert': alert_html, 'contact': contact_html} self.setHTML(html) - def updateNick(self, new_nick): - """Change the current nick - - @param new_nick(unicode): new nick to use - """ - self.nick = new_nick - self.refresh() - - def setAlert(self, alert): - """Show a visual indicator - - @param alert: True if alert must be shown - """ - self.alert = alert - self.refresh() - class ContactMenuBar(base_widget.WidgetMenuBar): @@ -132,51 +117,35 @@ self.jid = jid_ self.label = ContactLabel(host, self.jid, display=display) self.avatar = ContactMenuBar(self, host) if plugin_menu_context else Image() - self.states = HTML("") + self.states = HTML() try: # FIXME: dirty hack to force using an Image when the menu is actually empty self.avatar.items[0] except IndexError: self.avatar = Image() - self.updateAvatar(host.getAvatarURL(self.jid.bare)) self.add(self.avatar) self.add(self.label) self.add(self.states) + self.update() self.addClickListener(self) - def setAlert(self, alert): - """Show a visual indicator. - - @param alert (bool): True if alert indicator show be shown - """ - self.label.setAlert(alert) + def update(self): + """Update the display. - def updateAvatar(self, url): - """Update the avatar. - - @param url (unicode): image url + @param with_bare (bool): if True, ignore the resource and update with bare information. """ - self.avatar.setUrl(url) + self.avatar.setUrl(self.host.getAvatarURL(self.jid)) - def updateNick(self, new_nick): - """Update the nickname. - - @param new_nick (unicode): new nickname to use - """ - self.label.updateNick(html_tools.html_sanitize(new_nick)) - - def updateStates(self, states): - """Update the states. - - @param states (dict{unicode: unicode}): new states - """ - self.states.setHTML(u''.join(states.values())) + self.label.update() + clist = self.host.contact_list + show = clist.getCache(self.jid, C.PRESENCE_SHOW) + if show is None: + show = C.PRESENCE_UNAVAILABLE + html_tools.setPresenceStyle(self.label, show) def onClick(self, sender): try: - self.parent.onClick(self.jid.bare) + self.parent.onClick(self.jid) except (AttributeError, TypeError): pass - else: - self.setAlert(False) quick_menus.QuickMenusManager.addDataCollector(C.MENU_JID_CONTEXT, lambda caller, dummy: {'jid': unicode(caller.jid.bare)})