diff --git a/frontends/primitivus/chat.py b/frontends/primitivus/chat.py
index 122a3e66..1772bf92 100644
--- a/frontends/primitivus/chat.py
+++ b/frontends/primitivus/chat.py
@@ -48,7 +48,14 @@ class ChatText(urwid.FlowWidget):
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 @@ class Chat(urwid.WidgetWrap, QuickChat):
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):
diff --git a/frontends/primitivus/contact_list.py b/frontends/primitivus/contact_list.py
index ed2bed00..f2604418 100644
--- a/frontends/primitivus/contact_list.py
+++ b/frontends/primitivus/contact_list.py
@@ -21,6 +21,7 @@ along with this program. If not, see .
import urwid
from quick_frontend.quick_contact_list import QuickContactList
+from tools.jid import JID
import custom_widgets
@@ -29,13 +30,13 @@ class ContactList(urwid.WidgetWrap, QuickContactList):
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 @@ class ContactList(urwid.WidgetWrap, QuickContactList):
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 __contactClicked(self, list_wid):
+ 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, 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)
diff --git a/frontends/primitivus/custom_widgets.py b/frontends/primitivus/custom_widgets.py
index 6c3f1fe9..762d76be 100644
--- a/frontends/primitivus/custom_widgets.py
+++ b/frontends/primitivus/custom_widgets.py
@@ -95,13 +95,31 @@ class SelectableText(urwid.FlowWidget):
"""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 @@ class SelectableText(urwid.FlowWidget):
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']
diff --git a/frontends/primitivus/primitivus b/frontends/primitivus/primitivus
index b37a0919..56dd91c5 100755
--- a/frontends/primitivus/primitivus
+++ b/frontends/primitivus/primitivus
@@ -60,6 +60,8 @@ const_PALETTE = [('title', 'black', 'light gray', 'standout,underline'),
('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 @@ class PrimitivusApp(QuickApp):
#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 @@ class PrimitivusApp(QuickApp):
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())
diff --git a/frontends/quick_frontend/quick_app.py b/frontends/quick_frontend/quick_app.py
index e8c0008c..b3092b09 100644
--- a/frontends/quick_frontend/quick_app.py
+++ b/frontends/quick_frontend/quick_app.py
@@ -67,7 +67,7 @@ class QuickApp():
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 @@ class QuickApp():
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 @@ class QuickApp():
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 @@ class QuickApp():
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 @@ class QuickApp():
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 @@ class QuickApp():
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 @@ class QuickApp():
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 @@ class QuickApp():
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 @@ class QuickApp():
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 @@ class QuickApp():
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 @@ class QuickApp():
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 @@ class QuickApp():
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 @@ class QuickApp():
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 @@ class QuickApp():
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 @@ class QuickApp():
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 @@ class QuickApp():
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)
diff --git a/frontends/wix/contact_list.py b/frontends/wix/contact_list.py
index d96e8fc5..da62293e 100644
--- a/frontends/wix/contact_list.py
+++ b/frontends/wix/contact_list.py
@@ -95,7 +95,6 @@ class ContactList(wx.SimpleHtmlListBox, QuickContactList):
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 = """