comparison src/browser/sat_browser/contact_list.py @ 634:16a5da120b7f frontends_multi_profiles

browser side (contact list): Contact list improvments: - removed optional arguments from getContactBox: they are now managed by the hosting panel, as the arguments should be same for all contacts in a panel - contact name is no more specified on ContactBox creation, is gotten by the ContactLabel itself using the cache (TODO: "nick" listener) - renamed setMessageXXX to setAlert for consitency with QuickFrontend (furthermore the alert could be used for something else than waiting messages) - ContactBoxes are stored using bare jid - parent is used in ContactBox instead of host
author Goffi <goffi@goffi.org>
date Mon, 23 Feb 2015 18:44:57 +0100
parents 617f7a5c5312
children 7113d40533d6
comparison
equal deleted inserted replaced
633:617f7a5c5312 634:16a5da120b7f
91 def onClick(self, sender): 91 def onClick(self, sender):
92 self.host.displayWidget(blog.MicroblogPanel, self.group) 92 self.host.displayWidget(blog.MicroblogPanel, self.group)
93 93
94 94
95 class ContactLabel(HTML): 95 class ContactLabel(HTML):
96 def __init__(self, jid_, name=None): 96 """Display a contact in HTML, selecting best display (jid/nick/etc)"""
97
98 def __init__(self, host, jid_):
99 # TODO: add a listener for nick changes
97 HTML.__init__(self) 100 HTML.__init__(self)
98 self.name = name or unicode(jid_) 101 self.host = host
99 self.waiting = False 102 self.jid = jid_.bare
103 self.nick = self.host.contact_lists[C.PROF_KEY_NONE].getCache(self.jid, "nick")
104 self.alert = False
100 self.refresh() 105 self.refresh()
101 self.setStyleName('contactLabel') 106 self.setStyleName('contactLabel')
102 107
103 def refresh(self): 108 def refresh(self):
104 if self.waiting: 109 alert_html = "<strong>(*)</strong>&nbsp;" if self.alert else ""
105 wait_html = "<b>(*)</b>&nbsp;" 110 contact_html = html_tools.html_sanitize(self.nick or unicode(self.jid))
106 self.setHTML("%(wait)s%(name)s" % {'wait': wait_html, 111 html = "%(alert)s%(contact)s" % {'alert': alert_html,
107 'name': html_tools.html_sanitize(self.name)}) 112 'contact': contact_html}
108 113 self.setHTML(html)
109 def setMessageWaiting(self, waiting): 114
110 """Show a visual indicator if message are waiting 115 def setAlert(self, alert):
111 116 """Show a visual indicator
112 @param waiting: True if message are waiting""" 117
113 self.waiting = waiting 118 @param alert: True if alert must be shown
119 """
120 self.alert = alert
114 self.refresh() 121 self.refresh()
115 122
116 123
117 class ContactMenuBar(base_widget.WidgetMenuBar): 124 class ContactMenuBar(base_widget.WidgetMenuBar):
118 125
129 self.items[0].setHTML('<img src="%s" />' % url) 136 self.items[0].setHTML('<img src="%s" />' % url)
130 137
131 138
132 class ContactBox(VerticalPanel, ClickHandler, base_widget.DragLabel): 139 class ContactBox(VerticalPanel, ClickHandler, base_widget.DragLabel):
133 140
134 def __init__(self, host, jid_, name=None, on_click=None, handle_menu=None): 141 def __init__(self, parent, jid_):
135 """ 142 """
136 143 @param parent (ContactPanel): ContactPanel hosting this box
137 @param host (SatWebFrontend): %(doc_host)s
138 @param jid_ (jid.JID): contact JID 144 @param jid_ (jid.JID): contact JID
139 @param name (unicode): contact alias
140 @param on_click (callable): click callback
141 @param handle_menu (bool): if True, bind a popup menu to the avatar
142 """ 145 """
143 VerticalPanel.__init__(self, StyleName='contactBox', VerticalAlignment='middle') 146 VerticalPanel.__init__(self, StyleName='contactBox', VerticalAlignment='middle')
144 base_widget.DragLabel.__init__(self, jid_, "CONTACT", host) 147 ClickHandler.__init__(self)
145 self.jid = jid_ 148 base_widget.DragLabel.__init__(self, jid_, "CONTACT", parent.host)
146 self.label = ContactLabel(jid_, name) 149 self.jid = jid_.bare
147 self.avatar = ContactMenuBar(self, host) if handle_menu else Image() 150 self.label = ContactLabel(parent.host, self.jid)
148 self.updateAvatar(host.getAvatarURL(jid_)) 151 self.avatar = ContactMenuBar(self, parent.host) if parent.handle_menu else Image()
152 self.updateAvatar(parent.host.getAvatarURL(self.jid))
149 self.add(self.avatar) 153 self.add(self.avatar)
150 self.add(self.label) 154 self.add(self.label)
151 if on_click: 155 self.addClickListener(self)
152 ClickHandler.__init__(self)
153 self.addClickListener(self)
154 self._on_click = on_click
155 156
156 def addMenus(self, menu_bar): 157 def addMenus(self, menu_bar):
157 menu_bar.addCachedMenus(C.MENU_ROSTER_JID_CONTEXT, {'jid': unicode(self.jid)}) 158 menu_bar.addCachedMenus(C.MENU_ROSTER_JID_CONTEXT, {'jid': unicode(self.jid)})
158 menu_bar.addCachedMenus(C.MENU_JID_CONTEXT, {'jid': unicode(self.jid)}) 159 menu_bar.addCachedMenus(C.MENU_JID_CONTEXT, {'jid': unicode(self.jid)})
159 160
160 def setMessageWaiting(self, waiting): 161 def setAlert(self, alert):
161 """Show a visual indicator if message are waiting 162 """Show a visual indicator
162 163
163 @param waiting: True if message are waiting""" 164 @param alert: True if alert indicator show be shown"""
164 self.label.setMessageWaiting(waiting) 165 self.label.setAlert(alert)
165 166
166 def updateAvatar(self, url): 167 def updateAvatar(self, url):
167 """Update the avatar. 168 """Update the avatar.
168 169
169 @param url (unicode): image url 170 @param url (unicode): image url
170 """ 171 """
171 self.avatar.setUrl(url) 172 self.avatar.setUrl(url)
172 173
173 def onClick(self, sender): 174 def onClick(self, sender):
174 self._on_click(self.jid) 175 try:
176 self.parent.onClick(self.jid)
177 except AttributeError:
178 pass
179 else:
180 self.setAlert(False)
175 181
176 182
177 class GroupPanel(VerticalPanel): 183 class GroupPanel(VerticalPanel):
178 184
179 def __init__(self, parent): 185 def __init__(self, parent):
223 """ContactList graphic representation 229 """ContactList graphic representation
224 230
225 Special features like popup menu panel or changing the contact states must be done in a sub-class. 231 Special features like popup menu panel or changing the contact states must be done in a sub-class.
226 """ 232 """
227 233
228 def __init__(self, host, handle_click=False, handle_menu=False): 234 def __init__(self, parent, handle_click=True, handle_menu=True):
235 """@param on_click (callable): click callback (used if ContactBox is created)
236 @param handle_menu (bool): if True, bind a popup menu to the avatar (used if ContactBox is created)
237 """ # FIXME
229 VerticalPanel.__init__(self) 238 VerticalPanel.__init__(self)
230 self.host = host 239 self._parent = parent
240 self.host = parent.host
231 self._contacts = {} # entity jid to ContactBox map 241 self._contacts = {} # entity jid to ContactBox map
232 self.click_listener = None 242 self.click_listener = None
233 self.handle_menu = handle_menu 243 self.handle_menu = handle_menu
234 244
235 if handle_click: 245 if handle_click:
236 def cb(contact_jid): 246 def cb(contact_jid):
237 host.displayWidget(chat.Chat, contact_jid, type_=C.CHAT_ONE2ONE) 247 self.host.displayWidget(chat.Chat, contact_jid, type_=C.CHAT_ONE2ONE)
238 self.click_listener = cb 248 self.onClick = cb
239 249
240 def display(self, jids): 250 def display(self, jids):
241 """Display a contact in the list. 251 """Display a contact in the list.
242 252
243 @param jids (list[jid.JID]): jids to display (the order is kept) 253 @param jids (list[jid.JID]): jids to display (the order is kept)
259 return contact_jid in self._contacts 269 return contact_jid in self._contacts
260 270
261 def getContacts(self): 271 def getContacts(self):
262 return self._contacts 272 return self._contacts
263 273
264 def getContactBox(self, contact_jid, name=None, on_click=None, handle_menu=None): 274 def getContactBox(self, contact_jid):
265 """get the Contactbox of a contact 275 """get the Contactbox of a contact
266 276
267 if the Contactbox doesn't exists, it will be created 277 if the Contactbox doesn't exists, it will be created
268 @param contact_jid (jid.JID): the contact 278 @param contact_jid (jid.JID): the contact
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 279 @return: ContactBox instance
273 """ 280 """
274 assert isinstance(contact_jid, jid.JID)
275 try: 281 try:
276 return self._contacts[contact_jid] 282 return self._contacts[contact_jid.bare]
277 except KeyError: 283 except KeyError:
278 box = ContactBox(self.host, contact_jid, name, on_click, handle_menu) 284 box = ContactBox(self, contact_jid)
279 self._contacts[contact_jid] = box 285 self._contacts[contact_jid.bare] = box
280 return box 286 return box
281 287
282 def updateAvatar(self, jid_, url): 288 def updateAvatar(self, jid_, url):
283 """Update the avatar of the given contact 289 """Update the avatar of the given contact
284 290
292 298
293 299
294 class ContactsPanel(BaseContactsPanel): 300 class ContactsPanel(BaseContactsPanel):
295 """The contact list that is displayed on the left side.""" 301 """The contact list that is displayed on the left side."""
296 302
297 def __init__(self, host): 303 def __init__(self, parent):
298 BaseContactsPanel.__init__(self, host, handle_click=True, handle_menu=True) 304 BaseContactsPanel.__init__(self, parent, handle_click=True, handle_menu=True)
299 305
300 def setState(self, jid_, type_, state): 306 def setState(self, jid_, type_, state):
301 """Change the appearance of the contact, according to the state 307 """Change the appearance of the contact, according to the state
308
302 @param jid_ (jid.JID): jid.JID which need to change state 309 @param jid_ (jid.JID): jid.JID which need to change state
303 @param type_ (unicode): one of "availability", "messageWaiting" 310 @param type_ (unicode): one of "availability", "messageWaiting"
304 @param state: 311 @param state:
305 - for messageWaiting type: 312 - for messageWaiting type:
306 True if message are waiting 313 True if message are waiting
311 if type_ == 'availability': 318 if type_ == 'availability':
312 if state is None: 319 if state is None:
313 state = C.PRESENCE_UNAVAILABLE 320 state = C.PRESENCE_UNAVAILABLE
314 setPresenceStyle(contact_box.label, state) 321 setPresenceStyle(contact_box.label, state)
315 elif type_ == 'messageWaiting': 322 elif type_ == 'messageWaiting':
316 contact_box.setMessageWaiting(state) 323 contact_box.setAlert(state)
317 324
318 325
319 class ContactTitleLabel(base_widget.DragLabel, Label, ClickHandler): 326 class ContactTitleLabel(base_widget.DragLabel, Label, ClickHandler):
327
320 def __init__(self, host, text): 328 def __init__(self, host, text):
321 Label.__init__(self, text) # , Element=DOM.createElement('div') 329 Label.__init__(self, text) # , Element=DOM.createElement('div')
322 self.setStyleName('contactTitle') 330 self.setStyleName('contactTitle')
323 base_widget.DragLabel.__init__(self, text, "CONTACT_TITLE", host) 331 base_widget.DragLabel.__init__(self, text, "CONTACT_TITLE", host)
324 ClickHandler.__init__(self) 332 ClickHandler.__init__(self)
332 """Manage the contacts and groups""" 340 """Manage the contacts and groups"""
333 341
334 def __init__(self, host): 342 def __init__(self, host):
335 QuickContactList.__init__(self, host, C.PROF_KEY_NONE) 343 QuickContactList.__init__(self, host, C.PROF_KEY_NONE)
336 SimplePanel.__init__(self) 344 SimplePanel.__init__(self)
345 self.host = host
337 self.scroll_panel = ScrollPanel() 346 self.scroll_panel = ScrollPanel()
338 self.vPanel = VerticalPanel() 347 self.vPanel = VerticalPanel()
339 _title = ContactTitleLabel(host, 'Contacts') 348 _title = ContactTitleLabel(host, 'Contacts')
340 DOM.setStyleAttribute(_title.getElement(), "cursor", "pointer") 349 DOM.setStyleAttribute(_title.getElement(), "cursor", "pointer")
341 self._contacts_panel = ContactsPanel(host) 350 self._contacts_panel = ContactsPanel(self)
342 self._contacts_panel.setStyleName('contactPanel') # FIXME: style doesn't exists ! 351 self._contacts_panel.setStyleName('contactPanel') # FIXME: style doesn't exists !
343 self._group_panel = GroupPanel(self) 352 self._group_panel = GroupPanel(self)
344 353
345 self.vPanel.add(_title) 354 self.vPanel.add(_title)
346 self.vPanel.add(self._group_panel) 355 self.vPanel.add(self._group_panel)
567 """Tell if the given group actually has visible members 576 """Tell if the given group actually has visible members
568 577
569 @param group (unicode): the group to check 578 @param group (unicode): the group to check
570 @return: boolean 579 @return: boolean
571 """ 580 """
581 raise Exception # FIXME: remove this method
572 for jid_ in self.groups[group]: 582 for jid_ in self.groups[group]:
573 if self._contacts_panel.getContactBox(jid_).isVisible(): 583 if self._contacts_panel.getContactBox(jid_).isVisible():
574 return True 584 return True
575 return False 585 return False
576 586