Mercurial > libervia-web
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) |