primitivus: chat state implementation

for now chat states are displayed in primitivus surrended text (after the contact's name)
This commit is contained in:
souliane 2013-09-08 19:13:02 +02:00
commit 41375e7bde
2 changed files with 126 additions and 63 deletions

View file

@ -145,7 +145,22 @@ class Chat(urwid.WidgetWrap, QuickChat):
self.__appendPresentPanel()
def __getDecoration(self, widget):
return sat_widgets.LabelLine(widget, sat_widgets.SurroundedText(unicode(unescapePrivate(self.target))))
return sat_widgets.LabelLine(widget, self.__getSurrendedText())
def __getSurrendedText(self):
"""Get the text to be displayed as the dialog title."""
if not hasattr(self, "surrended_text"):
self.__setSurrendedText()
return self.surrended_text
def __setSurrendedText(self, state=None):
"""Set the text to be displayed as the dialog title
@param stat: chat state of the contact
"""
text = unicode(unescapePrivate(self.target))
if state:
text += " (" + state + ")"
self.surrended_text = sat_widgets.SurroundedText(text)
def showDecoration(self, show=True):
"""Show/Hide the decoration around the chat window"""
@ -155,6 +170,18 @@ class Chat(urwid.WidgetWrap, QuickChat):
main_widget = self.pile
self._w = main_widget
def updateChatState(self, state):
"""Update the chat state of the contact.
@param state: new state to set
"""
if (self.type == 'one2one'):
self.__setSurrendedText(state)
self.showDecoration()
self.host.redraw()
elif (self.type == 'group'):
# TODO: chat state for groupchat
pass
def _presentClicked(self, list_wid, clicked_wid):
assert(self.type == 'group')
nick = clicked_wid.getValue()

View file

@ -49,6 +49,85 @@ class ChatList(QuickChatList):
def createChat(self, target):
return Chat(target, self.host)
class EditBar(sat_widgets.ModalEdit):
"""
The modal edit bar where you would enter messages and commands.
"""
def __init__(self, app):
modes = {None: ('NORMAL', u''),
'i': ('INSERTION', u'> '),
':': ('COMMAND', u':')} #XXX: captions *MUST* be unicode
super(EditBar, self).__init__(modes)
self.app = app
self.setCompletionMethod(self._text_completion)
urwid.connect_signal(self, 'click', self.onTextEntered)
def _text_completion(self, text, completion_data, mode):
if mode == 'INSERTION':
return self._nick_completion(text, completion_data)
else:
return text
def _nick_completion(self, text, completion_data):
"""Completion method which complete pseudo in group chat
for params, see AdvancedEdit"""
contact = self.app.contact_list.getContact() ###Based on the fact that there is currently only one contact selectable at once
if contact:
chat = self.app.chat_wins[contact]
if chat.type != "group":
return text
space = text.rfind(" ")
start = text[space+1:]
nicks = list(chat.occupants)
nicks.sort()
try:
start_idx=nicks.index(completion_data['last_nick'])+1
if start_idx == len(nicks):
start_idx = 0
except (KeyError,ValueError):
start_idx = 0
for idx in range(start_idx,len(nicks)) + range(0,start_idx):
if nicks[idx].lower().startswith(start.lower()):
completion_data['last_nick'] = nicks[idx]
return text[:space+1] + nicks[idx] + (': ' if space < 0 else '')
return text
def onTextEntered(self, editBar):
"""Called when text is entered in the main edit bar"""
if self.mode == 'INSERTION':
contact = self.app.contact_list.getContact() ###Based on the fact that there is currently only one contact selectableat once
if contact:
chat = self.app.chat_wins[contact]
try:
self.app.sendMessage(contact,
editBar.get_edit_text(),
mess_type = "groupchat" if chat.type == 'group' else "chat",
profile_key=self.app.profile)
except:
self.app.notify(_("Error while sending message"))
editBar.set_edit_text('')
elif self.mode == 'COMMAND':
self.commandHandler()
def commandHandler(self):
#TODO: separate class with auto documentation (with introspection)
# and completion method
command = self.get_edit_text()
if command == 'quit':
self.app.onExit()
raise urwid.ExitMainLoop()
def keypress(self, size, key):
"""Callback when a key is pressed. Send "composing" states."""
if key != "enter":
contact = self.app.contact_list.getContact()
if contact:
self.app.bridge.chatStateComposing(contact, self.app.profile)
return super(EditBar, self).keypress(size, key)
class PrimitivusApp(QuickApp):
def __init__(self):
@ -172,13 +251,6 @@ class PrimitivusApp(QuickApp):
except AttributeError:
return input
def commandHandler(self, editBar):
#TODO: separate class with auto documentation (with introspection)
# and completion method
command = editBar.get_edit_text()
if command == 'quit':
self.onExit()
raise urwid.ExitMainLoop()
def __buildMenuRoller(self):
menu = sat_widgets.Menu(self.loop)
@ -215,48 +287,11 @@ class PrimitivusApp(QuickApp):
#self.center_part = urwid.Columns([('weight',2,self.contact_list),('weight',8,Chat('',self))])
self.center_part = urwid.Columns([('weight',2,self.contact_list), ('weight',8,urwid.Filler(urwid.Text('')))])
modes = {None: ('NORMAL', u''),
'i': ('INSERTION', u'> '),
':': ('COMMAND', u':')} #XXX: captions *MUST* be unicode
self.editBar = sat_widgets.ModalEdit(modes)
self.editBar.setCompletionMethod(self._text_completion)
urwid.connect_signal(self.editBar,'click',self.onTextEntered)
self.editBar = EditBar(self)
self.menu_roller = self.__buildMenuRoller()
self.main_widget = sat_widgets.FocusFrame(self.center_part, header=self.menu_roller, footer=self.editBar, focus_part='footer')
return self.main_widget
def _text_completion(self, text, completion_data, mode):
if mode == 'INSERTION':
return self._nick_completion(text, completion_data)
else:
return text
def _nick_completion(self, text, completion_data):
"""Completion method which complete pseudo in group chat
for params, see AdvancedEdit"""
contact = self.contact_list.getContact() ###Based on the fact that there is currently only one contact selectable at once
if contact:
chat = self.chat_wins[contact]
if chat.type != "group":
return text
space = text.rfind(" ")
start = text[space+1:]
nicks = list(chat.occupants)
nicks.sort()
try:
start_idx=nicks.index(completion_data['last_nick'])+1
if start_idx == len(nicks):
start_idx = 0
except (KeyError,ValueError):
start_idx = 0
for idx in range(start_idx,len(nicks)) + range(0,start_idx):
if nicks[idx].lower().startswith(start.lower()):
completion_data['last_nick'] = nicks[idx]
return text[:space+1] + nicks[idx] + (': ' if space < 0 else '')
return text
def plug_profile(self, profile_key='@DEFAULT@'):
self.loop.widget = self.__buildMainWidget()
self.redraw()
@ -320,23 +355,6 @@ class PrimitivusApp(QuickApp):
self.center_part.widget_list[1] = self.chat_wins[contact]
self.menu_roller.addMenu(_('Chat menu'), self.chat_wins[contact].getMenu())
def onTextEntered(self, editBar):
"""Called when text is entered in the main edit bar"""
if self.mode == 'INSERTION':
contact = self.contact_list.getContact() ###Based on the fact that there is currently only one contact selectableat once
if contact:
chat = self.chat_wins[contact]
try:
self.sendMessage(contact,
editBar.get_edit_text(),
mess_type = "groupchat" if chat.type == 'group' else "chat",
profile_key=self.profile)
except:
self.notify(_("Error while sending message"))
editBar.set_edit_text('')
elif self.mode == 'COMMAND':
self.commandHandler(editBar)
def newMessage(self, from_jid, to_jid, msg, _type, extra, profile):
QuickApp.newMessage(self, from_jid, to_jid, msg, _type, extra, profile)
@ -576,6 +594,24 @@ class PrimitivusApp(QuickApp):
self.showPopUp(sat_widgets.Alert(_("Error"), _("Can't get search UI"), ok_cb=self.removePopUp))
self.bridge.searchRequest(search_jid, dict(data), self.profile, callback=success, errback=failure)
def chatStateReceived(self, from_jid_s, state, profile):
"""Signal observer to display a contact chat state
@param from_jid_s: contact who sent his new state
@state: state
@profile: current profile
"""
if not self.check_profile(profile):
return
if from_jid_s == "@ALL@":
for win in self.chat_wins:
self.chat_wins[win].updateChatState(state)
return
from_bare = JID(from_jid_s).short
if from_bare in self.chat_wins:
self.chat_wins[from_bare].updateChatState(state)
sat = PrimitivusApp()
sat.start()