diff src/browser/libervia_main.py @ 589:a5019e62c3e9 frontends_multi_profiles

browser side: big refactoring to base Libervia on QuickFrontend, first draft: /!\ not finished, partially working and highly instable - add collections module with an OrderedDict like class - SatWebFrontend inherit from QuickApp - general sat_frontends tools.jid module is used - bridge/json methods have moved to json module - UniBox is partially removed (should be totally removed before merge to trunk) - Signals are now register with the generic registerSignal method (which is called mainly in QuickFrontend) - the generic getOrCreateWidget method from QuickWidgetsManager is used instead of Libervia's specific methods - all Widget are now based more or less directly on QuickWidget - with the new QuickWidgetsManager.getWidgets method, it's no more necessary to check all widgets which are instance of a particular class - ChatPanel and related moved to chat module - MicroblogPanel and related moved to blog module - global and overcomplicated send method has been disabled: each class should manage its own sending - for consistency with other frontends, former ContactPanel has been renamed to ContactList and vice versa - for the same reason, ChatPanel has been renamed to Chat - for compatibility with QuickFrontend, a fake profile is used in several places, it is set to C.PROF_KEY_NONE (real profile is managed server side for obvious security reasons) - changed default url for web panel to SàT website, and contact address to generic SàT contact address - ContactList is based on QuickContactList, UI changes are done in update method - bride call (now json module) have been greatly improved, in particular call can be done in the same way as for other frontends (bridge.method_name(arg1, arg2, ..., callback=cb, errback=eb). Blocking method must be called like async methods due to javascript architecture - in bridge calls, a callback can now exists without errback - hard reload on BridgeSignals remote error has been disabled, a better option should be implemented - use of constants where that make sens, some style improvments - avatars are temporarily disabled - lot of code disabled, will be fixed or removed before merge - various other changes, check diff for more details server side: manage remote exception on getEntityData, removed getProfileJid call, added getWaitingConf, added getRoomsSubjects
author Goffi <goffi@goffi.org>
date Sat, 24 Jan 2015 01:45:39 +0100
parents 0a06cf833f5a
children be2891462e63
line wrap: on
line diff
--- a/src/browser/libervia_main.py	Thu Oct 23 16:56:36 2014 +0200
+++ b/src/browser/libervia_main.py	Sat Jan 24 01:45:39 2015 +0100
@@ -17,7 +17,6 @@
 # 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 pyjd  # this is dummy in pyjs
 
 ### logging configuration ###
 from sat_browser import logging
@@ -26,8 +25,11 @@
 log = getLogger(__name__)
 ###
 
+from sat_frontends.quick_frontend.quick_app import QuickApp
+
 from sat_frontends.tools.misc import InputHistory
 from sat_frontends.tools import strings
+from sat_frontends.tools import jid
 from sat.core.i18n import _
 
 from pyjamas.ui.RootPanel import RootPanel
@@ -35,26 +37,30 @@
 from pyjamas.ui.KeyboardListener import KEY_ESCAPE
 from pyjamas.Timer import Timer
 from pyjamas import Window, DOM
-from pyjamas.JSONService import JSONProxy
 
+from sat_browser import json
 from sat_browser import register
-from sat_browser import contact
+from sat_browser.contact_list import ContactList
 from sat_browser import base_widget
 from sat_browser import panels
+from sat_browser import chat
+from sat_browser import blog
 from sat_browser import dialog
-from sat_browser import jid
 from sat_browser import xmlui
 from sat_browser import html_tools
 from sat_browser import notification
 
 from sat_browser.constants import Const as C
 
+
 try:
     # FIXME: import plugin dynamically
     from sat_browser import plugin_sec_otr
 except ImportError:
     pass
 
+unicode = lambda s: str(s)
+
 MAX_MBLOG_CACHE = 500  # Max microblog entries kept in memories
 
 # Set to true to not create a new LiberviaWidget when a similar one
@@ -65,138 +71,25 @@
 REUSE_EXISTING_LIBERVIA_WIDGETS = True
 
 
-class LiberviaJsonProxy(JSONProxy):
-    def __init__(self, *args, **kwargs):
-        JSONProxy.__init__(self, *args, **kwargs)
-        self.handler = self
-        self.cb = {}
-        self.eb = {}
-
-    def call(self, method, cb, *args):
-        _id = self.callMethod(method, args)
-        if cb:
-            if isinstance(cb, tuple):
-                if len(cb) != 2:
-                    log.error("tuple syntax for bridge.call is (callback, errback), aborting")
-                    return
-                if cb[0] is not None:
-                    self.cb[_id] = cb[0]
-                self.eb[_id] = cb[1]
-            else:
-                self.cb[_id] = cb
-
-    def onRemoteResponse(self, response, request_info):
-        if request_info.id in self.cb:
-            _cb = self.cb[request_info.id]
-            # if isinstance(_cb, tuple):
-            #     #we have arguments attached to the callback
-            #     #we send them after the answer
-            #     callback, args = _cb
-            #     callback(response, *args)
-            # else:
-            #     #No additional argument, we call directly the callback
-            _cb(response)
-            del self.cb[request_info.id]
-            if request_info.id in self.eb:
-                del self.eb[request_info.id]
-
-    def onRemoteError(self, code, errobj, request_info):
-        """def dump(obj):
-            print "\n\nDUMPING %s\n\n" % obj
-            for i in dir(obj):
-                print "%s: %s" % (i, getattr(obj,i))"""
-        if request_info.id in self.eb:
-            _eb = self.eb[request_info.id]
-            _eb((code, errobj))
-            del self.cb[request_info.id]
-            del self.eb[request_info.id]
-        else:
-            if code != 0:
-                log.error("Internal server error")
-                """for o in code, error, request_info:
-                    dump(o)"""
-            else:
-                if isinstance(errobj['message'], dict):
-                    log.error("Error %s: %s" % (errobj['message']['faultCode'], errobj['message']['faultString']))
-                else:
-                    log.error("%s" % errobj['message'])
-
-
-class RegisterCall(LiberviaJsonProxy):
-    def __init__(self):
-        LiberviaJsonProxy.__init__(self, "/register_api",
-                        ["isRegistered", "isConnected", "asyncConnect", "registerParams", "getMenus"])
-
-
-class BridgeCall(LiberviaJsonProxy):
-    def __init__(self):
-        LiberviaJsonProxy.__init__(self, "/json_api",
-                        ["getContacts", "addContact", "sendMessage", "sendMblog", "sendMblogComment",
-                         "getLastMblogs", "getMassiveLastMblogs", "getMblogComments", "getProfileJid",
-                         "getHistory", "getPresenceStatuses", "joinMUC", "mucLeave", "getRoomsJoined",
-                         "inviteMUC", "launchTarotGame", "getTarotCardsPaths", "tarotGameReady",
-                         "tarotGamePlayCards", "launchRadioCollective", "getMblogs", "getMblogsWithComments",
-                         "getWaitingSub", "subscription", "delContact", "updateContact", "getCard",
-                         "getEntityData", "getParamsUI", "asyncGetParamA", "setParam", "launchAction",
-                         "disconnect", "chatStateComposing", "getNewAccountDomain", "confirmationAnswer",
-                         "syntaxConvert", "getAccountDialogUI", "getLastResource"
-                        ])
-
-
-class BridgeSignals(LiberviaJsonProxy):
-    RETRY_BASE_DELAY = 1000
-
-    def __init__(self, host):
-        self.host = host
-        self.retry_delay = self.RETRY_BASE_DELAY
-        LiberviaJsonProxy.__init__(self, "/json_signal_api",
-                        ["getSignals"])
-
-    def onRemoteResponse(self, response, request_info):
-        self.retry_delay = self.RETRY_BASE_DELAY
-        LiberviaJsonProxy.onRemoteResponse(self, response, request_info)
-
-    def onRemoteError(self, code, errobj, request_info):
-        if errobj['message'] == 'Empty Response':
-            Window.getLocation().reload()  # XXX: reset page in case of session ended.
-                                           # FIXME: Should be done more properly without hard reload
-        LiberviaJsonProxy.onRemoteError(self, code, errobj, request_info)
-        #we now try to reconnect
-        if isinstance(errobj['message'], dict) and errobj['message']['faultCode'] == 0:
-            Window.alert('You are not allowed to connect to server')
-        else:
-            def _timerCb(timer):
-                self.host.bridge_signals.call('getSignals', self.host._getSignalsCB)
-            Timer(notify=_timerCb).schedule(self.retry_delay)
-            self.retry_delay *= 2
-
-
-class SatWebFrontend(InputHistory):
+class SatWebFrontend(InputHistory, QuickApp):
     def onModuleLoad(self):
         log.info("============ onModuleLoad ==============")
-        panels.ChatPanel.registerClass()
-        panels.MicroblogPanel.registerClass()
-        self.whoami = None
-        self._selected_listeners = set()
-        self.bridge = BridgeCall()
-        self.bridge_signals = BridgeSignals(self)
-        self.uni_box = None
+        self.bridge_signals = json.BridgeSignals(self)
+        QuickApp.__init__(self, json.BridgeCall)
+        self.uni_box = None # FIXME: to be removed
         self.status_panel = HTML('<br />')
-        self.contact_panel = contact.ContactPanel(self)
+        # self.contact_panel = contact.ContactPanel(self)
         self.panel = panels.MainPanel(self)
         self.discuss_panel = self.panel.discuss_panel
         self.tab_panel = self.panel.tab_panel
         self.tab_panel.addTabListener(self)
-        self.libervia_widgets = set()  # keep track of all actives LiberviaWidgets
-        self.room_list = []  # list of rooms
-        self.mblog_cache = []  # used to keep our own blog entries in memory, to show them in new mblog panel
-        self.avatars_cache = {}  # keep track of jid's avatar hash (key=jid, value=file)
         self._register_box = None
         RootPanel().add(self.panel)
+
         self.notification = notification.Notification()
         DOM.addEventPreview(self)
         self.importPlugins()
-        self._register = RegisterCall()
+        self._register = json.RegisterCall()
         self._register.call('getMenus', self.gotMenus)
         self._register.call('registerParams', None)
         self._register.call('isRegistered', self._isRegisteredCB)
@@ -204,6 +97,36 @@
         self.init_cache = []  # used to cache events until initialisation is done
         self.cached_params = {}
 
+        #FIXME: to be removed (managed with cache and in quick_frontend
+        self.avatars_cache = {}  # keep track of jid's avatar hash (key=jid, value=file)
+        #FIXME: microblog cache should be managed directly in blog module
+        self.mblog_cache = []  # used to keep our own blog entries in memory, to show them in new mblog panel
+
+
+
+        # panels.ChatPanel.registerClass()
+        # panels.MicroblogPanel.registerClass()
+        # self._selected_listeners = set()
+        # # self.avatars_cache = {}  # keep track of jid's avatar hash (key=jid, value=file)
+
+    @property
+    def whoami(self):
+        # XXX: works because Libervia is mono-profile
+        #      if one day Libervia manage several profiles at once, this must be deleted
+        return self.profiles[C.PROF_KEY_NONE].whoami
+
+    @property
+    def contact_list(self):
+        return self.contact_lists[C.PROF_KEY_NONE]
+
+    def registerSignal(self, functionName, handler=None, iface="core", with_profile=True):
+        if handler is None:
+            callback = getattr(self, "{}{}".format(functionName, "Handler"))
+        else:
+            callback = handler
+
+        self.bridge_signals.register(functionName, callback, with_profile=with_profile)
+
     def importPlugins(self):
         self.plugins = {}
         inhibited_menus = []
@@ -219,8 +142,8 @@
 
         self.plugins['dummy_plugin'] = DummyPlugin()
 
-    def addSelectedListener(self, callback):
-        self._selected_listeners.add(callback)
+    # def addSelectedListener(self, callback):
+    #     self._selected_listeners.add(callback)
 
     def getSelected(self):
         wid = self.tab_panel.getCurrentPanel()
@@ -244,12 +167,14 @@
             selected.removeStyleName('selected_widget')
 
         widgets_panel.selected = widget
+        self.selected_widget = widget
 
         if widget:
             widgets_panel.selected.addStyleName('selected_widget')
 
-        for callback in self._selected_listeners:
-            callback(widget)
+        # FIXME:
+        # for callback in self._selected_listeners:
+        #     callback(widget)
 
     def resize(self):
         """Resize elements"""
@@ -260,8 +185,9 @@
 
     def onTabSelected(self, sender, tab_index):
         selected = self.getSelected()
-        for callback in self._selected_listeners:
-            callback(selected)
+        # FIXME:
+        # for callback in self._selected_listeners:
+        #     callback(selected)
 
     def onEventPreview(self, event):
         if event.type in ["keydown", "keypress", "keyup"] and event.keyCode == KEY_ESCAPE:
@@ -269,26 +195,28 @@
             event.preventDefault()
         return True
 
-    def getAvatar(self, jid_str):
-        """Return avatar of a jid if in cache, else ask for it.
+    # FIXME: must not call _entityDataUpdatedCb by itself
+    #        should not get VCard, backend plugin must be fixed too
+    # def getAvatar(self, jid_str):
+    #     """Return avatar of a jid if in cache, else ask for it.
 
-        @param jid_str (str): JID of the contact
-        @return: the URL to the avatar (str)
-        """
-        def dataReceived(result):
-            if 'avatar' in result:
-                self._entityDataUpdatedCb(jid_str, 'avatar', result['avatar'])
-            else:
-                self.bridge.call("getCard", None, jid_str)
+    #     @param jid_str (str): JID of the contact
+    #     @return: the URL to the avatar (str)
+    #     """
+    #     def dataReceived(result):
+    #         if 'avatar' in result:
+    #             self._entityDataUpdatedCb(jid_str, 'avatar', result['avatar'])
+    #         else:
+    #             self.bridge.call("getCard", None, jid_str)
 
-        def avatarError(error_data):
-            # The jid is maybe not in our roster, we ask for the VCard
-            self.bridge.call("getCard", None, jid_str)
+    #     def avatarError(error_data):
+    #         # The jid is maybe not in our roster, we ask for the VCard
+    #         self.bridge.call("getCard", None, jid_str)
 
-        if jid_str not in self.avatars_cache:
-            self.bridge.call('getEntityData', (dataReceived, avatarError), jid_str, ['avatar'])
-            self.avatars_cache[jid_str] = C.DEFAULT_AVATAR
-        return self.avatars_cache[jid_str]
+    #     if jid_str not in self.avatars_cache:
+    #         self.bridge.call('getEntityData', (dataReceived, avatarError), jid_str, ['avatar'])
+    #         self.avatars_cache[jid_str] = C.DEFAULT_AVATAR
+    #     return self.avatars_cache[jid_str]
 
     def registerWidget(self, wid):
         log.debug("Registering %s" % wid.getDebugName())
@@ -303,10 +231,6 @@
     def refresh(self):
         """Refresh the general display."""
         self.panel.refresh()
-        if self.getCachedParam(C.COMPOSITION_KEY, C.ENABLE_UNIBOX_PARAM) == 'true':
-            self.uni_box = self.panel.unibox_panel.unibox
-        else:
-            self.uni_box = None
         for lib_wid in self.libervia_widgets:
             lib_wid.refresh()
         self.resize()
@@ -326,8 +250,10 @@
 
     def addWidget(self, wid, tab_index=None):
         """ Add a widget at the bottom of the current or specified tab
+
         @param wid: LiberviaWidget to add
-        @param tab_index: index of the tab to add the widget to"""
+        @param tab_index: index of the tab to add the widget to
+        """
         if tab_index is None or tab_index < 0 or tab_index >= self.tab_panel.getWidgetCount():
             panel = self.tab_panel.getCurrentPanel()
         else:
@@ -351,7 +277,7 @@
                 menus_data.append((id_, path, path_i18n))
 
         self.menus = {}
-        inhibited = set()
+        inhibited = set() # FIXME
         extras = []
         for plugin in self.plugins.values():
             if hasattr(plugin, "inhibitMenus"):
@@ -390,12 +316,14 @@
         self.status_panel = panels.PresenceStatusPanel(self)
         self.panel.header.add(self.status_panel)
 
+        self.bridge_signals.call('getSignals', self.bridge_signals.signalHandler)
+
         #it's time to fill the page
-        self.bridge.call('getContacts', self._getContactsCB)
-        self.bridge.call('getParamsUI', self._getParamsUICB)
-        self.bridge_signals.call('getSignals', self._getSignalsCB)
-        #We want to know our own jid
-        self.bridge.call('getProfileJid', self._getProfileJidCB)
+        # self.bridge.call('getContacts', self._getContactsCB)
+        # self.bridge.call('getParamsUI', self._getParamsUICB)
+        # self.bridge_signals.call('getSignals', self._getSignalsCB)
+        # #We want to know our own jid
+        # self.bridge.call('getProfileJid', self._getProfileJidCB)
 
         def domain_cb(value):
             self._defaultDomain = value
@@ -404,18 +332,50 @@
         def domain_eb(value):
             self._defaultDomain = "libervia.org"
 
-        self.bridge.call("getNewAccountDomain", (domain_cb, domain_eb))
-        self.discuss_panel.addWidget(panels.MicroblogPanel(self, []))
+        self.bridge.getNewAccountDomain(callback=domain_cb, errback=domain_eb)
+        self.plug_profiles([C.PROF_KEY_NONE]) # XXX: None was used intitially, but pyjamas bug when using variable arguments and None is the only arg.
+        microblog_widget = self.widgets.getOrCreateWidget(blog.MicroblogPanel, (), profile=C.PROF_KEY_NONE)
+        self.setSelected(microblog_widget)
+        # self.discuss_panel.addWidget(panels.MicroblogPanel(self, []))
+
+        # # get cached params and refresh the display
+        # def param_cb(cat, name, count):
+        #     count[0] += 1
+        #     refresh = count[0] == len(C.CACHED_PARAMS)
+        #     return lambda value: self._paramUpdate(name, value, cat, refresh)
+
+        # count = [0]  # used to do something similar to DeferredList
+        # for cat, name in C.CACHED_PARAMS:
+        #     self.bridge.call('asyncGetParamA', param_cb(cat, name, count), name, cat)
 
-        # get cached params and refresh the display
-        def param_cb(cat, name, count):
-            count[0] += 1
-            refresh = count[0] == len(C.CACHED_PARAMS)
-            return lambda value: self._paramUpdate(name, value, cat, refresh)
+    def profilePlugged(self, profile):
+        #we fill the panels already here
+        for widget in self.widgets.getWidgets(blog.MicroblogPanel):
+            if widget.accept_all():
+                self.bridge.getMassiveLastMblogs('ALL', [], 10, profile=C.PROF_KEY_NONE, callback=widget.massiveInsert)
+            else:
+                self.bridge.getMassiveLastMblogs('GROUP', widget.accepted_groups, 10, profile=C.PROF_KEY_NONE, callback=widget.massiveInsert)
+
+        #we ask for our own microblogs:
+        self.bridge.getMassiveLastMblogs('JID', [unicode(self.whoami.bare)], 10, profile=C.PROF_KEY_NONE, callback=self._ownBlogsFills)
 
-        count = [0]  # used to do something similar to DeferredList
-        for cat, name in C.CACHED_PARAMS:
-            self.bridge.call('asyncGetParamA', param_cb(cat, name, count), name, cat)
+        # initialize plugins which waited for the connection to be done
+        for plugin in self.plugins.values():
+            if hasattr(plugin, 'profileConnected'):
+                plugin.profileConnected()
+
+    def addContactList(self, dummy):
+        contact_list = ContactList(self)
+        self.contact_lists[C.PROF_KEY_NONE] = contact_list
+        self.panel.addContactList(contact_list)
+        return contact_list
+
+    def newWidget(self, widget):
+        log.debug("newWidget: {}".format(widget))
+        self.addWidget(widget)
+
+    def setStatusOnline(self, online=True, show="", statuses={}, profile=C.PROF_KEY_NONE):
+        log.warning("setStatusOnline is not implemented, as session are for unique profile which is always online for now")
 
     def _tryAutoConnect(self, skip_validation=False):
         """This method retrieve the eventual URL parameters to auto-connect the user.
@@ -471,71 +431,6 @@
             jid, attributes, groups = contact_
             self._newContactCb(jid, attributes, groups)
 
-    def _getSignalsCB(self, signal_data):
-        self.bridge_signals.call('getSignals', self._getSignalsCB)
-        if len(signal_data) == 1:
-            signal_data.append([])
-        log.debug("Got signal ==> name: %s, params: %s" % (signal_data[0], signal_data[1]))
-        name, args = signal_data
-        if name == 'personalEvent':
-            self._personalEventCb(*args)
-        elif name == 'newMessage':
-            self._newMessageCb(*args)
-        elif name == 'presenceUpdate':
-            self._presenceUpdateCb(*args)
-        elif name == 'paramUpdate':
-            self._paramUpdate(*args)
-        elif name == 'roomJoined':
-            self._roomJoinedCb(*args)
-        elif name == 'roomLeft':
-            self._roomLeftCb(*args)
-        elif name == 'roomUserJoined':
-            self._roomUserJoinedCb(*args)
-        elif name == 'roomUserLeft':
-            self._roomUserLeftCb(*args)
-        elif name == 'roomUserChangedNick':
-            self._roomUserChangedNickCb(*args)
-        elif name == 'askConfirmation':
-            self._askConfirmation(*args)
-        elif name == 'newAlert':
-            self._newAlert(*args)
-        elif name == 'tarotGamePlayers':
-            self._tarotGameStartedCb(True, *args)
-        elif name == 'tarotGameStarted':
-            self._tarotGameStartedCb(False, *args)
-        elif name == 'tarotGameNew' or \
-             name == 'tarotGameChooseContrat' or \
-             name == 'tarotGameShowCards' or \
-             name == 'tarotGameInvalidCards' or \
-             name == 'tarotGameCardsPlayed' or \
-             name == 'tarotGameYourTurn' or \
-             name == 'tarotGameScore':
-            self._tarotGameGenericCb(name, args[0], args[1:])
-        elif name == 'radiocolPlayers':
-            self._radioColStartedCb(True, *args)
-        elif name == 'radiocolStarted':
-            self._radioColStartedCb(False, *args)
-        elif name == 'radiocolPreload':
-            self._radioColGenericCb(name, args[0], args[1:])
-        elif name == 'radiocolPlay':
-            self._radioColGenericCb(name, args[0], args[1:])
-        elif name == 'radiocolNoUpload':
-            self._radioColGenericCb(name, args[0], args[1:])
-        elif name == 'radiocolUploadOk':
-            self._radioColGenericCb(name, args[0], args[1:])
-        elif name == 'radiocolSongRejected':
-            self._radioColGenericCb(name, args[0], args[1:])
-        elif name == 'subscribe':
-            self._subscribeCb(*args)
-        elif name == 'contactDeleted':
-            self._contactDeletedCb(*args)
-        elif name == 'newContact':
-            self._newContactCb(*args)
-        elif name == 'entityDataUpdated':
-            self._entityDataUpdatedCb(*args)
-        elif name == 'chatStateReceived':
-            self._chatStateReceivedCb(*args)
-
     def _getParamsUICB(self, xml_ui):
         """Hide the parameters item if there's nothing to display"""
         if not xml_ui:
@@ -552,42 +447,45 @@
                     _groups = set(mblog['groups'].split() if mblog['groups'] else [])
                 else:
                     _groups = None
-                mblog_entry = panels.MicroblogItem(mblog)
+                mblog_entry = blog.MicroblogItem(mblog)
                 self.mblog_cache.append((_groups, mblog_entry))
 
         if len(self.mblog_cache) > MAX_MBLOG_CACHE:
             del self.mblog_cache[0:len(self.mblog_cache - MAX_MBLOG_CACHE)]
-        for lib_wid in self.libervia_widgets:
-            if isinstance(lib_wid, panels.MicroblogPanel):
-                self.FillMicroblogPanel(lib_wid)
+        for widget in self.widgets.getWidgets(blog.MicroblogPanel):
+            self.FillMicroblogPanel(widget)
+
+        # FIXME
         self.initialised = True  # initialisation phase is finished here
         for event_data in self.init_cache:  # so we have to send all the cached events
             self._personalEventCb(*event_data)
         del self.init_cache
 
     def _getProfileJidCB(self, jid_s):
-        self.whoami = jid.JID(jid_s)
-        #we can now ask our status
-        self.bridge.call('getPresenceStatuses', self._getPresenceStatusesCb)
-        #the rooms where we are
-        self.bridge.call('getRoomsJoined', self._getRoomsJoinedCb)
-        #and if there is any subscription request waiting for us
-        self.bridge.call('getWaitingSub', self._getWaitingSubCb)
-        #we fill the panels already here
-        for lib_wid in self.libervia_widgets:
-            if isinstance(lib_wid, panels.MicroblogPanel):
-                if lib_wid.accept_all():
-                    self.bridge.call('getMassiveLastMblogs', lib_wid.massiveInsert, 'ALL', [], 10)
-                else:
-                    self.bridge.call('getMassiveLastMblogs', lib_wid.massiveInsert, 'GROUP', lib_wid.accepted_groups, 10)
+        # FIXME
+        raise Exception("should not be here !")
+        # self.whoami = jid.JID(jid_s)
+        # #we can now ask our status
+        # self.bridge.call('getPresenceStatuses', self._getPresenceStatusesCb)
+        # #the rooms where we are
+        # self.bridge.call('getRoomsJoined', self._getRoomsJoinedCb)
+        # #and if there is any subscription request waiting for us
+        # self.bridge.call('getWaitingSub', self._getWaitingSubCb)
+        # #we fill the panels already here
+        # for lib_wid in self.libervia_widgets:
+        #     if isinstance(lib_wid, panels.MicroblogPanel):
+        #         if lib_wid.accept_all():
+        #             self.bridge.call('getMassiveLastMblogs', lib_wid.massiveInsert, 'ALL', [], 10)
+        #         else:
+        #             self.bridge.call('getMassiveLastMblogs', lib_wid.massiveInsert, 'GROUP', lib_wid.accepted_groups, 10)
 
-        #we ask for our own microblogs:
-        self.bridge.call('getMassiveLastMblogs', self._ownBlogsFills, 'JID', [self.whoami.bare], 10)
+        # #we ask for our own microblogs:
+        # self.bridge.call('getMassiveLastMblogs', self._ownBlogsFills, 'JID', [self.whoami.bare], 10)
 
-        # initialize plugins which waited for the connection to be done
-        for plugin in self.plugins.values():
-            if hasattr(plugin, 'profileConnected'):
-                plugin.profileConnected()
+        # # initialize plugins which waited for the connection to be done
+        # for plugin in self.plugins.values():
+        #     if hasattr(plugin, 'profileConnected'):
+        #         plugin.profileConnected()
 
     ## Signals callbacks ##
 
@@ -604,11 +502,10 @@
                 _groups = set(data['groups'].split() if data['groups'] else [])
             else:
                 _groups = None
-            mblog_entry = panels.MicroblogItem(data)
+            mblog_entry = blog.MicroblogItem(data)
 
-            for lib_wid in self.libervia_widgets:
-                if isinstance(lib_wid, panels.MicroblogPanel):
-                    self.addBlogEntry(lib_wid, sender, _groups, mblog_entry)
+            for widget in self.widgets.getWidgets(blog.MicroblogPanel):
+                self.addBlogEntry(widget, sender, _groups, mblog_entry)
 
             if sender == self.whoami.bare:
                 found = False
@@ -625,9 +522,8 @@
                     if len(self.mblog_cache) > MAX_MBLOG_CACHE:
                         del self.mblog_cache[0:len(self.mblog_cache - MAX_MBLOG_CACHE)]
         elif event_type == 'MICROBLOG_DELETE':
-            for lib_wid in self.libervia_widgets:
-                if isinstance(lib_wid, panels.MicroblogPanel):
-                    lib_wid.removeEntry(data['type'], data['id'])
+            for widget in self.widgets.getWidgets(blog.MicroblogPanel):
+                widget.removeEntry(data['type'], data['id'])
             log.debug("%s %s %s" % (self.whoami.bare, sender, data['type']))
 
             if sender == self.whoami.bare and data['type'] == 'main_item':
@@ -663,209 +559,209 @@
                 if lib_wid.isJidAccepted(entity):
                     self.bridge.call('getMassiveLastMblogs', lib_wid.massiveInsert, 'JID', [entity], 10)
 
-    def getLiberviaWidget(self, class_, entity, ignoreOtherTabs=True):
-        """Get the corresponding panel if it exists.
-        @param class_ (class): class of the panel (ChatPanel, MicroblogPanel...)
-        @param entity (dict): dictionnary to define the entity.
-        @param ignoreOtherTabs (bool): if True, the widgets that are not
-        contained by the currently selected tab will be ignored
-        @return: the existing widget that has been found or None."""
-        selected_tab = self.tab_panel.getCurrentPanel()
-        for lib_wid in self.libervia_widgets:
-            parent = lib_wid.getWidgetsPanel(expect=False)
-            if parent is None or (ignoreOtherTabs and parent != selected_tab):
-                # do not return a widget that is not in the currently selected tab
-                continue
-            if isinstance(lib_wid, class_):
-                try:
-                    if lib_wid.matchEntity(*(entity.values())):  # XXX: passing **entity bugs!
-                        log.debug("existing widget found: %s" % lib_wid.getDebugName())
-                        return lib_wid
-                except AttributeError as e:
-                    e.stack_list()
-                    return None
-        return None
+    # def getLiberviaWidget(self, class_, entity, ignoreOtherTabs=True):
+    #     """Get the corresponding panel if it exists.
+    #     @param class_ (class): class of the panel (ChatPanel, MicroblogPanel...)
+    #     @param entity (dict): dictionnary to define the entity.
+    #     @param ignoreOtherTabs (bool): if True, the widgets that are not
+    #     contained by the currently selected tab will be ignored
+    #     @return: the existing widget that has been found or None."""
+    #     selected_tab = self.tab_panel.getCurrentPanel()
+    #     for lib_wid in self.libervia_widgets:
+    #         parent = lib_wid.getWidgetsPanel(expect=False)
+    #         if parent is None or (ignoreOtherTabs and parent != selected_tab):
+    #             # do not return a widget that is not in the currently selected tab
+    #             continue
+    #         if isinstance(lib_wid, class_):
+    #             try:
+    #                 if lib_wid.matchEntity(*(entity.values())):  # XXX: passing **entity bugs!
+    #                     log.debug("existing widget found: %s" % lib_wid.getDebugName())
+    #                     return lib_wid
+    #             except AttributeError as e:
+    #                 e.stack_list()
+    #                 return None
+    #     return None
 
-    def getOrCreateLiberviaWidget(self, class_, entity, select=True, new_tab=None):
-        """Get the matching LiberviaWidget if it exists, or create a new one.
-        @param class_ (class): class of the panel (ChatPanel, MicroblogPanel...)
-        @param entity (dict): dictionnary to define the entity.
-        @param select (bool): if True, select the widget that has been found or created
-        @param new_tab (str): if not None, a widget which is created is created in
-        a new tab. In that case new_tab is a unicode to label that new tab.
-        If new_tab is not None and a widget is found, no tab is created.
-        @return: the newly created wigdet if REUSE_EXISTING_LIBERVIA_WIDGETS
-         is set to False or if the widget has not been found, the existing
-         widget that has been found otherwise."""
-        lib_wid = None
-        tab = None
-        if REUSE_EXISTING_LIBERVIA_WIDGETS:
-            lib_wid = self.getLiberviaWidget(class_, entity, new_tab is None)
-        if lib_wid is None:  # create a new widget
-            lib_wid = class_.createPanel(self, *(entity.values()))  # XXX: passing **entity bugs!
-            if new_tab is None:
-                self.addWidget(lib_wid)
-            else:
-                tab = self.addTab(new_tab, lib_wid, False)
-        else:  # reuse existing widget
-            tab = lib_wid.getWidgetsPanel(expect=False)
-            if new_tab is None:
-                if tab is not None:
-                    tab.removeWidget(lib_wid)
-                self.addWidget(lib_wid)
-        if select:
-            if new_tab is not None:
-                self.tab_panel.selectTab(tab)
-            # must be done after the widget is added,
-            # for example to scroll to the bottom
-            self.setSelected(lib_wid)
-            lib_wid.refresh()
-        return lib_wid
+    # def getOrCreateLiberviaWidget(self, class_, entity, select=True, new_tab=None):
+    #     """Get the matching LiberviaWidget if it exists, or create a new one.
+    #     @param class_ (class): class of the panel (ChatPanel, MicroblogPanel...)
+    #     @param entity (dict): dictionnary to define the entity.
+    #     @param select (bool): if True, select the widget that has been found or created
+    #     @param new_tab (str): if not None, a widget which is created is created in
+    #     a new tab. In that case new_tab is a unicode to label that new tab.
+    #     If new_tab is not None and a widget is found, no tab is created.
+    #     @return: the newly created wigdet if REUSE_EXISTING_LIBERVIA_WIDGETS
+    #      is set to False or if the widget has not been found, the existing
+    #      widget that has been found otherwise."""
+    #     lib_wid = None
+    #     tab = None
+    #     if REUSE_EXISTING_LIBERVIA_WIDGETS:
+    #         lib_wid = self.getLiberviaWidget(class_, entity, new_tab is None)
+    #     if lib_wid is None:  # create a new widget
+    #         lib_wid = class_.createPanel(self, *(entity.values()))  # XXX: passing **entity bugs!
+    #         if new_tab is None:
+    #             self.addWidget(lib_wid)
+    #         else:
+    #             tab = self.addTab(new_tab, lib_wid, False)
+    #     else:  # reuse existing widget
+    #         tab = lib_wid.getWidgetsPanel(expect=False)
+    #         if new_tab is None:
+    #             if tab is not None:
+    #                 tab.removeWidget(lib_wid)
+    #             self.addWidget(lib_wid)
+    #     if select:
+    #         if new_tab is not None:
+    #             self.tab_panel.selectTab(tab)
+    #         # must be done after the widget is added,
+    #         # for example to scroll to the bottom
+    #         self.setSelected(lib_wid)
+    #         lib_wid.refresh()
+    #     return lib_wid
 
-    def getRoomWidget(self, target):
-        """Get the MUC widget for the given target.
+    # def getRoomWidget(self, target):
+    #     """Get the MUC widget for the given target.
 
-        @param target (jid.JID): BARE jid of the MUC
-        @return: panels.ChatPanel instance or None
-        """
-        entity = {'item': target, 'type_': 'group'}
-        if target.full() in self.room_list or target in self.room_list:  # as JID is a string-based class, we don't know what will please Pyjamas...
-            return self.getLiberviaWidget(panels.ChatPanel, entity, ignoreOtherTabs=False)
-        return None
+    #     @param target (jid.JID): BARE jid of the MUC
+    #     @return: panels.ChatPanel instance or None
+    #     """
+    #     entity = {'item': target, 'type_': 'group'}
+    #     if target.full() in self.room_list or target in self.room_list:  # as JID is a string-based class, we don't know what will please Pyjamas...
+    #         return self.getLiberviaWidget(panels.ChatPanel, entity, ignoreOtherTabs=False)
+    #     return None
 
-    def getOrCreateRoomWidget(self, target):
-        """Get the MUC widget for the given target, create it if necessary.
+    # def getOrCreateRoomWidget(self, target):
+    #     """Get the MUC widget for the given target, create it if necessary.
 
-        @param target (jid.JID): BARE jid of the MUC
-        @return: panels.ChatPanel instance
-        """
-        lib_wid = self.getRoomWidget(target)
-        if lib_wid:
-            return lib_wid
+    #     @param target (jid.JID): BARE jid of the MUC
+    #     @return: panels.ChatPanel instance
+    #     """
+    #     lib_wid = self.getRoomWidget(target)
+    #     if lib_wid:
+    #         return lib_wid
 
-        # XXX: target.node.startwith(...) raises an error "startswith is not a function"
-        # This happens when node a is property defined in the JID class
-        # FIXME: pyjamas doesn't handle the properties well
-        node = target.node
+    #     # XXX: target.node.startwith(...) raises an error "startswith is not a function"
+    #     # This happens when node a is property defined in the JID class
+    #     # FIXME: pyjamas doesn't handle the properties well
+    #     node = target.node
 
-        # XXX: it's not really beautiful, but it works :)
-        if node.startswith('sat_tarot_'):
-            tab_name = "Tarot"
-        elif node.startswith('sat_radiocol_'):
-            tab_name = "Radio collective"
-        else:
-            tab_name = target.node
+    #     # XXX: it's not really beautiful, but it works :)
+    #     if node.startswith('sat_tarot_'):
+    #         tab_name = "Tarot"
+    #     elif node.startswith('sat_radiocol_'):
+    #         tab_name = "Radio collective"
+    #     else:
+    #         tab_name = target.node
 
-        self.room_list.append(target)
-        entity = {'item': target, 'type_': 'group'}
-        return self.getOrCreateLiberviaWidget(panels.ChatPanel, entity, new_tab=tab_name)
+    #     self.room_list.append(target)
+    #     entity = {'item': target, 'type_': 'group'}
+    #     return self.getOrCreateLiberviaWidget(panels.ChatPanel, entity, new_tab=tab_name)
 
-    def _newMessageCb(self, from_jid_s, msg, msg_type, to_jid_s, extra):
-        from_jid = jid.JID(from_jid_s)
-        to_jid = jid.JID(to_jid_s)
-        for plugin in self.plugins.values():
-            if hasattr(plugin, 'messageReceivedTrigger'):
-                if not plugin.messageReceivedTrigger(from_jid, msg, msg_type, to_jid, extra):
-                    return  # plugin returned False to interrupt the process
-        self.newMessageCb(from_jid, msg, msg_type, to_jid, extra)
+    # def _newMessageCb(self, from_jid_s, msg, msg_type, to_jid_s, extra):
+    #     from_jid = jid.JID(from_jid_s)
+    #     to_jid = jid.JID(to_jid_s)
+    #     for plugin in self.plugins.values():
+    #         if hasattr(plugin, 'messageReceivedTrigger'):
+    #             if not plugin.messageReceivedTrigger(from_jid, msg, msg_type, to_jid, extra):
+    #                 return  # plugin returned False to interrupt the process
+    #     self.newMessageCb(from_jid, msg, msg_type, to_jid, extra)
 
-    def newMessageCb(self, from_jid, msg, msg_type, to_jid, extra):
-        other = to_jid if from_jid.bare == self.whoami.bare else from_jid
-        lib_wid = self.getLiberviaWidget(panels.ChatPanel, {'item': other}, ignoreOtherTabs=False)
-        self.displayNotification(from_jid, msg)
-        if msg_type == 'headline' and from_jid.full() == self._defaultDomain:
-            try:
-                assert extra['subject']  # subject is defined and not empty
-                title = extra['subject']
-            except (KeyError, AssertionError):
-                title = _('Announcement from %s') % from_jid.full()
-            msg = strings.addURLToText(html_tools.XHTML2Text(msg))
-            dialog.InfoDialog(title, msg).show()
-            return
-        if lib_wid is not None:
-            if msg_type == C.MESS_TYPE_INFO:
-                lib_wid.printInfo(msg)
-            else:
-                lib_wid.printMessage(from_jid, msg, extra)
-            if 'header_info' in extra:
-                lib_wid.setHeaderInfo(extra['header_info'])
-        else:
-            # FIXME: "info" message and header info will be lost here
-            if not self.contact_panel.isContactInRoster(other.bare):
-                self.contact_panel.updateContact(other.bare, {}, [C.GROUP_NOT_IN_ROSTER])
-            # The message has not been shown, we must indicate it
-            self.contact_panel.setContactMessageWaiting(other.bare, True)
+    # def newMessageCb(self, from_jid, msg, msg_type, to_jid, extra):
+    #     other = to_jid if from_jid.bare == self.whoami.bare else from_jid
+    #     lib_wid = self.getLiberviaWidget(panels.ChatPanel, {'item': other}, ignoreOtherTabs=False)
+    #     self.displayNotification(from_jid, msg)
+    #     if msg_type == 'headline' and from_jid.full() == self._defaultDomain:
+    #         try:
+    #             assert extra['subject']  # subject is defined and not empty
+    #             title = extra['subject']
+    #         except (KeyError, AssertionError):
+    #             title = _('Announcement from %s') % from_jid.full()
+    #         msg = strings.addURLToText(html_tools.XHTML2Text(msg))
+    #         dialog.InfoDialog(title, msg).show()
+    #         return
+    #     if lib_wid is not None:
+    #         if msg_type == C.MESS_TYPE_INFO:
+    #             lib_wid.printInfo(msg)
+    #         else:
+    #             lib_wid.printMessage(from_jid, msg, extra)
+    #         if 'header_info' in extra:
+    #             lib_wid.setHeaderInfo(extra['header_info'])
+    #     else:
+    #         # FIXME: "info" message and header info will be lost here
+    #         if not self.contact_panel.isContactInRoster(other.bare):
+    #             self.contact_panel.updateContact(other.bare, {}, [C.GROUP_NOT_IN_ROSTER])
+    #         # The message has not been shown, we must indicate it
+    #         self.contact_panel.setContactMessageWaiting(other.bare, True)
 
-    def _presenceUpdateCb(self, entity, show, priority, statuses):
-        entity_jid = jid.JID(entity)
-        if self.whoami and self.whoami == entity_jid:  # XXX: QnD way to get our presence/status
-            assert(isinstance(self.status_panel, panels.PresenceStatusPanel))
-            self.status_panel.setPresence(show)  # pylint: disable=E1103
-            if statuses:
-                self.status_panel.setStatus(statuses.values()[0])  # pylint: disable=E1103
-        else:
-            bare_jid = entity_jid.bareJID()
-            if bare_jid.full() in self.room_list or bare_jid in self.room_list:  # as JID is a string-based class, we don't know what will please Pyjamas...
-                wid = self.getRoomWidget(bare_jid)
-            else:
-                wid = self.contact_panel
-                if show == 'unavailable':  # XXX: save some resources as for now we only need 'unavailable'
-                    for plugin in self.plugins.values():
-                        if hasattr(plugin, 'presenceReceivedTrigger'):
-                            plugin.presenceReceivedTrigger(entity_jid, show, priority, statuses)
-            if wid:
-                wid.setConnected(entity_jid.bare, entity_jid.resource, show, priority, statuses)
+    # def _presenceUpdateCb(self, entity, show, priority, statuses):
+    #     entity_jid = jid.JID(entity)
+    #     if self.whoami and self.whoami == entity_jid:  # XXX: QnD way to get our presence/status
+    #         assert(isinstance(self.status_panel, panels.PresenceStatusPanel))
+    #         self.status_panel.setPresence(show)  # pylint: disable=E1103
+    #         if statuses:
+    #             self.status_panel.setStatus(statuses.values()[0])  # pylint: disable=E1103
+    #     else:
+    #         bare_jid = entity_jid.bareJID()
+    #         if bare_jid.full() in self.room_list or bare_jid in self.room_list:  # as JID is a string-based class, we don't know what will please Pyjamas...
+    #             wid = self.getRoomWidget(bare_jid)
+    #         else:
+    #             wid = self.contact_panel
+    #             if show == 'unavailable':  # XXX: save some resources as for now we only need 'unavailable'
+    #                 for plugin in self.plugins.values():
+    #                     if hasattr(plugin, 'presenceReceivedTrigger'):
+    #                         plugin.presenceReceivedTrigger(entity_jid, show, priority, statuses)
+    #         if wid:
+    #             wid.setConnected(entity_jid.bare, entity_jid.resource, show, priority, statuses)
 
-    def _roomJoinedCb(self, room_jid_s, room_nicks, user_nick):
-        chat_panel = self.getOrCreateRoomWidget(jid.JID(room_jid_s))
-        chat_panel.setUserNick(user_nick)
-        chat_panel.setPresents(room_nicks)
-        chat_panel.refresh()
+    # def _roomJoinedCb(self, room_jid_s, room_nicks, user_nick):
+    #     chat_panel = self.getOrCreateRoomWidget(jid.JID(room_jid_s))
+    #     chat_panel.setUserNick(user_nick)
+    #     chat_panel.setPresents(room_nicks)
+    #     chat_panel.refresh()
 
-    def _roomLeftCb(self, room_jid_s, room_nicks, user_nick):
-        try:
-            del self.room_list[room_jid_s]
-        except KeyError:
-            try:  # as JID is a string-based class,  we don't know what will please Pyjamas...
-                del self.room_list[jid.JID(room_jid_s)]
-            except KeyError:
-                pass
+    # def _roomLeftCb(self, room_jid_s, room_nicks, user_nick):
+    #     try:
+    #         del self.room_list[room_jid_s]
+    #     except KeyError:
+    #         try:  # as JID is a string-based class,  we don't know what will please Pyjamas...
+    #             del self.room_list[jid.JID(room_jid_s)]
+    #         except KeyError:
+    #             pass
 
-    def _roomUserJoinedCb(self, room_jid_s, user_nick, user_data):
-        lib_wid = self.getOrCreateRoomWidget(jid.JID(room_jid_s))
-        if lib_wid:
-            lib_wid.userJoined(user_nick, user_data)
+    # def _roomUserJoinedCb(self, room_jid_s, user_nick, user_data):
+    #     lib_wid = self.getOrCreateRoomWidget(jid.JID(room_jid_s))
+    #     if lib_wid:
+    #         lib_wid.userJoined(user_nick, user_data)
 
-    def _roomUserLeftCb(self, room_jid_s, user_nick, user_data):
-        lib_wid = self.getRoomWidget(jid.JID(room_jid_s))
-        if lib_wid:
-            lib_wid.userLeft(user_nick, user_data)
+    # def _roomUserLeftCb(self, room_jid_s, user_nick, user_data):
+    #     lib_wid = self.getRoomWidget(jid.JID(room_jid_s))
+    #     if lib_wid:
+    #         lib_wid.userLeft(user_nick, user_data)
 
-    def _roomUserChangedNickCb(self, room_jid_s, old_nick, new_nick):
-        """Called when an user joined a MUC room"""
-        lib_wid = self.getRoomWidget(jid.JID(room_jid_s))
-        if lib_wid:
-            lib_wid.changeUserNick(old_nick, new_nick)
+    # def _roomUserChangedNickCb(self, room_jid_s, old_nick, new_nick):
+    #     """Called when an user joined a MUC room"""
+    #     lib_wid = self.getRoomWidget(jid.JID(room_jid_s))
+    #     if lib_wid:
+    #         lib_wid.changeUserNick(old_nick, new_nick)
 
-    def _tarotGameStartedCb(self, waiting, room_jid_s, referee, players):
-        lib_wid = self.getRoomWidget(jid.JID(room_jid_s))
-        if lib_wid:
-            lib_wid.startGame("Tarot", waiting, referee, players)
+    # def _tarotGameStartedCb(self, waiting, room_jid_s, referee, players):
+    #     lib_wid = self.getRoomWidget(jid.JID(room_jid_s))
+    #     if lib_wid:
+    #         lib_wid.startGame("Tarot", waiting, referee, players)
 
-    def _tarotGameGenericCb(self, event_name, room_jid_s, args):
-        lib_wid = self.getRoomWidget(jid.JID(room_jid_s))
-        if lib_wid:
-            getattr(lib_wid.getGame("Tarot"), event_name)(*args)
+    # def _tarotGameGenericCb(self, event_name, room_jid_s, args):
+    #     lib_wid = self.getRoomWidget(jid.JID(room_jid_s))
+    #     if lib_wid:
+    #         getattr(lib_wid.getGame("Tarot"), event_name)(*args)
 
-    def _radioColStartedCb(self, waiting, room_jid_s, referee, players, queue_data):
-        lib_wid = self.getRoomWidget(jid.JID(room_jid_s))
-        if lib_wid:
-            lib_wid.startGame("RadioCol", waiting, referee, players, queue_data)
+    # def _radioColStartedCb(self, waiting, room_jid_s, referee, players, queue_data):
+    #     lib_wid = self.getRoomWidget(jid.JID(room_jid_s))
+    #     if lib_wid:
+    #         lib_wid.startGame("RadioCol", waiting, referee, players, queue_data)
 
-    def _radioColGenericCb(self, event_name, room_jid_s, args):
-        lib_wid = self.getRoomWidget(jid.JID(room_jid_s))
-        if lib_wid:
-            getattr(lib_wid.getGame("RadioCol"), event_name)(*args)
+    # def _radioColGenericCb(self, event_name, room_jid_s, args):
+    #     lib_wid = self.getRoomWidget(jid.JID(room_jid_s))
+    #     if lib_wid:
+    #         getattr(lib_wid.getGame("RadioCol"), event_name)(*args)
 
     def _getPresenceStatusesCb(self, presence_data):
         for entity in presence_data:
@@ -923,19 +819,19 @@
                     if lib_wid.isJidAccepted(entity_jid_s) or (self.whoami and entity_jid_s == self.whoami.bare):
                         lib_wid.updateValue('avatar', entity_jid_s, avatar)
 
-    def _chatStateReceivedCb(self, from_jid_s, state):
-        """Callback when a new chat state is received.
-        @param from_jid_s: JID of the contact who sent his state, or '@ALL@'
-        @param state: new state (string)
-        """
-        if from_jid_s == '@ALL@':
-            for lib_wid in self.libervia_widgets:
-                if isinstance(lib_wid, panels.ChatPanel):
-                    lib_wid.setState(state, nick=C.ALL_OCCUPANTS)
-            return
-        from_jid = jid.JID(from_jid_s)
-        lib_wid = self.getLiberviaWidget(panels.ChatPanel, {'item': from_jid}, ignoreOtherTabs=False)
-        lib_wid.setState(state, nick=from_jid.resource)
+    # def _chatStateReceivedCb(self, from_jid_s, state):
+    #     """Callback when a new chat state is received.
+    #     @param from_jid_s: JID of the contact who sent his state, or '@ALL@'
+    #     @param state: new state (string)
+    #     """
+    #     if from_jid_s == '@ALL@':
+    #         for lib_wid in self.libervia_widgets:
+    #             if isinstance(lib_wid, panels.ChatPanel):
+    #                 lib_wid.setState(state, nick=C.ALL_OCCUPANTS)
+    #         return
+    #     from_jid = jid.JID(from_jid_s)
+    #     lib_wid = self.getLiberviaWidget(panels.ChatPanel, {'item': from_jid}, ignoreOtherTabs=False)
+    #     lib_wid.setState(state, nick=from_jid.resource)
 
     def _askConfirmation(self, confirmation_id, confirmation_type, data):
         answer_data = {}
@@ -974,41 +870,43 @@
                           "Your message can't be sent", Width="400px").center()
         log.error("sendError: %s" % str(errorData))
 
-    def send(self, targets, text, extra={}):
-        """Send a message to any target type.
-        @param targets: list of tuples (type, entities, addr) with:
-        - type in ("PUBLIC", "GROUP", "COMMENT", "STATUS" , "groupchat" , "chat")
-        - entities could be a JID, a list groups, a node hash... depending the target
-        - addr in ("To", "Cc", "Bcc") - ignore case
-        @param text: the message content
-        @param extra: options
-        """
-        # FIXME: too many magic strings, we should use constants instead
-        addresses = []
-        for target in targets:
-            type_, entities, addr = target[0], target[1], 'to' if len(target) < 3 else target[2].lower()
-            if type_ in ("PUBLIC", "GROUP"):
-                self.bridge.call("sendMblog", None, type_, entities if type_ == "GROUP" else None, text, extra)
-            elif type_ == "COMMENT":
-                self.bridge.call("sendMblogComment", None, entities, text, extra)
-            elif type_ == "STATUS":
-                assert(isinstance(self.status_panel, panels.PresenceStatusPanel))
-                self.bridge.call('setStatus', None, self.status_panel.presence, text)  # pylint: disable=E1103
-            elif type_ in ("groupchat", "chat"):
-                addresses.append((addr, entities))
-            else:
-                log.error("Unknown target type")
-        if addresses:
-            if len(addresses) == 1 and addresses[0][0] == 'to':
-                to_jid_s = addresses[0][1]
-                for plugin in self.plugins.values():
-                    if hasattr(plugin, 'sendMessageTrigger'):
-                        if not plugin.sendMessageTrigger(jid.JID(to_jid_s), text, type_, extra):
-                            return  # plugin returned False to interrupt the process
-                self.bridge.call('sendMessage', (None, self.sendError), to_jid_s, text, '', type_, extra)
-            else:
-                extra.update({'address': '\n'.join([('%s:%s' % entry) for entry in addresses])})
-                self.bridge.call('sendMessage', (None, self.sendError), self.whoami.domain, text, '', type_, extra)
+    # FIXME: this method is fat too complicated and depend of widget type
+    #        must be refactored and moved to each widget instead
+    # def send(self, targets, text, extra={}):
+    #     """Send a message to any target type.
+    #     @param targets: list of tuples (type, entities, addr) with:
+    #     - type in ("PUBLIC", "GROUP", "COMMENT", "STATUS" , "groupchat" , "chat")
+    #     - entities could be a JID, a list groups, a node hash... depending the target
+    #     - addr in ("To", "Cc", "Bcc") - ignore case
+    #     @param text: the message content
+    #     @param extra: options
+    #     """
+    #     # FIXME: too many magic strings, we should use constants instead
+    #     addresses = []
+    #     for target in targets:
+    #         type_, entities, addr = target[0], target[1], 'to' if len(target) < 3 else target[2].lower()
+    #         if type_ in ("PUBLIC", "GROUP"):
+    #             self.bridge.call("sendMblog", None, type_, entities if type_ == "GROUP" else None, text, extra)
+    #         elif type_ == "COMMENT":
+    #             self.bridge.call("sendMblogComment", None, entities, text, extra)
+    #         elif type_ == "STATUS":
+    #             assert(isinstance(self.status_panel, panels.PresenceStatusPanel))
+    #             self.bridge.call('setStatus', None, self.status_panel.presence, text)  # pylint: disable=E1103
+    #         elif type_ in ("groupchat", "chat"):
+    #             addresses.append((addr, entities))
+    #         else:
+    #             log.error("Unknown target type")
+    #     if addresses:
+    #         if len(addresses) == 1 and addresses[0][0] == 'to':
+    #             to_jid_s = addresses[0][1]
+    #             for plugin in self.plugins.values():
+    #                 if hasattr(plugin, 'sendMessageTrigger'):
+    #                     if not plugin.sendMessageTrigger(jid.JID(to_jid_s), text, type_, extra):
+    #                         return  # plugin returned False to interrupt the process
+    #             self.bridge.call('sendMessage', (None, self.sendError), to_jid_s, text, '', type_, extra)
+    #         else:
+    #             extra.update({'address': '\n'.join([('%s:%s' % entry) for entry in addresses])})
+    #             self.bridge.call('sendMessage', (None, self.sendError), self.whoami.domain, text, '', type_, extra)
 
     def showWarning(self, type_=None, msg=None):
         """Display a popup information message, e.g. to notify the recipient of a message being composed.
@@ -1024,4 +922,3 @@
 if __name__ == '__main__':
     app = SatWebFrontend()
     app.onModuleLoad()
-    pyjd.run()