changeset 737:378af36155c2

frontends: set and retrieve your own presence and status
author souliane <souliane@mailoo.org>
date Mon, 25 Nov 2013 01:56:07 +0100
parents 6246eb6d64a0
children e867f146d49f
files frontends/src/constants.py frontends/src/primitivus/contact_list.py frontends/src/primitivus/primitivus frontends/src/primitivus/status.py frontends/src/quick_frontend/quick_app.py frontends/src/wix/contact_list.py frontends/src/wix/main_window.py
diffstat 7 files changed, 145 insertions(+), 22 deletions(-) [+]
line wrap: on
line diff
--- a/frontends/src/constants.py	Sat Nov 23 10:21:40 2013 +0100
+++ b/frontends/src/constants.py	Mon Nov 25 01:56:07 2013 +0100
@@ -23,12 +23,35 @@
 except:  # libervia doesn't allow to explicit the exception here
     _ = lambda text: text
 
-class Const(object):
+try:
+    from collections import OrderedDict  # only available from python 2.7
+except ImportError:
+    try:
+        from ordereddict import OrderedDict
+    except ImportError:
+        pass  # libervia can not import external libraries
+
 
-    # TODO: find a way to merge it with the ones of primitivus and wix
-    PRESENCE = {"": _("Online"),
-                "chat": _("Free for chat"),
-                "away": _("Away from keyboard"),
-                "dnd": _("Do not disturb"),
-                "xa": _("Away")
-                }
+def getPresence():
+    """We cannot do it directly in the Const class, if it is not encapsulated
+    in a method we get a JS runtime SyntaxError: "missing ) in parenthetical".
+    # TODO: merge this definition with those in primitivus.constants and wix.constants
+    """
+    try:
+        presence = OrderedDict([("", _("Online")),
+                                ("chat", _("Free for chat")),
+                                ("away", _("Away from keyboard")),
+                                ("dnd", _("Do not disturb")),
+                                ("xa", _("Away"))])
+    except TypeError:
+        presence = {"": _("Online"),
+                    "chat": _("Free for chat"),
+                    "away": _("Away from keyboard"),
+                    "dnd": _("Do not disturb"),
+                    "xa": _("Away")
+                    }
+    return presence
+
+
+class Const(object):
+    PRESENCE = getPresence()
--- a/frontends/src/primitivus/contact_list.py	Sat Nov 23 10:21:40 2013 +0100
+++ b/frontends/src/primitivus/contact_list.py	Mon Nov 25 01:56:07 2013 +0100
@@ -22,6 +22,7 @@
 from sat_frontends.quick_frontend.quick_contact_list import QuickContactList
 from sat_frontends.quick_frontend.quick_utils import escapePrivate, unescapePrivate
 from sat.tools.jid import JID
+from sat_frontends.primitivus.status import StatusBar
 from sat_frontends.primitivus.constants import Const
 
 class ContactList(urwid.WidgetWrap, QuickContactList):
@@ -37,7 +38,8 @@
         self.show_disconnected = False
 
         #we now build the widget
-        self.frame = urwid.Frame(self.__buildList())
+        self.host.status_bar = StatusBar(host)
+        self.frame = urwid.Frame(self.__buildList(), None, self.host.status_bar)
         self.main_widget = sat_widgets.LabelLine(self.frame, sat_widgets.SurroundedText(_("Contacts")))
         urwid.WidgetWrap.__init__(self, self.main_widget)
         if on_click:
--- a/frontends/src/primitivus/primitivus	Sat Nov 23 10:21:40 2013 +0100
+++ b/frontends/src/primitivus/primitivus	Mon Nov 25 01:56:07 2013 +0100
@@ -33,6 +33,7 @@
 from sat_frontends.primitivus.notify import Notify
 from sat_frontends.tools.misc import InputHistory
 from sat_frontends.primitivus.constants import Const
+from sat_frontends.constants import Const as commonConst
 import logging
 from logging import debug, info, error
 from sat.tools.jid  import JID
@@ -119,6 +120,17 @@
         if command == 'quit':
             self.app.onExit()
             raise urwid.ExitMainLoop()
+        elif command == 'presence':
+            self.app.status_bar.onPresenceClick()
+        elif command in ['presence %s' % show for show in commonConst.PRESENCE.keys()]:
+            self.app.status_bar.onChange(user_data=sat_widgets.ClickableText(commonConst.PRESENCE[command[9:]]))
+        elif command == 'status':
+            self.app.status_bar.onStatusClick()
+        elif command.startswith('status '):
+            self.app.status_bar.onChange(user_data=sat_widgets.AdvancedEdit(command[7:]))
+        else:
+            return
+        self.set_edit_text('')
 
     def keypress(self, size, key):
         """Callback when a key is pressed. Send "composing" states
@@ -151,7 +163,7 @@
 
         ## main loop setup ##
         self.main_widget = ProfileManager(self)
-        self.loop = urwid.MainLoop(self.main_widget, const.PALETTE, event_loop=urwid.GLibEventLoop(), input_filter=self.inputFilter, unhandled_input=self.keyHandler)
+        self.loop = urwid.MainLoop(self.main_widget, Const.PALETTE, event_loop=urwid.GLibEventLoop(), input_filter=self.inputFilter, unhandled_input=self.keyHandler)
 
         ##misc setup##
         self.chat_wins = ChatList(self)
@@ -321,10 +333,10 @@
             #we still have popup to show, we display it
             self.showPopUp(next_popup)
 
-    def showPopUp(self, pop_up_widget, perc_width=40, perc_height=40, valign='middle'):
+    def showPopUp(self, pop_up_widget, perc_width=40, perc_height=40, align='center', valign='middle'):
         "Show a pop-up window if possible, else put it in queue"
         if not isinstance(self.loop.widget, urwid.Overlay):
-            display_widget = urwid.Overlay(pop_up_widget, self.main_widget, 'center', ('relative', perc_width), valign, ('relative', perc_height))
+            display_widget = urwid.Overlay(pop_up_widget, self.main_widget, align, ('relative', perc_width), valign, ('relative', perc_height))
             self.loop.widget = display_widget
             self.redraw()
         else:
@@ -590,7 +602,7 @@
             self.showPopUp(pop_up_widget)
 
     def onAboutRequest(self, menu):
-        self.showPopUp(sat_widgets.Alert(_("About"), const.APP_NAME + " v" + self.bridge.getVersion(), ok_cb=self.removePopUp))
+        self.showPopUp(sat_widgets.Alert(_("About"), Const.APP_NAME + " v" + self.bridge.getVersion(), ok_cb=self.removePopUp))
 
     #MISC CALLBACKS#
 
@@ -627,5 +639,13 @@
         if from_bare in self.chat_wins:
             self.chat_wins[from_bare].updateChatState(state)
 
+    def setStatusOnline(self, online=True, show="", statuses={}):
+        if not online or not show or not statuses:
+            return
+        try:
+            self.status_bar.setPresenceStatus(show, statuses['default'])
+        except (KeyError, TypeError):
+            pass
+
 sat = PrimitivusApp()
 sat.start()
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/frontends/src/primitivus/status.py	Mon Nov 25 01:56:07 2013 +0100
@@ -0,0 +1,68 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
+# Primitivus: a SAT frontend
+# Copyright (C) 2013  Adrien Cossa (souliane@mailoo.org)
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU Affero General Public License for more details.
+
+# You should have received a copy of the GNU Affero General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+import urwid
+import copy
+from urwid_satext import sat_widgets
+from sat_frontends.primitivus.xmlui import XMLUI
+from sat_frontends.constants import Const as commonConst
+from sat_frontends.primitivus.constants import Const
+
+
+class StatusBar(urwid.Columns):
+
+    def __init__(self, host):
+        self.host = host
+        self.presence = sat_widgets.ClickableText('')
+        status_prefix = urwid.Text('[')
+        status_suffix = urwid.Text(']')
+        self.status = sat_widgets.ClickableText('')
+        self.setPresenceStatus('', '')
+        urwid.Columns.__init__(self, [('weight', 1, self.presence), ('weight', 1, status_prefix),
+                                      ('weight', 9, self.status), ('weight', 1, status_suffix)])
+        urwid.connect_signal(self.presence, 'click', self.onPresenceClick)
+        urwid.connect_signal(self.status, 'click', self.onStatusClick)
+
+    def onPresenceClick(self, sender=None):
+        options = [commonConst.PRESENCE[presence] for presence in commonConst.PRESENCE]
+        list_widget = sat_widgets.GenericList(options=options, option_type=sat_widgets.ClickableText, on_click=self.onChange)
+        decorated = sat_widgets.LabelLine(list_widget, sat_widgets.SurroundedText(_('Set your presence')))
+        self.host.showPopUp(decorated)
+
+    def onStatusClick(self, sender=None):
+        pop_up_widget = sat_widgets.InputDialog(_('Set your status'), _('New status'), default_txt=self.status.get_text(),
+                                                cancel_cb=lambda dummy: self.host.removePopUp, ok_cb=self.onChange)
+        self.host.showPopUp(pop_up_widget)
+
+    def onChange(self, sender=None, user_data=None):
+        new_value = user_data.get_text()
+        previous = ([key for key in Const.PRESENCE if Const.PRESENCE[key][0] == self.presence.get_text()][0], self.status.get_text())
+        if isinstance(user_data, sat_widgets.ClickableText):
+            new = ([key for key in commonConst.PRESENCE if commonConst.PRESENCE[key] == new_value][0], previous[1])
+        elif isinstance(user_data, sat_widgets.AdvancedEdit):
+            new = (previous[0], new_value[0])
+        if new != previous:
+            self.host.bridge.setPresence(show=new[0], statuses={'default': new[1]}, profile_key=self.host.profile)  #FIXME: manage multilingual statuses
+            self.setPresenceStatus(new[0], new[1])
+        self.host.removePopUp()
+
+    def setPresenceStatus(self, show, status):
+        show_icon, show_attr = Const.PRESENCE.get(show)
+        self.presence.set_text(('show_normal', show_icon))
+        self.status.set_text((show_attr, status))
--- a/frontends/src/quick_frontend/quick_app.py	Sat Nov 23 10:21:40 2013 +0100
+++ b/frontends/src/quick_frontend/quick_app.py	Mon Nov 25 01:56:07 2013 +0100
@@ -294,12 +294,13 @@
         assert alert_type in ['INFO','ERROR']
         self.showDialog(unicode(msg),unicode(title),alert_type.lower())
 
-    def setStatusOnline(self, online=True):
-        pass
+    def setStatusOnline(self, online=True, show="", statuses={}):
+        raise NotImplementedError
 
     def presenceUpdate(self, jabber_id, show, priority, statuses, 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)
@@ -309,7 +310,7 @@
             if show == "unavailable":
                 self.setStatusOnline(False)
             else:
-                self.setStatusOnline(True)
+                self.setStatusOnline(True, show, statuses)
             return
 
         self.contact_list.updatePresence(from_jid, show, priority, statuses)
--- a/frontends/src/wix/contact_list.py	Sat Nov 23 10:21:40 2013 +0100
+++ b/frontends/src/wix/contact_list.py	Mon Nov 25 01:56:07 2013 +0100
@@ -114,7 +114,7 @@
         _show = self.getCache(jid,'show')
         if _show == None or _show == 'unavailable':
             return None
-        show = filter(lambda x : x[0] == _show, Const.PRESENCE)[0]
+        show = [x for x in Const.PRESENCE if x[0] == _show][0]
 
         #show[0]==shortcut
         #show[1]==human readable
--- a/frontends/src/wix/main_window.py	Sat Nov 23 10:21:40 2013 +0100
+++ b/frontends/src/wix/main_window.py	Mon Nov 25 01:56:07 2013 +0100
@@ -76,7 +76,7 @@
                                       style=wx.CB_DROPDOWN | wx.CB_READONLY)
         self.tools.AddControl(self.statusBox)
         self.tools.AddSeparator()
-        self.statusTxt=wx.TextCtrl(self.tools, -1, style = wx.TE_PROCESS_ENTER)
+        self.statusTxt = wx.TextCtrl(self.tools, -1, style=wx.TE_PROCESS_ENTER)
         self.tools.AddControl(self.statusTxt)
         self.Bind(wx.EVT_COMBOBOX, self.onStatusChange, self.statusBox)
         self.Bind(wx.EVT_TEXT_ENTER, self.onStatusChange, self.statusTxt)
@@ -209,11 +209,20 @@
             data = [answer_data] if answer_data else []
             answer_cb(True if (answer == wx.ID_YES or answer == wx.ID_OK) else False, *data)
 
-    def setStatusOnline(self, online=True):
+    def setStatusOnline(self, online=True, show="", statuses={}):
         """enable/disable controls, must be called when local user online status change"""
         if online:
             self.SetStatusText(Const.msgONLINE)
             self.tools.Enable()
+            try:
+                presence = [x for x in Const.PRESENCE if x[0] == show][0][1]
+                self.statusBox.SetValue(presence)
+            except (TypeError, IndexError):
+                pass
+            try:
+                self.statusTxt.SetValue(statuses['default'])
+            except (TypeError, KeyError):
+                pass
         else:
             self.SetStatusText(Const.msgOFFLINE)
             self.tools.Disable()
@@ -351,9 +360,9 @@
         self.bridge.disconnect(self.profile)
 
     def __updateStatus(self):
-        show = filter(lambda x:x[1] == self.statusBox.GetValue(), Const.PRESENCE)[0][0]
-        status =  self.statusTxt.GetValue()
-        self.bridge.setPresence(show=show, statuses={'default':status}, profile_key=self.profile)  #FIXME: manage multilingual statuses
+        show = [x for x in Const.PRESENCE if x[1] == self.statusBox.GetValue()][0][0]
+        status = self.statusTxt.GetValue()
+        self.bridge.setPresence(show=show, statuses={'default': status}, profile_key=self.profile)  #FIXME: manage multilingual statuses
 
     def onStatusChange(self, e):
         debug(_("Status change request"))