Mercurial > libervia-backend
changeset 125:8d611eb9ae48
primitivus: contact list enhancement
- primitivus: contact list now display groups and sexy name (instead of bare jid)
- primitivus: contact list now show an alert when somebody want to contact you, and its chat window is not on the screen
- primitivus: cursor is now visible when going to chat window (useful to go back in logs)
author | Goffi <goffi@goffi.org> |
---|---|
date | Mon, 12 Jul 2010 17:50:00 +0800 |
parents | 961e0898271f |
children | 1b33b681ebd8 |
files | frontends/primitivus/chat.py frontends/primitivus/contact_list.py frontends/primitivus/custom_widgets.py frontends/primitivus/primitivus frontends/quick_frontend/quick_app.py frontends/wix/contact_list.py |
diffstat | 6 files changed, 180 insertions(+), 50 deletions(-) [+] |
line wrap: on
line diff
--- a/frontends/primitivus/chat.py Thu Jul 08 19:47:54 2010 +0800 +++ b/frontends/primitivus/chat.py Mon Jul 12 17:50:00 2010 +0800 @@ -48,7 +48,14 @@ return self.display_widget(size, focus).rows(size, focus) def render(self, size, focus=False): - return self.display_widget(size, focus).render(size, focus) + canvas = urwid.CompositeCanvas(self.display_widget(size, focus).render(size, focus)) + if focus: + canvas.set_cursor(self.get_cursor_coords(size)) + return canvas + + def get_cursor_coords(self, size): + #(maxcol,) = size + return 0, 0 def display_widget(self, size, focus): my_mess = (self.from_jid.resource == self.parent.nick) if self.parent.type == "group" else (self.from_jid.short == self.my_jid.short) #mymess = True if message comes from local user @@ -134,7 +141,7 @@ def __buildPresentList(self): - self.present_wid = custom_widgets.GenericList([],option_type = custom_widgets.UnselectableText) + self.present_wid = custom_widgets.GenericList([],option_type = custom_widgets.ClickableText) return self.present_wid def __appendPresentPanel(self):
--- a/frontends/primitivus/contact_list.py Thu Jul 08 19:47:54 2010 +0800 +++ b/frontends/primitivus/contact_list.py Mon Jul 12 17:50:00 2010 +0800 @@ -21,6 +21,7 @@ import urwid from quick_frontend.quick_contact_list import QuickContactList +from tools.jid import JID import custom_widgets @@ -29,13 +30,13 @@ def __init__(self, host, CM, on_click=None, on_change=None, user_data=None): self.host = host - - self.list_wid = custom_widgets.GenericList([], style=['single','no_first_select'], align='left', on_click=self.__contactClicked, on_change=on_change) - + self.selected = None + self.groups={} + self.alert_jid=set() + #we now build the widget - frame_body = self.list_wid - frame = urwid.Frame(frame_body) - self.main_widget = custom_widgets.LabelLine(frame, custom_widgets.SurroundedText(_("Contacts"))) + self.frame = urwid.Frame(self.__buildList()) + self.main_widget = custom_widgets.LabelLine(self.frame, custom_widgets.SurroundedText(_("Contacts"))) urwid.WidgetWrap.__init__(self, self.main_widget) if on_click: urwid.connect_signal(self, 'click', on_click, user_data) @@ -44,38 +45,126 @@ QuickContactList.__init__(self, CM) def __contains__(self, jid): - contacts = self.list_wid.getAllValues() - return jid.short in contacts + for group in self.groups: + if jid.short in self.groups[group][1]: + return True + return False + + def setFocus(self, name): + """give focus to the first group or contact with the given name""" + idx = 0 + for widget in self.frame.body.body: + if widget.getValue() == name: + self.frame.body.set_focus(idx) + return + idx+=1 + + def putAlert(self, jid): + """Put an alert on the jid to get attention from user (e.g. for new message)""" + self.alert_jid.add(jid.short) + self.frame.body = self.__buildList() + self.host.redraw() + + def __groupClicked(self, group_wid): + group = self.groups[group_wid.getValue()] + group[0] = not group[0] + self.frame.body = self.__buildList() + self.host.redraw() + self.setFocus(group_wid.getValue()) - def __contactClicked(self, list_wid): + def __contactClicked(self, contact_wid, selected): + self.selected = contact_wid.data + for widget in self.frame.body.body: + if widget.__class__ == custom_widgets.SelectableText: + widget.setState(widget.data == self.selected, invisible=True) + if self.selected in self.alert_jid: + self.alert_jid.remove(self.selected) + self.frame.body = self.__buildList() + self.host.redraw() self._emit('click') + def __buildContact(self, content, param_contacts): + """Add contact representation in widget list + @param content: widget list, e.g. SimpleListWalker + @param contacts: list of JID""" + contacts = list(param_contacts) + contacts.sort() + for contact in contacts: + jid=JID(contact) + name = self.CM.getAttr(jid,'name') + nick = self.CM.getAttr(jid,'nick') + display = nick or name or jid.node or jid.short + header = '(*) ' if contact in self.alert_jid else '' + widget = custom_widgets.SelectableText(display, selected = contact==self.selected, header=header, data=contact) + if contact in self.alert_jid: + widget.setAttribute('default','alert') + content.append(widget) + urwid.connect_signal(widget, 'change', self.__contactClicked) + + def __buildList(self): + """Build the main contact list widget""" + content = urwid.SimpleListWalker([]) + group_keys = self.groups.keys() + group_keys.sort() + for key in group_keys: + unfolded = self.groups[key][0] + if key!=None: + header = '[-]' if unfolded else '[+]' + widget = custom_widgets.ClickableText(key,header=header+' ') + content.append(widget) + urwid.connect_signal(widget, 'click', self.__groupClicked) + if unfolded: + self.__buildContact(content, self.groups[key][1]) + return urwid.ListBox(content) + def get_contact(self): """Return contact currently selected""" - return self.list_wid.getSelectedValue() + return self.selected def clear_contacts(self): """clear all the contact list""" - self.list_wid.changeValues([]) + self.groups={} - def replace(self, jid, groups=None): + def replace(self, jid, groups=[None]): """add a contact to the list if doesn't exist, else update it""" - contacts = self.list_wid.getAllValues() + assert groups.__class__ == list + assert jid.__class__ == JID + if not groups: + groups=[None] + for group in groups: + if not self.groups.has_key(group): + self.groups[group] = [True,set()] #[unfold,list_of_contacts] + self.groups[group][1].add(jid.short) + self.frame.body = self.__buildList() + self.host.redraw() + + + """contacts = self.list_wid.getAllValues() if jid.short not in contacts: contacts.append(jid.short) contacts.sort() self.list_wid.changeValues(contacts) - self._emit('change') + self._emit('change')""" def disconnect(self, jid): """mark a contact disconnected""" - self.remove(jid) + self.remove(jid.short) def remove(self, jid): """remove a contact from the list""" - self.list_wid.deleteValue(jid.short) + groups_to_remove = [] + for group in self.groups: + contacts = self.groups[group][1] + if jid.short in contacts: + contacts.remove(jid.short) + if not len(contacts): + groups_to_remove.append(group) + for group in groups_to_remove: + del self.groups[group] + self.frame.body = self.__buildList() + self.host.redraw() - def add(self, jid, param_groups=None): + def add(self, jid, param_groups=[None]): """add a contact to the list""" - self.replace(jid) + self.replace(jid,param_groups)
--- a/frontends/primitivus/custom_widgets.py Thu Jul 08 19:47:54 2010 +0800 +++ b/frontends/primitivus/custom_widgets.py Mon Jul 12 17:50:00 2010 +0800 @@ -95,13 +95,31 @@ """Text which can be selected with space""" signals = ['change'] - def __init__(self, text, align='left'): + def __init__(self, text, align='left', header='', select_attr=None, default_attr=None, selected = False, data=None): self.text=unicode(text) + self.header=header + if data: + self.data=data + if select_attr: + self.selected = select_attr + if default_attr: + self.default = default_attr self.align = align - self.__selected=False + self.__selected=selected def getValue(self): return self.text + + def setAttribute(self, name, value): + """Change attribut used for rendering widget + @param name: one of + -default: when not selected + -selected: when selected + @param value: name of the attribute + /!\ the attribute name followed by _focus is used when widget has focus""" + assert name in ['default', 'selected'] + self.__setattr__(name,value) + self._invalidate() def setState(self, selected, invisible=False): """Change state @@ -132,15 +150,24 @@ return self.display_widget(size, focus).render(size, focus) def display_widget(self, size, focus): - attr = 'selected' if self.__selected else 'default' + try: + select_attr = self.selected + except AttributeError: + select_attr = 'selected' + try: + default_attr = self.default + except AttributeError: + default_attr = 'default' + attr = select_attr if self.__selected else default_attr if focus: attr+="_focus" - return urwid.Text((attr,self.text), align=self.align) + return urwid.Text((attr,self.header+self.text), align=self.align) -class UnselectableText(SelectableText): +class ClickableText(SelectableText): + signals = SelectableText.signals + ['click'] def setState(self, selected, invisible=False): - pass + self._emit('click') class GenericList(urwid.WidgetWrap): signals = ['click','change']
--- a/frontends/primitivus/primitivus Thu Jul 08 19:47:54 2010 +0800 +++ b/frontends/primitivus/primitivus Mon Jul 12 17:50:00 2010 +0800 @@ -60,6 +60,8 @@ ('selected_focus', 'default,bold', 'dark red'), ('default', 'default', 'default'), ('default_focus', 'default,bold', 'default'), + ('alert', 'default,underline', 'default'), + ('alert_focus', 'default,bold,underline', 'default'), ('date', 'light gray', 'default'), ('my_nick', 'dark red,bold', 'default'), ('other_nick', 'dark cyan,bold', 'default'), @@ -125,8 +127,6 @@ #The main widget is not built (probably in Profile Manager) pass - - def __buildMainWidget(self): self.contactList = ContactList(self, self.CM, on_click = self.contactSelected, on_change=lambda w: self.redraw()) #self.center_part = urwid.Columns([('weight',2,self.contactList),('weight',8,Chat('',self))]) @@ -166,6 +166,14 @@ profile_key=self.profile) editBar.set_edit_text('') + def newMessage(self, from_jid, msg, type, to_jid, profile): + if not self.check_profile(profile): + return + QuickApp.newMessage(self, from_jid, msg, type, to_jid, profile) + sender = JID(from_jid) + if JID(self.contactList.selected).short != sender.short: + self.contactList.putAlert(sender) + def onJoinRoom(self, button, edit): self.removePopUp() room_jid = JID(edit.get_edit_text())
--- a/frontends/quick_frontend/quick_app.py Thu Jul 08 19:47:54 2010 +0800 +++ b/frontends/quick_frontend/quick_app.py Mon Jul 12 17:50:00 2010 +0800 @@ -67,7 +67,7 @@ self.current_action_ids = set() self.current_action_ids_cb = {} - def __check_profile(self, profile): + def check_profile(self, profile): """Tell if the profile is currently followed by the application""" return profile in self.profiles.keys() @@ -160,7 +160,7 @@ def connected(self, profile): """called when the connection is made""" - if not self.__check_profile(profile): + if not self.check_profile(profile): return debug(_("Connected")) self.setStatusOnline(True) @@ -169,7 +169,7 @@ def disconnected(self, profile): """called when the connection is closed""" - if not self.__check_profile(profile): + if not self.check_profile(profile): return debug(_("Disconnected")) self.CM.clear() @@ -177,13 +177,13 @@ self.setStatusOnline(False) def newContact(self, JabberId, attributes, groups, profile): - if not self.__check_profile(profile): + if not self.check_profile(profile): return entity=JID(JabberId) self.rosterList[entity.short]=(dict(attributes), list(groups)) def newMessage(self, from_jid, msg, type, to_jid, profile): - if not self.__check_profile(profile): + if not self.check_profile(profile): return sender=JID(from_jid) addr=JID(to_jid) @@ -196,7 +196,7 @@ pass def presenceUpdate(self, jabber_id, show, priority, statuses, profile): - if not self.__check_profile(profile): + if not self.check_profile(profile): return debug (_("presence update for %(jid)s (show=%(show)s, priority=%(priority)s, statuses=%(statuses)s) [profile:%(profile)s]") % {'jid':jabber_id, 'show':show, 'priority':priority, 'statuses':statuses, 'profile':profile}); from_jid=JID(jabber_id) @@ -242,7 +242,7 @@ def roomJoined(self, room_id, room_service, room_nicks, user_nick, profile): """Called when a MUC room is joined""" - if not self.__check_profile(profile): + if not self.check_profile(profile): return debug (_("Room [%(room_name)s] joined by %(profile)s, users presents:%(users)s") % {'room_name':room_id+'@'+room_service, 'profile': profile, 'users':room_nicks}) room_jid=room_id+'@'+room_service @@ -254,7 +254,7 @@ def roomUserJoined(self, room_id, room_service, user_nick, user_data, profile): """Called when an user joined a MUC room""" - if not self.__check_profile(profile): + if not self.check_profile(profile): return room_jid=room_id+'@'+room_service if self.chat_wins.has_key(room_jid): @@ -263,7 +263,7 @@ def roomUserLeft(self, room_id, room_service, user_nick, user_data, profile): """Called when an user joined a MUC room""" - if not self.__check_profile(profile): + if not self.check_profile(profile): return room_jid=room_id+'@'+room_service if self.chat_wins.has_key(room_jid): @@ -272,7 +272,7 @@ def roomNewSubject(self, room_id, room_service, subject, profile): """Called when subject of MUC room change""" - if not self.__check_profile(profile): + if not self.check_profile(profile): return room_jid=room_id+'@'+room_service if self.chat_wins.has_key(room_jid): @@ -280,7 +280,7 @@ debug (_("new subject for room [%(room_jid)s]: %(subject)s") % {'room_jid':room_jid, "subject":subject}) def tarotGameStarted(self, room_jid, referee, players, profile): - if not self.__check_profile(profile): + if not self.check_profile(profile): return debug (_("Tarot Game Started \o/")) if self.chat_wins.has_key(room_jid): @@ -288,7 +288,7 @@ debug (_("new Tarot game started by [%(referee)s] in room [%(room_jid)s] with %(players)s") % {'referee':referee, 'room_jid':room_jid, 'players':[str(player) for player in players]}) def tarotGameNew(self, room_jid, hand, profile): - if not self.__check_profile(profile): + if not self.check_profile(profile): return debug (_("New Tarot Game")) if self.chat_wins.has_key(room_jid): @@ -296,21 +296,21 @@ def tarotChooseContrat(self, room_jid, xml_data, profile): """Called when the player has too select his contrat""" - if not self.__check_profile(profile): + if not self.check_profile(profile): return debug (_("Tarot: need to select a contrat")) if self.chat_wins.has_key(room_jid): self.chat_wins[room_jid].getGame("Tarot").chooseContrat(xml_data) def tarotShowCards(self, room_jid, game_stage, cards, data, profile): - if not self.__check_profile(profile): + if not self.check_profile(profile): return debug (_("Show cards")) if self.chat_wins.has_key(room_jid): self.chat_wins[room_jid].getGame("Tarot").showCards(game_stage, cards, data) def tarotMyTurn(self, room_jid, profile): - if not self.__check_profile(profile): + if not self.check_profile(profile): return debug (_("My turn to play")) if self.chat_wins.has_key(room_jid): @@ -318,21 +318,21 @@ def tarotScore(self, room_jid, xml_data, winners, loosers, profile): """Called when the game is finished and the score are updated""" - if not self.__check_profile(profile): + if not self.check_profile(profile): return debug (_("Tarot: score received")) if self.chat_wins.has_key(room_jid): self.chat_wins[room_jid].getGame("Tarot").showScores(xml_data, winners, loosers) def tarotCardsPlayed(self, room_jid, player, cards, profile): - if not self.__check_profile(profile): + if not self.check_profile(profile): return debug (_("Card(s) played (%(player)s): %(cards)s") % {"player":player, "cards":cards}) if self.chat_wins.has_key(room_jid): self.chat_wins[room_jid].getGame("Tarot").cardsPlayed(player, cards) def tarotInvalidCards(self, room_jid, phase, played_cards, invalid_cards, profile): - if not self.__check_profile(profile): + if not self.check_profile(profile): return debug (_("Cards played are not valid: %s") % invalid_cards) if self.chat_wins.has_key(room_jid): @@ -340,7 +340,7 @@ def subscribe(self, type, raw_jid, profile): """Called when a subsciption management signal is received""" - if not self.__check_profile(profile): + if not self.check_profile(profile): return entity = JID(raw_jid) if type=="subscribed": @@ -364,7 +364,7 @@ pass #FIXME def paramUpdate(self, name, value, namespace, profile): - if not self.__check_profile(profile): + if not self.check_profile(profile): return debug(_("param update: [%(namespace)s] %(name)s = %(value)s") % {'namespace':namespace, 'name':name, 'value':value}) if (namespace,name) == ("Connection", "JabberID"): @@ -374,7 +374,7 @@ self.profiles[profile]['watched']=value.split() def contactDeleted(self, jid, profile): - if not self.__check_profile(profile): + if not self.check_profile(profile): return target = JID(jid) self.CM.remove(target)
--- a/frontends/wix/contact_list.py Thu Jul 08 19:47:54 2010 +0800 +++ b/frontends/wix/contact_list.py Mon Jul 12 17:50:00 2010 +0800 @@ -95,7 +95,6 @@ status = self.CM.getAttr(jid,'status') or '' avatar = self.CM.getAttr(jid,'avatar') or IMAGE_DIR+'/empty_avatar.png' - #XXX: yes table I know :) but wxHTML* doesn't support CSS html = """ <table border='0'> <td>