Mercurial > libervia-web
diff src/browser/libervia_main.py @ 679:a90cc8fc9605
merged branch frontends_multi_profiles
author | Goffi <goffi@goffi.org> |
---|---|
date | Wed, 18 Mar 2015 16:15:18 +0100 |
parents | 3eb3a2c0c011 849ffb24d5bf |
children | 801eb94aa869 |
line wrap: on
line diff
--- a/src/browser/libervia_main.py Thu Feb 05 12:05:32 2015 +0100 +++ b/src/browser/libervia_main.py Wed Mar 18 16:15:18 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,16 @@ log = getLogger(__name__) ### +from sat.core.i18n import D_ + +from sat_frontends.quick_frontend.quick_app import QuickApp +from sat_frontends.quick_frontend import quick_widgets +from sat_frontends.quick_frontend import quick_menus + from sat_frontends.tools.misc import InputHistory from sat_frontends.tools import strings +from sat_frontends.tools import jid +from sat_frontends.tools import host_listener from sat.core.i18n import _ from pyjamas.ui.RootPanel import RootPanel @@ -35,19 +42,22 @@ 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 import base_widget -from sat_browser import panels +from sat_browser.contact_list import ContactList +from sat_browser import widget +from sat_browser import main_panel +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 import libervia_widget from sat_browser.constants import Const as C +import os.path + try: # FIXME: import plugin dynamically @@ -55,148 +65,36 @@ except ImportError: pass + +unicode = str # FIXME: pyjamas workaround + + MAX_MBLOG_CACHE = 500 # Max microblog entries kept in memories # Set to true to not create a new LiberviaWidget when a similar one # already exist (i.e. a chat panel with the same target). Instead # the existing widget will be eventually removed from its parent -# and added to new base_widget.WidgetsPanel, or replaced to the expected +# and added to new libervia_widget.WidgetsPanel, or replaced to the expected # position if the previous and the new parent are the same. -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']) +# REUSE_EXISTING_LIBERVIA_WIDGETS = True # FIXME -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", - "getMblogs", "getMassiveMblogs", "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.status_panel = HTML('<br />') - self.contact_panel = contact.ContactPanel(self) - self.panel = panels.MainPanel(self) - self.discuss_panel = self.panel.discuss_panel + self.bridge_signals = json.BridgeSignals(self) + QuickApp.__init__(self, json.BridgeCall) + self.uni_box = None # FIXME: to be removed + self.panel = main_panel.MainPanel(self) 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) @@ -205,35 +103,65 @@ self.cached_params = {} self.next_rsm_index = 0 + #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 + + # self._selected_listeners = set() # FIXME: to be done with new listeners mechanism + + @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] + + @property + def visible_widgets(self): + widgets_panel = self.tab_panel.getCurrentPanel() + return [wid for wid in widgets_panel.widgets if isinstance(wid, quick_widgets.QuickWidget)] + + @property + def base_location(self): + """Return absolute base url of this Libervia instance""" + url = Window.getLocation().getHref() + if url.endswith(C.LIBERVIA_MAIN_PAGE): + url = url[:-len(C.LIBERVIA_MAIN_PAGE)] + if url.endswith("/"): + url = url[:-1] + return url + + 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 = [] - # FIXME: plugins import should be dynamic and generic like in sat try: self.plugins['otr'] = plugin_sec_otr.OTR(self) except TypeError: # plugin_sec_otr has not been imported - inhibited_menus.append('OTR') + pass - class DummyPlugin(object): - def inhibitMenus(self): - return inhibited_menus - - 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() - if not isinstance(wid, base_widget.WidgetsPanel): - log.error("Tab widget is not a base_widget.WidgetsPanel, can't get selected widget") + if not isinstance(wid, libervia_widget.WidgetsPanel): + log.error("Tab widget is not a WidgetsPanel, can't get selected widget") return None return wid.selected def setSelected(self, widget): """Define the selected widget""" widgets_panel = self.tab_panel.getCurrentPanel() - if not isinstance(widgets_panel, base_widget.WidgetsPanel): + if not isinstance(widgets_panel, libervia_widget.WidgetsPanel): return selected = widgets_panel.selected @@ -244,13 +172,16 @@ if selected: selected.removeStyleName('selected_widget') + # FIXME: check that widget is in the current WidgetsPanel 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,9 +191,11 @@ return True def onTabSelected(self, sender, tab_index): - selected = self.getSelected() - for callback in self._selected_listeners: - callback(selected) + pass + # selected = self.getSelected() + # 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: @@ -270,26 +203,24 @@ event.preventDefault() return True - def getAvatar(self, jid_str): + # FIXME: must not call _entityDataUpdatedCb by itself + # should not get VCard, backend plugin must be fixed too + def getAvatarURL(self, jid_): """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) + @param jid_ (jid.JID): JID of the contact + @return: the URL to the avatar (unicode) """ - 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) - - 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] + assert isinstance(jid_, jid.JID) + contact_list = self.contact_list # pyjamas issue: need a temporary variable to call a property's method + avatar_hash = contact_list.getCache(jid_, 'avatar') + if avatar_hash is None: + # we have no value for avatar_hash, so we request the vcard + self.bridge.getCard(unicode(jid_), profile=C.PROF_KEY_NONE) + if not avatar_hash: + return C.DEFAULT_AVATAR_URL + ret = os.path.join(C.AVATARS_DIR, avatar_hash) + return ret def registerWidget(self, wid): log.debug("Registering %s" % wid.getDebugName()) @@ -304,64 +235,65 @@ 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() - def addTab(self, label, wid, select=True): - """Create a new tab and eventually add a widget in - @param label: label of the tab - @param wid: LiberviaWidget to add - @param select: True to select the added tab - """ - widgets_panel = base_widget.WidgetsPanel(self) - self.tab_panel.add(widgets_panel, label) - widgets_panel.addWidget(wid) - if select: - self.tab_panel.selectTab(self.tab_panel.getWidgetCount() - 1) - return widgets_panel - 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: - panel = self.tab_panel.tabBar.getTabWidget(tab_index) + panel = self.tab_panel.deck.getWidget(tab_index) panel.addWidget(wid) def displayNotification(self, title, body): self.notification.notify(title, body) - def gotMenus(self, menus): + def gotMenus(self, backend_menus): """Put the menus data in cache and build the main menu bar - @param menus (list[tuple]): menu data + @param backend_menus (list[tuple]): menu data from backend """ - def process(menus, inhibited=None): - for raw_menu in menus: - id_, type_, path, path_i18n = raw_menu - if inhibited and path[0] in inhibited: - continue - menus_data = self.menus.setdefault(type_, []) - menus_data.append((id_, path, path_i18n)) + main_menu = self.panel.menu # most of global menu callbacks are in main_menu + + # Categories (with icons) + self.menus.addCategory(C.MENU_GLOBAL, [D_(u"General")], extra={'icon': 'home'}) + self.menus.addCategory(C.MENU_GLOBAL, [D_(u"Contacts")], extra={'icon': 'social'}) + self.menus.addCategory(C.MENU_GLOBAL, [D_(u"Groups")], extra={'icon': 'social'}) + self.menus.addCategory(C.MENU_GLOBAL, [D_(u"Games")], extra={'icon': 'games'}) + + # menus to have before backend menus + self.menus.addMenu(C.MENU_GLOBAL, (D_(u"Groups"), D_(u"Discussion")), callback=main_menu.onJoinRoom) + + # menus added by the backend/plugins (include other types than C.MENU_GLOBAL) + self.menus.addMenus(backend_menus, top_extra={'icon': 'plugins'}) + + # menus to have under backend menus + self.menus.addMenu(C.MENU_GLOBAL, (D_(u"Contacts"), D_(u"Manage groups")), callback=main_menu.onManageContactGroups) - self.menus = {} - inhibited = set() - extras = [] - for plugin in self.plugins.values(): - if hasattr(plugin, "inhibitMenus"): - inhibited.update(plugin.inhibitMenus()) - if hasattr(plugin, "extraMenus"): - extras.extend(plugin.extraMenus()) - process(menus, inhibited) - process(extras) - self.panel.menu.createMenus() + # separator and right hand menus + self.menus.addMenuItem(C.MENU_GLOBAL, [], quick_menus.MenuSeparator()) + + self.menus.addMenu(C.MENU_GLOBAL, (D_(u"Help"), D_("Social contract")), top_extra={'icon': 'help'}, callback=main_menu.onSocialContract) + self.menus.addMenu(C.MENU_GLOBAL, (D_(u"Help"), D_("About")), callback=main_menu.onAbout) + self.menus.addMenu(C.MENU_GLOBAL, (D_(u"Settings"), D_("Account")), top_extra={'icon': 'settings'}, callback=main_menu.onAccount) + self.menus.addMenu(C.MENU_GLOBAL, (D_(u"Settings"), D_("Parameters")), callback=main_menu.onParameters) + # XXX: temporary, will change when a full profile will be managed in SàT + self.menus.addMenu(C.MENU_GLOBAL, (D_(u"Settings"), D_("Upload avatar")), callback=main_menu.onAvatarUpload) + + # we call listener to have menu added by local classes/plugins + self.callListeners('gotMenus') # FIXME: to be done another way or moved to quick_app + + # and finally the menus which must appear at the bottom + self.menus.addMenu(C.MENU_GLOBAL, (D_(u"General"), D_(u"Disconnect")), callback=main_menu.onDisconnect) + + # we can now display all the menus + main_menu.update(C.MENU_GLOBAL) def _isRegisteredCB(self, result): registered, warning = result @@ -386,17 +318,19 @@ self._register_box.hide() del self._register_box # don't work if self._register_box is None - # display the real presence status panel - self.panel.header.remove(self.status_panel) - self.status_panel = panels.PresenceStatusPanel(self) - self.panel.header.add(self.status_panel) + # display the presence status panel and tab bar + self.presence_status_panel = main_panel.PresenceStatusPanel(self) + self.panel.addPresenceStatusPanel(self.presence_status_panel) + self.panel.tab_panel.getTabBar().setVisible(True) + + 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 @@ -405,18 +339,72 @@ 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. + # self.discuss_panel.addWidget(panel.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) + + def profilePlugged(self, dummy): # FIXME: to be called as a "profilePlugged" listener? + QuickApp.profilePlugged(self, dummy) + + microblog_widget = self.displayWidget(blog.MicroblogPanel, ()) + self.setSelected(microblog_widget) + + # we fill the panels already here + for wid in self.widgets.getWidgets(blog.MicroblogPanel): + if wid.accept_all(): + self.bridge.getMassiveMblogs('ALL', (), None, profile=C.PROF_KEY_NONE, callback=wid.massiveInsert) + else: + self.bridge.getMassiveMblogs('GROUP', list(wid.accepted_groups), None, profile=C.PROF_KEY_NONE, callback=wid.massiveInsert) + + #we ask for our own microblogs: + self.loadOurMainEntries() - # 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 addContactList(self, dummy): + contact_list = ContactList(self) + self.panel.addContactList(contact_list) + + # FIXME: the contact list height has to be set manually the first time + self.resize() + + return contact_list + + def newWidget(self, wid): + log.debug("newWidget: {}".format(wid)) + self.addWidget(wid) - 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) + def newMessageHandler(self, from_jid_s, msg, type_, to_jid_s, extra, profile=C.PROF_KEY_NONE): + if type_ == C.MESS_TYPE_HEADLINE: + from_jid = jid.JID(from_jid_s) + if from_jid.domain == self._defaultDomain: + # we display announcement from the server in a dialog for better visibility + try: + title = extra['subject'] + except KeyError: + title = _('Announcement from %s') % from_jid + msg = strings.addURLToText(html_tools.XHTML2Text(msg)) + dialog.InfoDialog(title, msg).show() + return + QuickApp.newMessageHandler(self, from_jid_s, msg, type_, to_jid_s, extra, profile) + + def disconnectedHandler(self, profile): + QuickApp.disconnectedHandler(self, profile) + Window.getLocation().reload() + + def setStatusOnline(self, online=True, show='', statuses={}, profile=C.PROF_KEY_NONE): + self.presence_status_panel.setPresence(show) + if statuses: + # FIXME: retrieve user language status or fallback to 'default' + self.presence_status_panel.setStatus(statuses.values()[0]) def _tryAutoConnect(self, skip_validation=False): """This method retrieve the eventual URL parameters to auto-connect the user. @@ -447,7 +435,8 @@ elif "public_blog" in data: # TODO: use the bare instead of node when all blogs can be retrieved node = jid.JID(data['public_blog']).node - self.addTab("%s's blog" % node, panels.WebPanel(self, "/blog/%s" % node)) + # FIXME: "/blog/{}" won't work with unicode nodes + self.displayWidget(widget.WebWidget, "/blog/{}".format(node), show_url=False, new_tab=_(u"{}'s blog").format(unicode(node))) else: dialog.InfoDialog("Error", "Unmanaged action result", Width="400px").center() @@ -455,9 +444,9 @@ def _actionEb(self, err_data): err_code, err_obj = err_data dialog.InfoDialog("Error", - str(err_obj), Width="400px").center() + unicode(err_obj), Width="400px").center() - def launchAction(self, callback_id, data): + def launchAction(self, callback_id, data=None, callback=None, profile=C.PROF_KEY_NONE): """ Launch a dynamic action @param callback_id: id of the action to launch @param data: data needed only for certain actions @@ -465,78 +454,13 @@ """ if data is None: data = {} - self.bridge.call('launchAction', (self._actionCb, self._actionEb), callback_id, data) + self.bridge.launchAction(callback_id, data, profile=profile, callback=self._actionCb, errback=self._actionEb) def _getContactsCB(self, contacts_data): for contact_ in contacts_data: 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: @@ -558,48 +482,52 @@ _groups = set(mblog['groups'].split() if mblog['groups'] else []) else: _groups = None - mblog_entry = panels.MicroblogItem(mblog) + mblog_entry = blog.MicroblogItem(mblog) cache.append((_groups, mblog_entry)) self.mblog_cache.extend(cache) if len(self.mblog_cache) > MAX_MBLOG_CACHE: del self.mblog_cache[0:len(self.mblog_cache - MAX_MBLOG_CACHE)] - widget_list = [mblog_panel] if mblog_panel else self.libervia_widgets - for lib_wid in widget_list: - if isinstance(lib_wid, panels.MicroblogPanel): - self.fillMicroblogPanel(lib_wid, cache) + widget_list = [mblog_panel] if mblog_panel else self.widgets.getWidgets(blog.MicroblogPanel) + + for wid in widget_list: + self.fillMicroblogPanel(wid, cache) + + # FIXME if self.initialised: return 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) + self.personalEventHandler(*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('getMassiveMblogs', lib_wid.massiveInsert, 'ALL', []) - else: - self.bridge.call('getMassiveMblogs', lib_wid.massiveInsert, 'GROUP', lib_wid.accepted_groups) + # 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, panel.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.loadOurMainEntries() + # #we ask for our own microblogs: + # self.loadOurMainEntries() - # 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() def loadOurMainEntries(self, index=0, mblog_panel=None): """Load a page of our own blogs from the cache or ask them to the @@ -610,7 +538,7 @@ """ delta = index - self.next_rsm_index if delta < 0: - assert(mblog_panel is not None) + assert mblog_panel is not None self.fillMicroblogPanel(mblog_panel, self.mblog_cache[index:index + C.RSM_MAX_ITEMS]) return @@ -618,12 +546,13 @@ self._ownBlogsFills(result, mblog_panel) rsm = {'max': str(delta + C.RSM_MAX_ITEMS), 'index': str(self.next_rsm_index)} - self.bridge.call('getMassiveMblogs', cb, 'JID', [self.whoami.bare], rsm) + self.bridge.getMassiveMblogs('JID', [unicode(self.whoami.bare)], rsm, callback=cb, profile=C.PROF_KEY_NONE) self.next_rsm_index = index + C.RSM_MAX_ITEMS ## Signals callbacks ## - def _personalEventCb(self, sender, event_type, data): + def personalEventHandler(self, sender, event_type, data): + # FIXME: move some code from here to QuickApp if not self.initialised: self.init_cache.append((sender, event_type, data)) return @@ -636,11 +565,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 wid in self.widgets.getWidgets(blog.MicroblogPanel): + wid.addEntryIfAccepted(sender, _groups, mblog_entry) if sender == self.whoami.bare: found = False @@ -657,9 +585,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 wid in self.widgets.getWidgets(blog.MicroblogPanel): + wid.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': @@ -669,235 +596,276 @@ self.mblog_cache.remove(entry) break - def addBlogEntry(self, mblog_panel, sender, _groups, mblog_entry): - """Check if an entry can go in MicroblogPanel and add to it - @param mblog_panel: MicroblogPanel instance - @param sender: jid of the entry sender - @param _groups: groups which can receive this entry - @param mblog_entry: panels.MicroblogItem instance""" - if mblog_entry.type == "comment" or mblog_panel.isJidAccepted(sender) or (_groups == None and self.whoami and sender == self.whoami.bare) \ - or (_groups and _groups.intersection(mblog_panel.accepted_groups)): - mblog_panel.addEntry(mblog_entry) - def fillMicroblogPanel(self, mblog_panel, mblogs): """Fill a microblog panel with entries in cache + @param mblog_panel: MicroblogPanel instance """ #XXX: only our own entries are cached for cache_entry in mblogs: _groups, mblog_entry = cache_entry - self.addBlogEntry(mblog_panel, self.whoami.bare, *cache_entry) + mblog_panel.addEntryIfAccepted(self.whoami.bare, *cache_entry) def getEntityMBlog(self, entity): log.info("geting mblog for entity [%s]" % (entity,)) for lib_wid in self.libervia_widgets: - if isinstance(lib_wid, panels.MicroblogPanel): + if isinstance(lib_wid, blog.MicroblogPanel): if lib_wid.isJidAccepted(entity): - self.bridge.call('getMassiveMblogs', lib_wid.massiveInsert, 'JID', [entity]) + self.bridge.call('getMassiveMblogs', lib_wid.massiveInsert, 'JID', [unicode(entity)]) + + # 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 displayWidget(self, class_, target, dropped=False, new_tab=None, *args, **kwargs): + """Get or create a LiberviaWidget and select it. When the user dropped + something, a new widget is always created, otherwise we look for an + existing widget and re-use it if it's in the current tab. + + @arg class_(class): see quick_widgets.getOrCreateWidget + @arg target: see quick_widgets.getOrCreateWidget + @arg dropped(bool): if True, assume the widget has been dropped + @arg new_tab(unicode): if not None, it holds the name of a new tab to + open for the widget. If None, use the default behavior. + @param args(list): optional args to create a new instance of class_ + @param kwargs(list): optional kwargs to create a new instance of class_ + @return: the widget + """ + kwargs['profile'] = C.PROF_KEY_NONE + + if dropped: + kwargs['on_new_widget'] = None + kwargs['on_existing_widget'] = C.WIDGET_RECREATE + wid = self.widgets.getOrCreateWidget(class_, target, *args, **kwargs) + self.setSelected(wid) + return wid + + if new_tab: + kwargs['on_new_widget'] = None + kwargs['on_existing_widget'] = C.WIDGET_RECREATE + wid = self.widgets.getOrCreateWidget(class_, target, *args, **kwargs) + self.tab_panel.addWidgetsTab(new_tab) + self.addWidget(wid, tab_index=self.tab_panel.getWidgetCount() - 1) + return 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 + kwargs['on_existing_widget'] = C.WIDGET_RAISE + try: + wid = self.widgets.getOrCreateWidget(class_, target, *args, **kwargs) + except quick_widgets.WidgetAlreadyExistsError: + kwargs['on_existing_widget'] = C.WIDGET_KEEP + wid = self.widgets.getOrCreateWidget(class_, target, *args, **kwargs) + widgets_panel = wid.getParent(libervia_widget.WidgetsPanel, expect=False) + if widgets_panel is None: + # The widget exists but is hidden + self.addWidget(wid) + elif widgets_panel != self.tab_panel.getCurrentPanel(): + # the widget is on an other tab, so we add a new one here + kwargs['on_existing_widget'] = C.WIDGET_RECREATE + wid = self.widgets.getOrCreateWidget(class_, target, *args, **kwargs) + self.addWidget(wid) + self.setSelected(wid) + return wid + - 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 - - def getOrCreateRoomWidget(self, target): - """Get the MUC widget for the given target, create it if necessary. + # 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 (unicode): 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 - @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 + # def getRoomWidget(self, target): + # """Get the MUC widget for the given target. - # 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 + # @param target (jid.JID): BARE jid of the MUC + # @return: panel.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(panel.ChatPanel, entity, ignoreOtherTabs=False) + # return None - self.room_list.append(target) - entity = {'item': target, 'type_': 'group'} - return self.getOrCreateLiberviaWidget(panels.ChatPanel, entity, new_tab=tab_name) + # def getOrCreateRoomWidget(self, target): + # """Get the MUC widget for the given target, create it if necessary. - 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) + # @param target (jid.JID): BARE jid of the MUC + # @return: panel.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: 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(panel.ChatPanel, entity, new_tab=tab_name) - 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_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(panel.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, main_panel.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: @@ -929,7 +897,8 @@ msg = HTML('The contact <b>%s</b> want to add you in his/her contact list, do you accept ?' % html_tools.html_sanitize(entity)) def ok_cb(ignore): - self.bridge.call('subscription', None, "subscribed", entity, '', _dialog.getSelectedGroups()) + self.bridge.call('subscription', None, "subscribed", entity) + self.bridge.updateContact(entity, '', _dialog.getSelectedGroups()) def cancel_cb(ignore): self.bridge.call('subscription', None, "unsubscribed", entity, '', '') @@ -945,31 +914,32 @@ self.contact_panel.updateContact(contact_jid, attributes, groups) def _entityDataUpdatedCb(self, entity_jid_s, key, value): + raise Exception # FIXME should not be here if key == "avatar": avatar = '/' + C.AVATARS_DIR + value self.avatars_cache[entity_jid_s] = avatar self.contact_panel.updateAvatar(entity_jid_s, avatar) for lib_wid in self.libervia_widgets: - if isinstance(lib_wid, panels.MicroblogPanel): + if isinstance(lib_wid, blog.MicroblogPanel): 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 (unicode): new state + # """ + # if from_jid_s == '@ALL@': + # for lib_wid in self.libervia_widgets: + # if isinstance(lib_wid, panel.ChatPanel): + # lib_wid.setState(state, nick=C.ALL_OCCUPANTS) + # return + # from_jid = jid.JID(from_jid_s) + # lib_wid = self.getLiberviaWidget(panel.ChatPanel, {'item': from_jid}, ignoreOtherTabs=False) + # lib_wid.setState(state, nick=from_jid.resource) - def _askConfirmation(self, confirmation_id, confirmation_type, data): + def askConfirmationHandler(self, confirmation_id, confirmation_type, data): answer_data = {} def confirm_cb(result): @@ -996,51 +966,53 @@ def getCachedParam(self, category, name): """Return a parameter cached value (e.g for refreshing the UI) - @param category (str): the parameter category - @pram name (str): the parameter name + @param category (unicode): the parameter category + @pram name (unicode): the parameter name """ return self.cached_params[(category, name)] if (category, name) in self.cached_params else None def sendError(self, errorData): dialog.InfoDialog("Error while sending message", "Your message can't be sent", Width="400px").center() - log.error("sendError: %s" % str(errorData)) + log.error("sendError: %s" % unicode(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, main_panel.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. @@ -1049,11 +1021,25 @@ @msg: message to be displayed """ if not hasattr(self, "warning_popup"): - self.warning_popup = panels.WarningPopup() + self.warning_popup = main_panel.WarningPopup() self.warning_popup.showWarning(type_, msg) + def showDialog(self, message, title="", type_="info", answer_cb=None, answer_data=None): + if type_ == 'info': + popup = dialog.InfoDialog(unicode(title), unicode(message), callback=answer_cb) + elif type_ == 'error': + popup = dialog.InfoDialog(unicode(title), unicode(message), callback=answer_cb) + elif type_ == 'yes/no': + popup = dialog.ConfirmDialog(lambda answer: answer_cb(answer, answer_data), + text=unicode(message), title=unicode(title)) + popup.cancel_button.setText(_("No")) + else: + popup = dialog.InfoDialog(unicode(title), unicode(message), callback=answer_cb) + log.error(_('unmanaged dialog type: %s'), type_) + popup.show() + if __name__ == '__main__': app = SatWebFrontend() app.onModuleLoad() - pyjd.run() + host_listener.callListeners(app)