comparison 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
comparison
equal deleted inserted replaced
590:1bffc4c244c3 679:a90cc8fc9605
1 #!/usr/bin/python
2 # -*- coding: utf-8 -*-
3
4 # Libervia: a Salut à Toi frontend
5 # Copyright (C) 2011, 2012, 2013, 2014 Jérôme Poisson <goffi@goffi.org>
6
7 # This program is free software: you can redistribute it and/or modify
8 # it under the terms of the GNU Affero General Public License as published by
9 # the Free Software Foundation, either version 3 of the License, or
10 # (at your option) any later version.
11
12 # This program is distributed in the hope that it will be useful,
13 # but WITHOUT ANY WARRANTY; without even the implied warranty of
14 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 # GNU Affero General Public License for more details.
16
17 # You should have received a copy of the GNU Affero General Public License
18 # along with this program. If not, see <http://www.gnu.org/licenses/>.
19
20 """ Contacts / jids related panels """
21
22 import pyjd # this is dummy in pyjs
23 from sat.core.log import getLogger
24 log = getLogger(__name__)
25 from sat_frontends.tools import jid
26
27 from pyjamas.ui.AbsolutePanel import AbsolutePanel
28 from pyjamas.ui.VerticalPanel import VerticalPanel
29 from pyjamas.ui.HTML import HTML
30
31 import html_tools
32 import contact_widget
33 from constants import Const as C
34
35
36 # FIXME: must be removed
37 class Occupant(HTML):
38 """Occupant of a MUC room"""
39
40 def __init__(self, nick, state=None, special=""):
41 """
42 @param nick: the user nickname
43 @param state: the user chate state (XEP-0085)
44 @param special: a string of symbols (e.g: for activities)
45 """
46 HTML.__init__(self, StyleName="occupant")
47 self.nick = nick
48 self._state = state
49 self.special = special
50 self._refresh()
51
52 def __str__(self):
53 return self.nick
54
55 def setState(self, state):
56 self._state = state
57 self._refresh()
58
59 def addSpecial(self, special):
60 """@param special: unicode"""
61 if special not in self.special:
62 self.special += special
63 self._refresh()
64
65 def removeSpecials(self, special):
66 """@param special: unicode or list"""
67 if not isinstance(special, list):
68 special = [special]
69 for symbol in special:
70 self.special = self.special.replace(symbol, "")
71 self._refresh()
72
73 def _refresh(self):
74 state = (' %s' % C.MUC_USER_STATES[self._state]) if self._state else ''
75 special = "" if len(self.special) == 0 else " %s" % self.special
76 self.setHTML("%s%s%s" % (html_tools.html_sanitize(self.nick), special, state))
77
78
79 class ContactsPanel(VerticalPanel):
80 """ContactList graphic representation
81
82 Special features like popup menu panel or changing the contact states must be done in a sub-class.
83 """
84
85 def __init__(self, host, merge_resources=True, contacts_click=None,
86 contacts_style=None, contacts_menus=True,
87 contacts_display=C.CONTACT_DEFAULT_DISPLAY):
88 """
89
90 @param host (SatWebFrontend): host instance
91 @param merge_resources (bool): if True, the entities sharing the same
92 bare JID will also share the same contact box.
93 @param contacts_click (callable): click callback for the contact boxes
94 @param contacts_style (unicode): CSS style name for the contact boxes
95 @param contacts_menus (tuple): define the menu types that fit this
96 contact panel, with values from the menus type constants.
97 @param contacts_display (tuple): prioritize the display methods of the
98 contact's label with values in ("jid", "nick", "bare", "resource")
99 """
100 VerticalPanel.__init__(self)
101 self.host = host
102 self.merge_resources = merge_resources
103 self._contacts = {} # entity jid to ContactBox map
104 self.click_listener = None
105
106 if contacts_click is not None:
107 self.onClick = contacts_click
108
109 self.contacts_style = contacts_style
110 self.contacts_menus = contacts_menus
111 self.contacts_display = contacts_display
112
113 def _key(self, contact_jid):
114 """Return internal key for this contact.
115
116 @param contact_jid (jid.JID): contact JID
117 @return: jid.JID
118 """
119 return contact_jid.bare if self.merge_resources else contact_jid
120
121 def setList(self, jids):
122 """set all contacts in the list in one shot.
123
124 @param jids (list[jid.JID]): jids to display (the order is kept)
125 @param name (unicode): optional name of the contact
126 """
127 # FIXME: we do a full clear and add boxes after, we should only remove recently hidden boxes and add new ones, and re-order
128 current = [box.jid for box in self.children if isinstance(box, contact_widget.ContactBox)]
129 if current == jids:
130 # the display doesn't change
131 return
132 self.clear()
133 for contact_jid in jids:
134 assert isinstance(contact_jid, jid.JID)
135 self.addContact(contact_jid)
136
137 def getContactBox(self, contact_jid):
138 """Get a contact box for a contact, add it if it doesn't exist yet.
139
140 @param contact_jid (jid.JID): contact JID
141 @return: ContactBox
142 """
143 try:
144 return self._contacts[self._key(contact_jid)]
145 except KeyError:
146 box = contact_widget.ContactBox(self.host, contact_jid,
147 style_name=self.contacts_style,
148 display=self.contacts_display,
149 plugin_menu_context=self.contacts_menus)
150 self._contacts[self._key(contact_jid)] = box
151 return box
152
153 def addContact(self, contact_jid):
154 """Add a contact to the list.
155
156 @param contact_jid (jid.JID): contact JID
157 """
158 box = self.getContactBox(contact_jid)
159 if box not in self.children:
160 VerticalPanel.append(self, box)
161
162 def removeContact(self, contact_jid):
163 """Remove a contact from the list.
164
165 @param contact_jid (jid.JID): contact JID
166 """
167 box = self._contacts.pop(self._key(contact_jid))
168 VerticalPanel.remove(self, box)
169
170 def updateAvatar(self, contact_jid, url):
171 """Update the avatar of the given contact
172
173 @param contact_jid (jid.JID): contact JID
174 @param url (unicode): image url
175 """
176 try:
177 self.getContactBox(contact_jid).updateAvatar(url)
178 except TypeError:
179 pass
180
181 def updateNick(self, contact_jid, new_nick):
182 """Update the avatar of the given contact.
183
184 @param contact_jid (jid.JID): contact JID
185 @param new_nick (unicode): new nick of the contact
186 """
187 try:
188 self.getContactBox(contact_jid).updateNick(new_nick)
189 except TypeError:
190 pass
191
192
193
194 # FIXME: must be removed and ContactsPanel must be used instead
195 class OccupantsList(AbsolutePanel):
196 """Panel user to show occupants of a room"""
197
198 def __init__(self):
199 AbsolutePanel.__init__(self)
200 self.occupants_list = {}
201 self.setStyleName('occupantsList')
202
203 def addOccupant(self, nick):
204 if nick in self.occupants_list:
205 return
206 _occupant = Occupant(nick)
207 self.occupants_list[nick] = _occupant
208 self.add(_occupant)
209
210 def removeOccupant(self, nick):
211 try:
212 self.remove(self.occupants_list[nick])
213 except KeyError:
214 log.error("trying to remove an unexisting nick")
215
216 def getOccupantBox(self, nick):
217 """Get the widget element of the given nick.
218
219 @return: Occupant
220 """
221 try:
222 return self.occupants_list[nick]
223 except KeyError:
224 return None
225
226 def clear(self):
227 self.occupants_list.clear()
228 AbsolutePanel.clear(self)
229
230 def updateSpecials(self, occupants=[], html=""):
231 """Set the specified html "symbol" to the listed occupants,
232 and eventually remove it from the others (if they got it).
233 This is used for example to visualize who is playing a game.
234 @param occupants: list of the occupants that need the symbol
235 @param html: unicode symbol (actually one character or more)
236 or a list to assign different symbols of the same family.
237 """
238 index = 0
239 special = html
240 for occupant in self.occupants_list.keys():
241 if occupant in occupants:
242 if isinstance(html, list):
243 special = html[index]
244 index = (index + 1) % len(html)
245 self.occupants_list[occupant].addSpecial(special)
246 else:
247 self.occupants_list[occupant].removeSpecials(html)