Mercurial > libervia-web
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()