view src/browser/sat_browser/contact_panel.py @ 660:267761bf7f08 frontends_multi_profiles

browser side (contact list): ContactPanels is used instead of OccupantsList in MUC: - ContactPanels become the generic class for all lists of contacts - OccupantsList will be removed - need to implements specials icons (e.g. for games) in ContactBox - ContactBox now manage a display arguments to set which data we want to display - ContactsPanel.display renamed to setList - ContactBox style can be changed when instaciating parent ContactsPanel - muc_contact CSS class is used for list of MUC occupants Not fully functionnal yet
author Goffi <goffi@goffi.org>
date Fri, 27 Feb 2015 22:53:27 +0100
parents 6d3142b782c3
children 2201ff543a05
line wrap: on
line source

#!/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, parent, on_click=None, handle_menu=True, contacts_style=None, contacts_display=C.CONTACT_DEFAULT_DISPLAY):
        """
        @param on_click (callable): click callback (used if ContactBox is created)
        @param handle_menu (bool): if True, bind a popup menu to the avatar (used if ContactBox is created)
        """ # FIXME
        VerticalPanel.__init__(self)
        self._parent = parent
        self.host = parent.host
        self._contacts = {} # entity jid to ContactBox map
        self.click_listener = None
        self.handle_menu = handle_menu

        if on_click is not None:
            self.onClick = on_click

        self.contacts_style=contacts_style
        self.contacts_display = contacts_display

    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 jid_ in jids:
            assert isinstance(jid_, jid.JID)
            box = self.getContactBox(jid_)
            VerticalPanel.append(self, box)

    def isContactPresent(self, contact_jid):
        """Return True if a contact is present in the panel"""
        return contact_jid in self._contacts

    def getContacts(self):
        return self._contacts

    def getContactBox(self, contact_jid):
        """get the Contactbox of a contact

        if the Contactbox doesn't exists, it will be created
        @param contact_jid (jid.JID): the contact
        @return: ContactBox instance
        """
        try:
            return self._contacts[contact_jid.bare]
        except KeyError:
            box = contact_widget.ContactBox(self, contact_jid, style_name=self.contacts_style, display=self.contacts_display)
            self._contacts[contact_jid.bare] = box
            return box

    def updateAvatar(self, jid_, url):
        """Update the avatar of the given contact

        @param jid_ (jid.JID): contact jid
        @param url (unicode): image url
        """
        try:
            self.getContactBox(jid_).updateAvatar(url)
        except TypeError:
            pass

    def updateNick(self, jid_, new_nick):
        """Update the avatar of the given contact

        @param jid_ (jid.JID): contact jid
        @param new_nick (unicode): new nick of the contact
        """
        try:
            self.getContactBox(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)