comparison src/browser/sat_browser/contact_list.py @ 630:71abccd8d228 frontends_multi_profiles

browser side: contact_list update: - removed ContactPanel's "add" and "remove" method, and replaced them by a display which display all needed contact at once - first naive implementation of display: if the display change, clear and add all ContactBox. Need to be done in a more efficient way in the future - ContactBox are never deleted, and only hidden when not displayed. ContactBox are automatically created on first use (TODO: add a way to delete them for entities not in roster)
author Goffi <goffi@goffi.org>
date Mon, 23 Feb 2015 18:16:07 +0100
parents 57a651a5b31d
children 617f7a5c5312
comparison
equal deleted inserted replaced
629:57a651a5b31d 630:71abccd8d228
129 self.items[0].setHTML('<img src="%s" />' % url) 129 self.items[0].setHTML('<img src="%s" />' % url)
130 130
131 131
132 class ContactBox(VerticalPanel, ClickHandler, base_widget.DragLabel): 132 class ContactBox(VerticalPanel, ClickHandler, base_widget.DragLabel):
133 133
134 def __init__(self, host, jid_, name=None, click_listener=None, handle_menu=None): 134 def __init__(self, host, jid_, name=None, on_click=None, handle_menu=None):
135 """ 135 """
136 136
137 @param host (SatWebFrontend) 137 @param host (SatWebFrontend): %(doc_host)s
138 @param jid_ (jid.JID): contact JID 138 @param jid_ (jid.JID): contact JID
139 @param name (unicode): contact alias 139 @param name (unicode): contact alias
140 @param click_listener (callable): click callback 140 @param on_click (callable): click callback
141 @param handle_menu (bool): if True, bind a popup menu to the avatar 141 @param handle_menu (bool): if True, bind a popup menu to the avatar
142 """ 142 """
143 VerticalPanel.__init__(self, StyleName='contactBox', VerticalAlignment='middle') 143 VerticalPanel.__init__(self, StyleName='contactBox', VerticalAlignment='middle')
144 base_widget.DragLabel.__init__(self, jid_, "CONTACT", host) 144 base_widget.DragLabel.__init__(self, jid_, "CONTACT", host)
145 self.jid = jid_ 145 self.jid = jid_
146 self.label = ContactLabel(jid_, name) 146 self.label = ContactLabel(jid_, name)
147 self.avatar = ContactMenuBar(self, host) if handle_menu else Image() 147 self.avatar = ContactMenuBar(self, host) if handle_menu else Image()
148 self.updateAvatar(host.getAvatarURL(jid_)) 148 self.updateAvatar(host.getAvatarURL(jid_))
149 self.add(self.avatar) 149 self.add(self.avatar)
150 self.add(self.label) 150 self.add(self.label)
151 if click_listener: 151 if on_click:
152 ClickHandler.__init__(self) 152 ClickHandler.__init__(self)
153 self.addClickListener(self) 153 self.addClickListener(self)
154 self.click_listener = click_listener 154 self._on_click = on_click
155 155
156 def addMenus(self, menu_bar): 156 def addMenus(self, menu_bar):
157 menu_bar.addCachedMenus(C.MENU_ROSTER_JID_CONTEXT, {'jid': unicode(self.jid)}) 157 menu_bar.addCachedMenus(C.MENU_ROSTER_JID_CONTEXT, {'jid': unicode(self.jid)})
158 menu_bar.addCachedMenus(C.MENU_JID_CONTEXT, {'jid': unicode(self.jid)}) 158 menu_bar.addCachedMenus(C.MENU_JID_CONTEXT, {'jid': unicode(self.jid)})
159 159
169 @param url (unicode): image url 169 @param url (unicode): image url
170 """ 170 """
171 self.avatar.setUrl(url) 171 self.avatar.setUrl(url)
172 172
173 def onClick(self, sender): 173 def onClick(self, sender):
174 self.click_listener(self.jid) 174 self._on_click(self.jid)
175 175
176 176
177 class GroupPanel(VerticalPanel): 177 class GroupPanel(VerticalPanel):
178 178
179 def __init__(self, parent): 179 def __init__(self, parent):
218 def getGroups(self): 218 def getGroups(self):
219 return self._groups 219 return self._groups
220 220
221 221
222 class BaseContactsPanel(VerticalPanel): 222 class BaseContactsPanel(VerticalPanel):
223 """Class that can be used to represent a contact list, but not necessarily 223 """ContactList graphic representation
224 the one that is displayed on the left side. Special features like popup menu 224
225 panel or changing the contact states must be done in a sub-class.""" 225 Special features like popup menu panel or changing the contact states must be done in a sub-class.
226 """
226 227
227 def __init__(self, host, handle_click=False, handle_menu=False): 228 def __init__(self, host, handle_click=False, handle_menu=False):
228 VerticalPanel.__init__(self) 229 VerticalPanel.__init__(self)
229 self.host = host 230 self.host = host
230 self.contacts = [] 231 self._contacts = {} # entity jid to ContactBox map
231 self.click_listener = None 232 self.click_listener = None
232 self.handle_menu = handle_menu 233 self.handle_menu = handle_menu
233 234
234 if handle_click: 235 if handle_click:
235 def cb(contact_jid): 236 def cb(contact_jid):
236 host.displayWidget(chat.Chat, contact_jid, type_=C.CHAT_ONE2ONE) 237 host.displayWidget(chat.Chat, contact_jid, type_=C.CHAT_ONE2ONE)
237 self.click_listener = cb 238 self.click_listener = cb
238 239
239 def add(self, jid_, name=None): 240 def display(self, jids):
240 """Add a contact to the list. 241 """Display a contact in the list.
241 242
242 @param jid_ (jid.JID): jid_ of the contact 243 @param jids (list[jid.JID]): jids to display (the order is kept)
243 @param name (unicode): optional name of the contact 244 @param name (unicode): optional name of the contact
244 """ 245 """
245 assert isinstance(jid_, jid.JID) 246 # FIXME: we do a full clear and add boxes after, we should only remove recently hidden boxes and add new ones, and re-order
246 if jid_ in self.contacts: 247 current = [box.jid for box in self.children if isinstance(box, ContactBox)]
248 if current == jids:
249 # the display doesn't change
247 return 250 return
248 index = 0 251 self.clear()
249 for contact_ in self.contacts: 252 for jid_ in jids:
250 if contact_ > jid_: 253 assert isinstance(jid_, jid.JID)
251 break 254 box = self.getContactBox(jid_)
252 index += 1 255 VerticalPanel.append(self, box)
253 self.contacts.insert(index, jid_)
254 box = ContactBox(self.host, jid_, name, self.click_listener, self.handle_menu)
255 VerticalPanel.insert(self, box, index)
256
257 def remove(self, jid_):
258 box = self.getContactBox(jid_)
259 if not box:
260 return
261 VerticalPanel.remove(self, box)
262 self.contacts.remove(jid_)
263 256
264 def isContactPresent(self, contact_jid): 257 def isContactPresent(self, contact_jid):
265 """Return True if a contact is present in the panel""" 258 """Return True if a contact is present in the panel"""
266 return contact_jid in self.contacts 259 return contact_jid in self._contacts
267 260
268 def getContacts(self): 261 def getContacts(self):
269 return self.contacts 262 return self._contacts
270 263
271 def getContactBox(self, contact_jid): 264 def getContactBox(self, contact_jid, name=None, on_click=None, handle_menu=None):
272 """get the widget of a contact 265 """get the Contactbox of a contact
273 266
267 if the Contactbox doesn't exists, it will be created
274 @param contact_jid (jid.JID): the contact 268 @param contact_jid (jid.JID): the contact
275 @return: ContactBox instance if present, else None""" 269 @param name (unicode): contact alias (used if ContactBox is created)
270 @param on_click (callable): click callback (used if ContactBox is created)
271 @param handle_menu (bool): if True, bind a popup menu to the avatar (used if ContactBox is created)
272 @return: ContactBox instance
273 """
276 assert isinstance(contact_jid, jid.JID) 274 assert isinstance(contact_jid, jid.JID)
277 for wid in self: 275 try:
278 if isinstance(wid, ContactBox) and wid.jid == contact_jid: 276 return self._contacts[contact_jid]
279 return wid 277 except KeyError:
280 return None 278 box = ContactBox(self.host, contact_jid, name, on_click, handle_menu)
279 self._contacts[contact_jid] = box
280 return box
281 281
282 def updateAvatar(self, jid_, url): 282 def updateAvatar(self, jid_, url):
283 """Update the avatar of the given contact 283 """Update the avatar of the given contact
284 284
285 @param jid_ (jid.JID): contact jid 285 @param jid_ (jid.JID): contact jid
306 True if message are waiting 306 True if message are waiting
307 - for availability type: 307 - for availability type:
308 C.PRESENCE_UNAVAILABLE or None if not connected, else presence like RFC6121 #4.7.2.1""" 308 C.PRESENCE_UNAVAILABLE or None if not connected, else presence like RFC6121 #4.7.2.1"""
309 assert type_ in ('availability', 'messageWaiting') 309 assert type_ in ('availability', 'messageWaiting')
310 contact_box = self.getContactBox(jid_) 310 contact_box = self.getContactBox(jid_)
311 if not contact_box: 311 if type_ == 'availability':
312 log.warning("No contact box found for {}".format(jid_)) 312 if state is None:
313 else: 313 state = C.PRESENCE_UNAVAILABLE
314 if type_ == 'availability': 314 setPresenceStyle(contact_box.label, state)
315 if state is None: 315 elif type_ == 'messageWaiting':
316 state = C.PRESENCE_UNAVAILABLE 316 contact_box.setMessageWaiting(state)
317 setPresenceStyle(contact_box.label, state)
318 elif type_ == 'messageWaiting':
319 contact_box.setMessageWaiting(state)
320 317
321 318
322 class ContactTitleLabel(base_widget.DragLabel, Label, ClickHandler): 319 class ContactTitleLabel(base_widget.DragLabel, Label, ClickHandler):
323 def __init__(self, host, text): 320 def __init__(self, host, text):
324 Label.__init__(self, text) # , Element=DOM.createElement('div') 321 Label.__init__(self, text) # , Element=DOM.createElement('div')
378 self._group_panel.add(group) 375 self._group_panel.add(group)
379 for group in removed_groups: 376 for group in removed_groups:
380 self._group_panel.remove(group) 377 self._group_panel.remove(group)
381 378
382 ### JIDS ### 379 ### JIDS ###
383 current_contacts = set([jid_ for jid_ in self._cache.keys() if self.entityToShow(jid_)]) 380 to_show = [jid_ for jid_ in self._cache.keys() if self.entityToShow(jid_)]
384 shown_contacts = set(self._contacts_panel.getContacts()) 381 to_show.sort()
385 new_contacts = current_contacts.difference(shown_contacts) 382
386 removed_contacts = shown_contacts.difference(current_contacts) 383 self._contacts_panel.display(to_show)
387 384
388 for contact in new_contacts: 385 for jid_ in self._alerts:
389 self._contacts_panel.add(contact) 386 self._contacts_panel.setState(jid_, "messageWaiting", True)
390 for contact in removed_contacts:
391 self._contacts_panel.remove(contact)
392 387
393 def onWindowResized(self, width, height): 388 def onWindowResized(self, width, height):
394 contact_panel_elt = self.getElement() 389 contact_panel_elt = self.getElement()
395 # FIXME: still needed ? 390 # FIXME: still needed ?
396 # classname = 'widgetsPanel' if isinstance(self.getParent().getParent(), panels.UniBoxPanel) else 'gwt-TabBar' 391 # classname = 'widgetsPanel' if isinstance(self.getParent().getParent(), panels.UniBoxPanel) else 'gwt-TabBar'
478 # self.host.room_contacts_chooser.resetContacts() 473 # self.host.room_contacts_chooser.resetContacts()
479 474
480 # self.updateVisibility([jid_s], self.getContactGroups(jid_s)) 475 # self.updateVisibility([jid_s], self.getContactGroups(jid_s))
481 476
482 def setContactMessageWaiting(self, jid, waiting): 477 def setContactMessageWaiting(self, jid, waiting):
483 """Show an visual indicator that contact has send a message 478 """Show a visual indicator that contact has send a message
479
484 @param jid: jid of the contact 480 @param jid: jid of the contact
485 @param waiting: True if message are waiting""" 481 @param waiting: True if message are waiting"""
486 self._contacts_panel.setState(jid, "messageWaiting", waiting) 482 raise Exception("Should not be there")
483 # self._contacts_panel.setState(jid, "messageWaiting", waiting)
487 484
488 # def getConnected(self, filter_muc=False): 485 # def getConnected(self, filter_muc=False):
489 # """return a list of all jid (bare jid) connected 486 # """return a list of all jid (bare jid) connected
490 # @param filter_muc: if True, remove the groups from the list 487 # @param filter_muc: if True, remove the groups from the list
491 # """ 488 # """
594 def updatePresence(self, entity, show, priority, statuses): 591 def updatePresence(self, entity, show, priority, statuses):
595 QuickContactList.updatePresence(self, entity, show, priority, statuses) 592 QuickContactList.updatePresence(self, entity, show, priority, statuses)
596 entity_bare = entity.bare 593 entity_bare = entity.bare
597 show = self.getCache(entity_bare, C.PRESENCE_SHOW) # we use cache to have the show nformation of main resource only 594 show = self.getCache(entity_bare, C.PRESENCE_SHOW) # we use cache to have the show nformation of main resource only
598 self._contacts_panel.setState(entity_bare, "availability", show) 595 self._contacts_panel.setState(entity_bare, "availability", show)
596 self.update()
599 597
600 # def updateVisibility(self, jids, groups): 598 # def updateVisibility(self, jids, groups):
601 # """Set the widgets visibility for the given contacts and groups 599 # """Set the widgets visibility for the given contacts and groups
602 600
603 # @param jids (list[unicode]): list of JID 601 # @param jids (list[unicode]): list of JID