Mercurial > libervia-web
diff src/browser/sat_browser/contact_panel.py @ 679:a90cc8fc9605
merged branch frontends_multi_profiles
author | Goffi <goffi@goffi.org> |
---|---|
date | Wed, 18 Mar 2015 16:15:18 +0100 |
parents | 849ffb24d5bf |
children | e876f493dccc |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/browser/sat_browser/contact_panel.py Wed Mar 18 16:15:18 2015 +0100 @@ -0,0 +1,247 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +# Libervia: a Salut à Toi frontend +# Copyright (C) 2011, 2012, 2013, 2014 Jérôme Poisson <goffi@goffi.org> + +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. + +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +""" Contacts / jids related panels """ + +import pyjd # this is dummy in pyjs +from sat.core.log import getLogger +log = getLogger(__name__) +from sat_frontends.tools import jid + +from pyjamas.ui.AbsolutePanel import AbsolutePanel +from pyjamas.ui.VerticalPanel import VerticalPanel +from pyjamas.ui.HTML import HTML + +import html_tools +import contact_widget +from constants import Const as C + + +# FIXME: must be removed +class Occupant(HTML): + """Occupant of a MUC room""" + + def __init__(self, nick, state=None, special=""): + """ + @param nick: the user nickname + @param state: the user chate state (XEP-0085) + @param special: a string of symbols (e.g: for activities) + """ + HTML.__init__(self, StyleName="occupant") + self.nick = nick + self._state = state + self.special = special + self._refresh() + + def __str__(self): + return self.nick + + def setState(self, state): + self._state = state + self._refresh() + + def addSpecial(self, special): + """@param special: unicode""" + if special not in self.special: + self.special += special + self._refresh() + + def removeSpecials(self, special): + """@param special: unicode or list""" + if not isinstance(special, list): + special = [special] + for symbol in special: + self.special = self.special.replace(symbol, "") + self._refresh() + + def _refresh(self): + state = (' %s' % C.MUC_USER_STATES[self._state]) if self._state else '' + special = "" if len(self.special) == 0 else " %s" % self.special + self.setHTML("%s%s%s" % (html_tools.html_sanitize(self.nick), special, state)) + + +class ContactsPanel(VerticalPanel): + """ContactList graphic representation + + Special features like popup menu panel or changing the contact states must be done in a sub-class. + """ + + def __init__(self, host, merge_resources=True, contacts_click=None, + contacts_style=None, contacts_menus=True, + contacts_display=C.CONTACT_DEFAULT_DISPLAY): + """ + + @param host (SatWebFrontend): host instance + @param merge_resources (bool): if True, the entities sharing the same + bare JID will also share the same contact box. + @param contacts_click (callable): click callback for the contact boxes + @param contacts_style (unicode): CSS style name for the contact boxes + @param contacts_menus (tuple): define the menu types that fit this + contact panel, with values from the menus type constants. + @param contacts_display (tuple): prioritize the display methods of the + contact's label with values in ("jid", "nick", "bare", "resource") + """ + VerticalPanel.__init__(self) + self.host = host + self.merge_resources = merge_resources + self._contacts = {} # entity jid to ContactBox map + self.click_listener = None + + if contacts_click is not None: + self.onClick = contacts_click + + self.contacts_style = contacts_style + self.contacts_menus = contacts_menus + self.contacts_display = contacts_display + + def _key(self, contact_jid): + """Return internal key for this contact. + + @param contact_jid (jid.JID): contact JID + @return: jid.JID + """ + return contact_jid.bare if self.merge_resources else contact_jid + + def setList(self, jids): + """set all contacts in the list in one shot. + + @param jids (list[jid.JID]): jids to display (the order is kept) + @param name (unicode): optional name of the contact + """ + # FIXME: we do a full clear and add boxes after, we should only remove recently hidden boxes and add new ones, and re-order + current = [box.jid for box in self.children if isinstance(box, contact_widget.ContactBox)] + if current == jids: + # the display doesn't change + return + self.clear() + for contact_jid in jids: + assert isinstance(contact_jid, jid.JID) + self.addContact(contact_jid) + + def getContactBox(self, contact_jid): + """Get a contact box for a contact, add it if it doesn't exist yet. + + @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, + 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. + + @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. + + @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 + """ + try: + self.getContactBox(contact_jid).updateAvatar(url) + except TypeError: + pass + + 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 + """ + try: + self.getContactBox(contact_jid).updateNick(new_nick) + except TypeError: + pass + + + +# FIXME: must be removed and ContactsPanel must be used instead +class OccupantsList(AbsolutePanel): + """Panel user to show occupants of a room""" + + def __init__(self): + AbsolutePanel.__init__(self) + self.occupants_list = {} + self.setStyleName('occupantsList') + + def addOccupant(self, nick): + if nick in self.occupants_list: + return + _occupant = Occupant(nick) + self.occupants_list[nick] = _occupant + self.add(_occupant) + + def removeOccupant(self, nick): + try: + self.remove(self.occupants_list[nick]) + except KeyError: + log.error("trying to remove an unexisting nick") + + def getOccupantBox(self, nick): + """Get the widget element of the given nick. + + @return: Occupant + """ + try: + return self.occupants_list[nick] + except KeyError: + return None + + def clear(self): + self.occupants_list.clear() + AbsolutePanel.clear(self) + + def updateSpecials(self, occupants=[], html=""): + """Set the specified html "symbol" to the listed occupants, + and eventually remove it from the others (if they got it). + This is used for example to visualize who is playing a game. + @param occupants: list of the occupants that need the symbol + @param html: unicode symbol (actually one character or more) + or a list to assign different symbols of the same family. + """ + index = 0 + special = html + for occupant in self.occupants_list.keys(): + if occupant in occupants: + if isinstance(html, list): + special = html[index] + index = (index + 1) % len(html) + self.occupants_list[occupant].addSpecial(special) + else: + self.occupants_list[occupant].removeSpecials(html)