diff --git a/frontends/primitivus/chat.py b/frontends/primitivus/chat.py
index 74d98bf3..122a3e66 100644
--- a/frontends/primitivus/chat.py
+++ b/frontends/primitivus/chat.py
@@ -22,33 +22,169 @@ along with this program. If not, see .
import urwid
from quick_frontend.quick_contact_list import QuickContactList
from quick_frontend.quick_chat import QuickChat
-from custom_widgets import Password,List,InputDialog,ConfirmDialog,Alert,SelectableText,LabelLine,SurroundedText
+import custom_widgets
+import time
+from tools.jid import JID
+class ChatText(urwid.FlowWidget):
+ """Manage the printing of chat message"""
+
+ def __init__(self, parent, timestamp, my_jid, from_jid, message, align='left'):
+ self.parent = parent
+ self.timestamp = time.localtime(timestamp)
+ self.my_jid = my_jid
+ self.from_jid = from_jid
+ self.message = unicode(message)
+ self.align = align
+
+ def selectable(self):
+ return True
+
+ def keypress(self, size, key):
+ return key
+
+ def rows(self,size,focus=False):
+ return self.display_widget(size, focus).rows(size, focus)
+
+ def render(self, size, focus=False):
+ return self.display_widget(size, focus).render(size, focus)
+
+ 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
+ render_txt = []
+ if self.parent.show_timestamp:
+ time_format = "%c" if self.timestamp < self.parent.day_change else "%H:%M" #if the message was sent before today, we print the full date
+ render_txt.append(('date',"[%s]" % time.strftime(time_format, self.timestamp)))
+ if self.parent.show_short_nick:
+ render_txt.append(('my_nick' if my_mess else 'other_nick',"**" if my_mess else "*"))
+ else:
+ render_txt.append(('my_nick' if my_mess else 'other_nick',"[%s] " % self.from_jid))
+ render_txt.append(self.message)
+ return urwid.Text(render_txt, align=self.align)
+
class Chat(urwid.WidgetWrap, QuickChat):
def __init__(self, target, host, type='one2one'):
+ self.target = target
QuickChat.__init__(self, target, host, type)
self.content = urwid.SimpleListWalker([])
self.text_list = urwid.ListBox(self.content)
- main_widget = LabelLine(
- urwid.Frame(self.text_list), SurroundedText(str(target))
- )
- urwid.WidgetWrap.__init__(self, main_widget)
+ self.chat_widget = urwid.Frame(self.text_list)
+ self.columns = urwid.Columns([('weight', 8, self.chat_widget)])
+ urwid.WidgetWrap.__init__(self, self.__getDecoration(self.columns))
self.setType(type)
-
+ self.day_change = time.strptime(time.strftime("%a %b %d 00:00:00 %Y")) #struct_time of day changing time
+ self.show_timestamp = True
+ self.show_short_nick = False
+ self.show_title = True
+ self.subject = None
+
+ def keypress(self, size, key):
+ if key == "meta p": #user wants to (un)hide the presents panel
+ if self.type == 'group':
+ widgets = self.columns.widget_list
+ if self.present_panel in widgets:
+ self.__removePresentPanel()
+ else:
+ self.__appendPresentPanel()
+ elif key == "meta t": #user wants to (un)hide timestamp
+ self.show_timestamp = not self.show_timestamp
+ for wid in self.content:
+ wid._invalidate()
+ elif key == "meta n": #user wants to (not) use short nick
+ self.show_short_nick = not self.show_short_nick
+ for wid in self.content:
+ wid._invalidate()
+ elif key == "meta l": #user wants to (un)hide widget decoration
+ show = not self._w.__class__ == custom_widgets.LabelLine
+ self.showDecoration(show)
+ self._invalidate()
+ elif key == "meta s": #user wants to (un)hide group's subject
+ if self.subject:
+ self.show_title = not self.show_title
+ if self.show_title:
+ self.setSubject(self.subject)
+ else:
+ self.chat_widget.header = None
+ self._invalidate()
+
+
+ return super(Chat, self).keypress(size, key)
+
def setType(self, type):
QuickChat.setType(self, type)
if type == 'one2one':
self.historyPrint(profile=self.host.profile)
-
+ elif type == 'group':
+ if len(self.columns.widget_list) == 1:
+ present_widget = self.__buildPresentList()
+ self.present_panel = custom_widgets.VerticalSeparator(present_widget)
+ self.__appendPresentPanel()
+
+ def __getDecoration(self, widget):
+ return custom_widgets.LabelLine(widget, custom_widgets.SurroundedText(unicode(self.target)))
+
+ def showDecoration(self, show=True):
+ if show:
+ main_widget = self.__getDecoration(self.columns)
+ else:
+ main_widget = self.columns
+ self._w = main_widget
+
+
+ def __buildPresentList(self):
+ self.present_wid = custom_widgets.GenericList([],option_type = custom_widgets.UnselectableText)
+ return self.present_wid
+
+ def __appendPresentPanel(self):
+ self.columns.widget_list.append(self.present_panel)
+ self.columns.column_types.append(('weight', 2))
+
+ def __removePresentPanel(self):
+ self.columns.set_focus(0) #necessary as the focus change to the next object, we can go out of range if we are on the last object of self.columns
+ self.columns.widget_list.remove(self.present_panel)
+ del self.columns.column_types[-1]
+
def setSubject(self, subject):
"""Set title for a group chat"""
QuickChat.setSubject(self, subject)
- self._w.base_widget.header = urwid.AttrMap(urwid.Text(unicode(subject),align='center'),'title')
+ self.subject = subject
+ self.chat_widget.header = urwid.AttrMap(urwid.Text(unicode(subject),align='center'),'title')
+ def setPresents(self, param_nicks):
+ """Set the users presents in the contact list for a group chat
+ @param nicks: list of nicknames
+ """
+ nicks = [unicode(nick) for nick in param_nicks] #FIXME: should be done in DBus bridge
+ nicks.sort()
+ QuickChat.setPresents(self, nicks)
+ self.present_wid.changeValues(nicks)
+ self.host.redraw()
+
+ def replaceUser(self, param_nick):
+ """Add user if it is not in the group list"""
+ nick = unicode(param_nick) #FIXME: should be done in DBus bridge
+ if "facebook" in nick:
+ self.host.debug()
+ QuickChat.replaceUser(self, nick)
+ presents = self.present_wid.getAllValues()
+ if nick not in presents:
+ presents.append(nick)
+ presents.sort()
+ self.present_wid.changeValues(presents)
+ self.host.redraw()
+
+ def removeUser(self, param_nick):
+ """Remove a user from the group list"""
+ nick = unicode(param_nick) #FIXME: should be done in DBus bridge
+ QuickChat.removeUser(self, nick)
+ self.present_wid.deleteValue(nick)
+ self.host.redraw()
def printMessage(self, from_jid, msg, profile, timestamp=""):
- self.content.append(SelectableText("[%s] " % from_jid + msg))
+ assert (from_jid.__class__ == JID)
+ my_jid = self.host.profiles[profile]['whoami']
+ self.content.append(ChatText(self, timestamp or None, my_jid, from_jid, msg))
self.text_list.set_focus(len(self.content)-1)
self.host.redraw()
diff --git a/frontends/primitivus/contact_list.py b/frontends/primitivus/contact_list.py
index a7ab60e6..ed2bed00 100644
--- a/frontends/primitivus/contact_list.py
+++ b/frontends/primitivus/contact_list.py
@@ -21,7 +21,7 @@ along with this program. If not, see .
import urwid
from quick_frontend.quick_contact_list import QuickContactList
-from custom_widgets import Password,List,InputDialog,ConfirmDialog,Alert,LabelLine,SurroundedText
+import custom_widgets
class ContactList(urwid.WidgetWrap, QuickContactList):
@@ -30,13 +30,12 @@ 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 = List([], style=['single','no_first_select'], align='left', on_click=self.__contactClicked, on_change=on_change)
+ self.list_wid = custom_widgets.GenericList([], style=['single','no_first_select'], align='left', on_click=self.__contactClicked, on_change=on_change)
#we now build the widget
- body_content = urwid.SimpleListWalker([self.list_wid])
- frame_body = urwid.ListBox(body_content)
+ frame_body = self.list_wid
frame = urwid.Frame(frame_body)
- self.main_widget = LabelLine(frame,SurroundedText(_("Contacts")))
+ self.main_widget = custom_widgets.LabelLine(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,6 +43,10 @@ class ContactList(urwid.WidgetWrap, QuickContactList):
urwid.connect_signal(self, 'change', on_change, user_data)
QuickContactList.__init__(self, CM)
+ def __contains__(self, jid):
+ contacts = self.list_wid.getAllValues()
+ return jid.short in contacts
+
def __contactClicked(self, list_wid):
self._emit('click')
@@ -66,7 +69,6 @@ class ContactList(urwid.WidgetWrap, QuickContactList):
def disconnect(self, jid):
"""mark a contact disconnected"""
- #self.host.debug()
self.remove(jid)
def remove(self, jid):
diff --git a/frontends/primitivus/custom_widgets.py b/frontends/primitivus/custom_widgets.py
index 46443bee..6c3f1fe9 100644
--- a/frontends/primitivus/custom_widgets.py
+++ b/frontends/primitivus/custom_widgets.py
@@ -137,10 +137,15 @@ class SelectableText(urwid.FlowWidget):
attr+="_focus"
return urwid.Text((attr,self.text), align=self.align)
+class UnselectableText(SelectableText):
+
+ def setState(self, selected, invisible=False):
+ pass
+
class GenericList(urwid.WidgetWrap):
signals = ['click','change']
- def __init__(self, options, style=[], align='left', on_click=None, on_change=None, user_data=None):
+ def __init__(self, options, style=[], align='left', option_type = SelectableText, on_click=None, on_change=None, user_data=None):
"""
Widget managing list of string and their selection
@param options: list of strings used for options
@@ -156,6 +161,7 @@ class GenericList(urwid.WidgetWrap):
self.no_first_select = 'no_first_select' in style
self.can_select_none = 'can_select_none' in style
self.align = align
+ self.option_type = option_type
self.first_display = True
if on_click:
@@ -222,11 +228,14 @@ class GenericList(urwid.WidgetWrap):
old_selected = self.getSelectedValues()
widgets = []
for option in new_values:
- widget = SelectableText(option, self.align)
+ widget = self.option_type(option, self.align)
if not self.first_display and option in old_selected:
widget.setState(True)
widgets.append(widget)
- urwid.connect_signal(widget, 'change', self.__onStateChange)
+ try:
+ urwid.connect_signal(widget, 'change', self.__onStateChange)
+ except NameError:
+ pass #the widget given doesn't support 'change' signal
self.content[:] = widgets
if self.first_display and self.single and new_values and not self.no_first_select:
self.content[0].setState(True)
@@ -249,8 +258,8 @@ class List(urwid.FlowWidget):
"""FlowWidget list, same arguments as GenericList, with an additional one 'max_height'"""
signals = ['click','change']
- def __init__(self, options, style=[], max_height=5, align='left', on_click=None, on_change=None, user_data=None):
- self.genericList = GenericList(options, style, align, on_click, on_change, user_data)
+ def __init__(self, options, style=[], max_height=5, align='left', option_type = SelectableText, on_click=None, on_change=None, user_data=None):
+ self.genericList = GenericList(options, style, align, option_type, on_click, on_change, user_data)
self.max_height = max_height
def selectable(self):
@@ -365,4 +374,18 @@ class LabelLine(urwid.LineBox):
urwid.LineBox.__init__(self, original_widget)
top_columns = self._w.widget_list[0]
top_columns.widget_list[1] = label_widget
+
+class VerticalSeparator(urwid.WidgetDecoration, urwid.WidgetWrap):
+ def __init__(self, original_widget, left_char = utf8decode("│"), right_char = ''):
+ """Draw a separator on left and/or of original_widget."""
+
+ widgets = [original_widget]
+ if left_char:
+ widgets.insert(0, ('fixed', 1, urwid.SolidFill(left_char)))
+ if right_char:
+ widgets.append(('fixed', 1, urwid.SolidFill(right_char)))
+ columns = urwid.Columns(widgets, box_columns = [0,2], focus_column = 1)
+ urwid.WidgetDecoration.__init__(self, original_widget)
+ urwid.WidgetWrap.__init__(self, columns)
+
diff --git a/frontends/primitivus/primitivus b/frontends/primitivus/primitivus
index 1cb0cdbb..b37a0919 100755
--- a/frontends/primitivus/primitivus
+++ b/frontends/primitivus/primitivus
@@ -60,6 +60,9 @@ const_PALETTE = [('title', 'black', 'light gray', 'standout,underline'),
('selected_focus', 'default,bold', 'dark red'),
('default', 'default', 'default'),
('default_focus', 'default,bold', 'default'),
+ ('date', 'light gray', 'default'),
+ ('my_nick', 'dark red,bold', 'default'),
+ ('other_nick', 'dark cyan,bold', 'default'),
]
class ChatList(QuickChatList):
@@ -108,6 +111,21 @@ class PrimitivusApp(QuickApp):
elif input == 'meta j': #user wants to join a room
pop_up_widget = InputDialog(_("Entering a MUC room"), _("Please enter MUC's JID"), default_txt = 'test@conference.necton2.int', cancel_cb=self.removePopUp, ok_cb=self.onJoinRoom)
self.showPopUp(pop_up_widget)
+ elif input == 'f2': #user wants to (un)hide the contact_list
+ try:
+ center_widgets = self.center_part.widget_list
+ if self.contactList in center_widgets:
+ self.center_part.set_focus(0) #necessary as the focus change to the next object, we can go out of range if we are on the last object of self.center_part
+ center_widgets.remove(self.contactList)
+ del self.center_part.column_types[0]
+ else:
+ center_widgets.insert(0, self.contactList)
+ self.center_part.column_types.insert(0, ('weight', 2))
+ except AttributeError:
+ #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())
diff --git a/frontends/quick_frontend/quick_app.py b/frontends/quick_frontend/quick_app.py
index 55e0ca02..e8c0008c 100644
--- a/frontends/quick_frontend/quick_app.py
+++ b/frontends/quick_frontend/quick_app.py
@@ -249,7 +249,7 @@ class QuickApp():
self.chat_wins[room_jid].setUserNick(user_nick)
self.chat_wins[room_jid].setType("group")
self.chat_wins[room_jid].id = room_jid
- self.chat_wins[room_jid].setPresents([user_nick]+room_nicks)
+ self.chat_wins[room_jid].setPresents(list(set([user_nick]+room_nicks)))
def roomUserJoined(self, room_id, room_service, user_nick, user_data, profile):
@@ -387,13 +387,15 @@ class QuickApp():
def updatedValue(self, name, data):
if name == "card_nick":
target = JID(data['jid'])
- self.CM.update(target, 'nick', data['nick'])
- self.contactList.replace(target)
+ if target in self.contactList:
+ self.CM.update(target, 'nick', data['nick'])
+ self.contactList.replace(target)
elif name == "card_avatar":
target = JID(data['jid'])
- filename = self.bridge.getAvatarFile(data['avatar'])
- self.CM.update(target, 'avatar', filename)
- self.contactList.replace(target)
+ if target in self.contactList:
+ filename = self.bridge.getAvatarFile(data['avatar'])
+ self.CM.update(target, 'avatar', filename)
+ self.contactList.replace(target)
def askConfirmation(self, type, id, data):
raise NotImplementedError
diff --git a/frontends/quick_frontend/quick_contact_list.py b/frontends/quick_frontend/quick_contact_list.py
index 7f47e86e..513716da 100644
--- a/frontends/quick_frontend/quick_contact_list.py
+++ b/frontends/quick_frontend/quick_contact_list.py
@@ -32,6 +32,9 @@ class QuickContactList():
"""
debug(_("Contact List init"))
self.CM = CM
+
+ def __contains__(self, jid):
+ raise NotImplementedError
def clear_contacts(self, jid):
"""Clear all the contact list"""
diff --git a/frontends/wix/contact_list.py b/frontends/wix/contact_list.py
index 8cd8a2bf..d96e8fc5 100644
--- a/frontends/wix/contact_list.py
+++ b/frontends/wix/contact_list.py
@@ -29,6 +29,9 @@ class ContactList(wx.SimpleHtmlListBox, QuickContactList):
self.groups = {} #list contacts in each groups, key = group
self.Bind(wx.EVT_LISTBOX, self.onSelected)
self.Bind(wx.EVT_LISTBOX_DCLICK, self.onActivated)
+
+ def __contains__(self, jid):
+ return bool(self.__find_idx(jid))
def __typeSwitch(self):
if self.type == "JID":