Mercurial > libervia-web
comparison 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 |
comparison
equal
deleted
inserted
replaced
590:1bffc4c244c3 | 679:a90cc8fc9605 |
---|---|
15 # GNU Affero General Public License for more details. | 15 # GNU Affero General Public License for more details. |
16 | 16 |
17 # You should have received a copy of the GNU Affero General Public License | 17 # You should have received a copy of the GNU Affero General Public License |
18 # along with this program. If not, see <http://www.gnu.org/licenses/>. | 18 # along with this program. If not, see <http://www.gnu.org/licenses/>. |
19 | 19 |
20 import pyjd # this is dummy in pyjs | |
21 | 20 |
22 ### logging configuration ### | 21 ### logging configuration ### |
23 from sat_browser import logging | 22 from sat_browser import logging |
24 logging.configure() | 23 logging.configure() |
25 from sat.core.log import getLogger | 24 from sat.core.log import getLogger |
26 log = getLogger(__name__) | 25 log = getLogger(__name__) |
27 ### | 26 ### |
28 | 27 |
28 from sat.core.i18n import D_ | |
29 | |
30 from sat_frontends.quick_frontend.quick_app import QuickApp | |
31 from sat_frontends.quick_frontend import quick_widgets | |
32 from sat_frontends.quick_frontend import quick_menus | |
33 | |
29 from sat_frontends.tools.misc import InputHistory | 34 from sat_frontends.tools.misc import InputHistory |
30 from sat_frontends.tools import strings | 35 from sat_frontends.tools import strings |
36 from sat_frontends.tools import jid | |
37 from sat_frontends.tools import host_listener | |
31 from sat.core.i18n import _ | 38 from sat.core.i18n import _ |
32 | 39 |
33 from pyjamas.ui.RootPanel import RootPanel | 40 from pyjamas.ui.RootPanel import RootPanel |
34 from pyjamas.ui.HTML import HTML | 41 from pyjamas.ui.HTML import HTML |
35 from pyjamas.ui.KeyboardListener import KEY_ESCAPE | 42 from pyjamas.ui.KeyboardListener import KEY_ESCAPE |
36 from pyjamas.Timer import Timer | 43 from pyjamas.Timer import Timer |
37 from pyjamas import Window, DOM | 44 from pyjamas import Window, DOM |
38 from pyjamas.JSONService import JSONProxy | 45 |
39 | 46 from sat_browser import json |
40 from sat_browser import register | 47 from sat_browser import register |
41 from sat_browser import contact | 48 from sat_browser.contact_list import ContactList |
42 from sat_browser import base_widget | 49 from sat_browser import widget |
43 from sat_browser import panels | 50 from sat_browser import main_panel |
51 from sat_browser import blog | |
44 from sat_browser import dialog | 52 from sat_browser import dialog |
45 from sat_browser import jid | |
46 from sat_browser import xmlui | 53 from sat_browser import xmlui |
47 from sat_browser import html_tools | 54 from sat_browser import html_tools |
48 from sat_browser import notification | 55 from sat_browser import notification |
56 from sat_browser import libervia_widget | |
49 | 57 |
50 from sat_browser.constants import Const as C | 58 from sat_browser.constants import Const as C |
59 import os.path | |
60 | |
51 | 61 |
52 try: | 62 try: |
53 # FIXME: import plugin dynamically | 63 # FIXME: import plugin dynamically |
54 from sat_browser import plugin_sec_otr | 64 from sat_browser import plugin_sec_otr |
55 except ImportError: | 65 except ImportError: |
56 pass | 66 pass |
57 | 67 |
68 | |
69 unicode = str # FIXME: pyjamas workaround | |
70 | |
71 | |
58 MAX_MBLOG_CACHE = 500 # Max microblog entries kept in memories | 72 MAX_MBLOG_CACHE = 500 # Max microblog entries kept in memories |
59 | 73 |
60 # Set to true to not create a new LiberviaWidget when a similar one | 74 # Set to true to not create a new LiberviaWidget when a similar one |
61 # already exist (i.e. a chat panel with the same target). Instead | 75 # already exist (i.e. a chat panel with the same target). Instead |
62 # the existing widget will be eventually removed from its parent | 76 # the existing widget will be eventually removed from its parent |
63 # and added to new base_widget.WidgetsPanel, or replaced to the expected | 77 # and added to new libervia_widget.WidgetsPanel, or replaced to the expected |
64 # position if the previous and the new parent are the same. | 78 # position if the previous and the new parent are the same. |
65 REUSE_EXISTING_LIBERVIA_WIDGETS = True | 79 # REUSE_EXISTING_LIBERVIA_WIDGETS = True # FIXME |
66 | 80 |
67 | 81 |
68 class LiberviaJsonProxy(JSONProxy): | 82 class SatWebFrontend(InputHistory, QuickApp): |
69 def __init__(self, *args, **kwargs): | |
70 JSONProxy.__init__(self, *args, **kwargs) | |
71 self.handler = self | |
72 self.cb = {} | |
73 self.eb = {} | |
74 | |
75 def call(self, method, cb, *args): | |
76 _id = self.callMethod(method, args) | |
77 if cb: | |
78 if isinstance(cb, tuple): | |
79 if len(cb) != 2: | |
80 log.error("tuple syntax for bridge.call is (callback, errback), aborting") | |
81 return | |
82 if cb[0] is not None: | |
83 self.cb[_id] = cb[0] | |
84 self.eb[_id] = cb[1] | |
85 else: | |
86 self.cb[_id] = cb | |
87 | |
88 def onRemoteResponse(self, response, request_info): | |
89 if request_info.id in self.cb: | |
90 _cb = self.cb[request_info.id] | |
91 # if isinstance(_cb, tuple): | |
92 # #we have arguments attached to the callback | |
93 # #we send them after the answer | |
94 # callback, args = _cb | |
95 # callback(response, *args) | |
96 # else: | |
97 # #No additional argument, we call directly the callback | |
98 _cb(response) | |
99 del self.cb[request_info.id] | |
100 if request_info.id in self.eb: | |
101 del self.eb[request_info.id] | |
102 | |
103 def onRemoteError(self, code, errobj, request_info): | |
104 """def dump(obj): | |
105 print "\n\nDUMPING %s\n\n" % obj | |
106 for i in dir(obj): | |
107 print "%s: %s" % (i, getattr(obj,i))""" | |
108 if request_info.id in self.eb: | |
109 _eb = self.eb[request_info.id] | |
110 _eb((code, errobj)) | |
111 del self.cb[request_info.id] | |
112 del self.eb[request_info.id] | |
113 else: | |
114 if code != 0: | |
115 log.error("Internal server error") | |
116 """for o in code, error, request_info: | |
117 dump(o)""" | |
118 else: | |
119 if isinstance(errobj['message'], dict): | |
120 log.error("Error %s: %s" % (errobj['message']['faultCode'], errobj['message']['faultString'])) | |
121 else: | |
122 log.error("%s" % errobj['message']) | |
123 | |
124 | |
125 class RegisterCall(LiberviaJsonProxy): | |
126 def __init__(self): | |
127 LiberviaJsonProxy.__init__(self, "/register_api", | |
128 ["isRegistered", "isConnected", "asyncConnect", "registerParams", "getMenus"]) | |
129 | |
130 | |
131 class BridgeCall(LiberviaJsonProxy): | |
132 def __init__(self): | |
133 LiberviaJsonProxy.__init__(self, "/json_api", | |
134 ["getContacts", "addContact", "sendMessage", "sendMblog", "sendMblogComment", | |
135 "getMblogs", "getMassiveMblogs", "getMblogComments", "getProfileJid", | |
136 "getHistory", "getPresenceStatuses", "joinMUC", "mucLeave", "getRoomsJoined", | |
137 "inviteMUC", "launchTarotGame", "getTarotCardsPaths", "tarotGameReady", | |
138 "tarotGamePlayCards", "launchRadioCollective", "getMblogs", "getMblogsWithComments", | |
139 "getWaitingSub", "subscription", "delContact", "updateContact", "getCard", | |
140 "getEntityData", "getParamsUI", "asyncGetParamA", "setParam", "launchAction", | |
141 "disconnect", "chatStateComposing", "getNewAccountDomain", "confirmationAnswer", | |
142 "syntaxConvert", "getAccountDialogUI", "getLastResource" | |
143 ]) | |
144 | |
145 | |
146 class BridgeSignals(LiberviaJsonProxy): | |
147 RETRY_BASE_DELAY = 1000 | |
148 | |
149 def __init__(self, host): | |
150 self.host = host | |
151 self.retry_delay = self.RETRY_BASE_DELAY | |
152 LiberviaJsonProxy.__init__(self, "/json_signal_api", | |
153 ["getSignals"]) | |
154 | |
155 def onRemoteResponse(self, response, request_info): | |
156 self.retry_delay = self.RETRY_BASE_DELAY | |
157 LiberviaJsonProxy.onRemoteResponse(self, response, request_info) | |
158 | |
159 def onRemoteError(self, code, errobj, request_info): | |
160 if errobj['message'] == 'Empty Response': | |
161 Window.getLocation().reload() # XXX: reset page in case of session ended. | |
162 # FIXME: Should be done more properly without hard reload | |
163 LiberviaJsonProxy.onRemoteError(self, code, errobj, request_info) | |
164 #we now try to reconnect | |
165 if isinstance(errobj['message'], dict) and errobj['message']['faultCode'] == 0: | |
166 Window.alert('You are not allowed to connect to server') | |
167 else: | |
168 def _timerCb(timer): | |
169 self.host.bridge_signals.call('getSignals', self.host._getSignalsCB) | |
170 Timer(notify=_timerCb).schedule(self.retry_delay) | |
171 self.retry_delay *= 2 | |
172 | |
173 | |
174 class SatWebFrontend(InputHistory): | |
175 def onModuleLoad(self): | 83 def onModuleLoad(self): |
176 log.info("============ onModuleLoad ==============") | 84 log.info("============ onModuleLoad ==============") |
177 panels.ChatPanel.registerClass() | 85 self.bridge_signals = json.BridgeSignals(self) |
178 panels.MicroblogPanel.registerClass() | 86 QuickApp.__init__(self, json.BridgeCall) |
179 self.whoami = None | 87 self.uni_box = None # FIXME: to be removed |
180 self._selected_listeners = set() | 88 self.panel = main_panel.MainPanel(self) |
181 self.bridge = BridgeCall() | |
182 self.bridge_signals = BridgeSignals(self) | |
183 self.uni_box = None | |
184 self.status_panel = HTML('<br />') | |
185 self.contact_panel = contact.ContactPanel(self) | |
186 self.panel = panels.MainPanel(self) | |
187 self.discuss_panel = self.panel.discuss_panel | |
188 self.tab_panel = self.panel.tab_panel | 89 self.tab_panel = self.panel.tab_panel |
189 self.tab_panel.addTabListener(self) | 90 self.tab_panel.addTabListener(self) |
190 self.libervia_widgets = set() # keep track of all actives LiberviaWidgets | |
191 self.room_list = [] # list of rooms | |
192 self.mblog_cache = [] # used to keep our own blog entries in memory, to show them in new mblog panel | |
193 self.avatars_cache = {} # keep track of jid's avatar hash (key=jid, value=file) | |
194 self._register_box = None | 91 self._register_box = None |
195 RootPanel().add(self.panel) | 92 RootPanel().add(self.panel) |
93 | |
196 self.notification = notification.Notification() | 94 self.notification = notification.Notification() |
197 DOM.addEventPreview(self) | 95 DOM.addEventPreview(self) |
198 self.importPlugins() | 96 self.importPlugins() |
199 self._register = RegisterCall() | 97 self._register = json.RegisterCall() |
200 self._register.call('getMenus', self.gotMenus) | 98 self._register.call('getMenus', self.gotMenus) |
201 self._register.call('registerParams', None) | 99 self._register.call('registerParams', None) |
202 self._register.call('isRegistered', self._isRegisteredCB) | 100 self._register.call('isRegistered', self._isRegisteredCB) |
203 self.initialised = False | 101 self.initialised = False |
204 self.init_cache = [] # used to cache events until initialisation is done | 102 self.init_cache = [] # used to cache events until initialisation is done |
205 self.cached_params = {} | 103 self.cached_params = {} |
206 self.next_rsm_index = 0 | 104 self.next_rsm_index = 0 |
207 | 105 |
106 #FIXME: microblog cache should be managed directly in blog module | |
107 self.mblog_cache = [] # used to keep our own blog entries in memory, to show them in new mblog panel | |
108 | |
109 # self._selected_listeners = set() # FIXME: to be done with new listeners mechanism | |
110 | |
111 @property | |
112 def whoami(self): | |
113 # XXX: works because Libervia is mono-profile | |
114 # if one day Libervia manage several profiles at once, this must be deleted | |
115 return self.profiles[C.PROF_KEY_NONE].whoami | |
116 | |
117 @property | |
118 def contact_list(self): | |
119 return self.contact_lists[C.PROF_KEY_NONE] | |
120 | |
121 @property | |
122 def visible_widgets(self): | |
123 widgets_panel = self.tab_panel.getCurrentPanel() | |
124 return [wid for wid in widgets_panel.widgets if isinstance(wid, quick_widgets.QuickWidget)] | |
125 | |
126 @property | |
127 def base_location(self): | |
128 """Return absolute base url of this Libervia instance""" | |
129 url = Window.getLocation().getHref() | |
130 if url.endswith(C.LIBERVIA_MAIN_PAGE): | |
131 url = url[:-len(C.LIBERVIA_MAIN_PAGE)] | |
132 if url.endswith("/"): | |
133 url = url[:-1] | |
134 return url | |
135 | |
136 def registerSignal(self, functionName, handler=None, iface="core", with_profile=True): | |
137 if handler is None: | |
138 callback = getattr(self, "{}{}".format(functionName, "Handler")) | |
139 else: | |
140 callback = handler | |
141 | |
142 self.bridge_signals.register(functionName, callback, with_profile=with_profile) | |
143 | |
208 def importPlugins(self): | 144 def importPlugins(self): |
209 self.plugins = {} | 145 self.plugins = {} |
210 inhibited_menus = [] | |
211 # FIXME: plugins import should be dynamic and generic like in sat | |
212 try: | 146 try: |
213 self.plugins['otr'] = plugin_sec_otr.OTR(self) | 147 self.plugins['otr'] = plugin_sec_otr.OTR(self) |
214 except TypeError: # plugin_sec_otr has not been imported | 148 except TypeError: # plugin_sec_otr has not been imported |
215 inhibited_menus.append('OTR') | 149 pass |
216 | 150 |
217 class DummyPlugin(object): | 151 # def addSelectedListener(self, callback): |
218 def inhibitMenus(self): | 152 # self._selected_listeners.add(callback) |
219 return inhibited_menus | |
220 | |
221 self.plugins['dummy_plugin'] = DummyPlugin() | |
222 | |
223 def addSelectedListener(self, callback): | |
224 self._selected_listeners.add(callback) | |
225 | 153 |
226 def getSelected(self): | 154 def getSelected(self): |
227 wid = self.tab_panel.getCurrentPanel() | 155 wid = self.tab_panel.getCurrentPanel() |
228 if not isinstance(wid, base_widget.WidgetsPanel): | 156 if not isinstance(wid, libervia_widget.WidgetsPanel): |
229 log.error("Tab widget is not a base_widget.WidgetsPanel, can't get selected widget") | 157 log.error("Tab widget is not a WidgetsPanel, can't get selected widget") |
230 return None | 158 return None |
231 return wid.selected | 159 return wid.selected |
232 | 160 |
233 def setSelected(self, widget): | 161 def setSelected(self, widget): |
234 """Define the selected widget""" | 162 """Define the selected widget""" |
235 widgets_panel = self.tab_panel.getCurrentPanel() | 163 widgets_panel = self.tab_panel.getCurrentPanel() |
236 if not isinstance(widgets_panel, base_widget.WidgetsPanel): | 164 if not isinstance(widgets_panel, libervia_widget.WidgetsPanel): |
237 return | 165 return |
238 | 166 |
239 selected = widgets_panel.selected | 167 selected = widgets_panel.selected |
240 | 168 |
241 if selected == widget: | 169 if selected == widget: |
242 return | 170 return |
243 | 171 |
244 if selected: | 172 if selected: |
245 selected.removeStyleName('selected_widget') | 173 selected.removeStyleName('selected_widget') |
246 | 174 |
175 # FIXME: check that widget is in the current WidgetsPanel | |
247 widgets_panel.selected = widget | 176 widgets_panel.selected = widget |
177 self.selected_widget = widget | |
248 | 178 |
249 if widget: | 179 if widget: |
250 widgets_panel.selected.addStyleName('selected_widget') | 180 widgets_panel.selected.addStyleName('selected_widget') |
251 | 181 |
252 for callback in self._selected_listeners: | 182 # FIXME: |
253 callback(widget) | 183 # for callback in self._selected_listeners: |
184 # callback(widget) | |
254 | 185 |
255 def resize(self): | 186 def resize(self): |
256 """Resize elements""" | 187 """Resize elements""" |
257 Window.onResize() | 188 Window.onResize() |
258 | 189 |
259 def onBeforeTabSelected(self, sender, tab_index): | 190 def onBeforeTabSelected(self, sender, tab_index): |
260 return True | 191 return True |
261 | 192 |
262 def onTabSelected(self, sender, tab_index): | 193 def onTabSelected(self, sender, tab_index): |
263 selected = self.getSelected() | 194 pass |
264 for callback in self._selected_listeners: | 195 # selected = self.getSelected() |
265 callback(selected) | 196 # FIXME: |
197 # for callback in self._selected_listeners: | |
198 # callback(selected) | |
266 | 199 |
267 def onEventPreview(self, event): | 200 def onEventPreview(self, event): |
268 if event.type in ["keydown", "keypress", "keyup"] and event.keyCode == KEY_ESCAPE: | 201 if event.type in ["keydown", "keypress", "keyup"] and event.keyCode == KEY_ESCAPE: |
269 #needed to prevent request cancellation in Firefox | 202 #needed to prevent request cancellation in Firefox |
270 event.preventDefault() | 203 event.preventDefault() |
271 return True | 204 return True |
272 | 205 |
273 def getAvatar(self, jid_str): | 206 # FIXME: must not call _entityDataUpdatedCb by itself |
207 # should not get VCard, backend plugin must be fixed too | |
208 def getAvatarURL(self, jid_): | |
274 """Return avatar of a jid if in cache, else ask for it. | 209 """Return avatar of a jid if in cache, else ask for it. |
275 | 210 |
276 @param jid_str (str): JID of the contact | 211 @param jid_ (jid.JID): JID of the contact |
277 @return: the URL to the avatar (str) | 212 @return: the URL to the avatar (unicode) |
278 """ | 213 """ |
279 def dataReceived(result): | 214 assert isinstance(jid_, jid.JID) |
280 if 'avatar' in result: | 215 contact_list = self.contact_list # pyjamas issue: need a temporary variable to call a property's method |
281 self._entityDataUpdatedCb(jid_str, 'avatar', result['avatar']) | 216 avatar_hash = contact_list.getCache(jid_, 'avatar') |
282 else: | 217 if avatar_hash is None: |
283 self.bridge.call("getCard", None, jid_str) | 218 # we have no value for avatar_hash, so we request the vcard |
284 | 219 self.bridge.getCard(unicode(jid_), profile=C.PROF_KEY_NONE) |
285 def avatarError(error_data): | 220 if not avatar_hash: |
286 # The jid is maybe not in our roster, we ask for the VCard | 221 return C.DEFAULT_AVATAR_URL |
287 self.bridge.call("getCard", None, jid_str) | 222 ret = os.path.join(C.AVATARS_DIR, avatar_hash) |
288 | 223 return ret |
289 if jid_str not in self.avatars_cache: | |
290 self.bridge.call('getEntityData', (dataReceived, avatarError), jid_str, ['avatar']) | |
291 self.avatars_cache[jid_str] = C.DEFAULT_AVATAR | |
292 return self.avatars_cache[jid_str] | |
293 | 224 |
294 def registerWidget(self, wid): | 225 def registerWidget(self, wid): |
295 log.debug("Registering %s" % wid.getDebugName()) | 226 log.debug("Registering %s" % wid.getDebugName()) |
296 self.libervia_widgets.add(wid) | 227 self.libervia_widgets.add(wid) |
297 | 228 |
302 log.warning('trying to remove a non registered Widget: %s' % wid.getDebugName()) | 233 log.warning('trying to remove a non registered Widget: %s' % wid.getDebugName()) |
303 | 234 |
304 def refresh(self): | 235 def refresh(self): |
305 """Refresh the general display.""" | 236 """Refresh the general display.""" |
306 self.panel.refresh() | 237 self.panel.refresh() |
307 if self.getCachedParam(C.COMPOSITION_KEY, C.ENABLE_UNIBOX_PARAM) == 'true': | |
308 self.uni_box = self.panel.unibox_panel.unibox | |
309 else: | |
310 self.uni_box = None | |
311 for lib_wid in self.libervia_widgets: | 238 for lib_wid in self.libervia_widgets: |
312 lib_wid.refresh() | 239 lib_wid.refresh() |
313 self.resize() | 240 self.resize() |
314 | 241 |
315 def addTab(self, label, wid, select=True): | |
316 """Create a new tab and eventually add a widget in | |
317 @param label: label of the tab | |
318 @param wid: LiberviaWidget to add | |
319 @param select: True to select the added tab | |
320 """ | |
321 widgets_panel = base_widget.WidgetsPanel(self) | |
322 self.tab_panel.add(widgets_panel, label) | |
323 widgets_panel.addWidget(wid) | |
324 if select: | |
325 self.tab_panel.selectTab(self.tab_panel.getWidgetCount() - 1) | |
326 return widgets_panel | |
327 | |
328 def addWidget(self, wid, tab_index=None): | 242 def addWidget(self, wid, tab_index=None): |
329 """ Add a widget at the bottom of the current or specified tab | 243 """ Add a widget at the bottom of the current or specified tab |
244 | |
330 @param wid: LiberviaWidget to add | 245 @param wid: LiberviaWidget to add |
331 @param tab_index: index of the tab to add the widget to""" | 246 @param tab_index: index of the tab to add the widget to |
247 """ | |
332 if tab_index is None or tab_index < 0 or tab_index >= self.tab_panel.getWidgetCount(): | 248 if tab_index is None or tab_index < 0 or tab_index >= self.tab_panel.getWidgetCount(): |
333 panel = self.tab_panel.getCurrentPanel() | 249 panel = self.tab_panel.getCurrentPanel() |
334 else: | 250 else: |
335 panel = self.tab_panel.tabBar.getTabWidget(tab_index) | 251 panel = self.tab_panel.deck.getWidget(tab_index) |
336 panel.addWidget(wid) | 252 panel.addWidget(wid) |
337 | 253 |
338 def displayNotification(self, title, body): | 254 def displayNotification(self, title, body): |
339 self.notification.notify(title, body) | 255 self.notification.notify(title, body) |
340 | 256 |
341 def gotMenus(self, menus): | 257 def gotMenus(self, backend_menus): |
342 """Put the menus data in cache and build the main menu bar | 258 """Put the menus data in cache and build the main menu bar |
343 | 259 |
344 @param menus (list[tuple]): menu data | 260 @param backend_menus (list[tuple]): menu data from backend |
345 """ | 261 """ |
346 def process(menus, inhibited=None): | 262 main_menu = self.panel.menu # most of global menu callbacks are in main_menu |
347 for raw_menu in menus: | 263 |
348 id_, type_, path, path_i18n = raw_menu | 264 # Categories (with icons) |
349 if inhibited and path[0] in inhibited: | 265 self.menus.addCategory(C.MENU_GLOBAL, [D_(u"General")], extra={'icon': 'home'}) |
350 continue | 266 self.menus.addCategory(C.MENU_GLOBAL, [D_(u"Contacts")], extra={'icon': 'social'}) |
351 menus_data = self.menus.setdefault(type_, []) | 267 self.menus.addCategory(C.MENU_GLOBAL, [D_(u"Groups")], extra={'icon': 'social'}) |
352 menus_data.append((id_, path, path_i18n)) | 268 self.menus.addCategory(C.MENU_GLOBAL, [D_(u"Games")], extra={'icon': 'games'}) |
353 | 269 |
354 self.menus = {} | 270 # menus to have before backend menus |
355 inhibited = set() | 271 self.menus.addMenu(C.MENU_GLOBAL, (D_(u"Groups"), D_(u"Discussion")), callback=main_menu.onJoinRoom) |
356 extras = [] | 272 |
357 for plugin in self.plugins.values(): | 273 # menus added by the backend/plugins (include other types than C.MENU_GLOBAL) |
358 if hasattr(plugin, "inhibitMenus"): | 274 self.menus.addMenus(backend_menus, top_extra={'icon': 'plugins'}) |
359 inhibited.update(plugin.inhibitMenus()) | 275 |
360 if hasattr(plugin, "extraMenus"): | 276 # menus to have under backend menus |
361 extras.extend(plugin.extraMenus()) | 277 self.menus.addMenu(C.MENU_GLOBAL, (D_(u"Contacts"), D_(u"Manage groups")), callback=main_menu.onManageContactGroups) |
362 process(menus, inhibited) | 278 |
363 process(extras) | 279 # separator and right hand menus |
364 self.panel.menu.createMenus() | 280 self.menus.addMenuItem(C.MENU_GLOBAL, [], quick_menus.MenuSeparator()) |
281 | |
282 self.menus.addMenu(C.MENU_GLOBAL, (D_(u"Help"), D_("Social contract")), top_extra={'icon': 'help'}, callback=main_menu.onSocialContract) | |
283 self.menus.addMenu(C.MENU_GLOBAL, (D_(u"Help"), D_("About")), callback=main_menu.onAbout) | |
284 self.menus.addMenu(C.MENU_GLOBAL, (D_(u"Settings"), D_("Account")), top_extra={'icon': 'settings'}, callback=main_menu.onAccount) | |
285 self.menus.addMenu(C.MENU_GLOBAL, (D_(u"Settings"), D_("Parameters")), callback=main_menu.onParameters) | |
286 # XXX: temporary, will change when a full profile will be managed in SÃ T | |
287 self.menus.addMenu(C.MENU_GLOBAL, (D_(u"Settings"), D_("Upload avatar")), callback=main_menu.onAvatarUpload) | |
288 | |
289 # we call listener to have menu added by local classes/plugins | |
290 self.callListeners('gotMenus') # FIXME: to be done another way or moved to quick_app | |
291 | |
292 # and finally the menus which must appear at the bottom | |
293 self.menus.addMenu(C.MENU_GLOBAL, (D_(u"General"), D_(u"Disconnect")), callback=main_menu.onDisconnect) | |
294 | |
295 # we can now display all the menus | |
296 main_menu.update(C.MENU_GLOBAL) | |
365 | 297 |
366 def _isRegisteredCB(self, result): | 298 def _isRegisteredCB(self, result): |
367 registered, warning = result | 299 registered, warning = result |
368 if not registered: | 300 if not registered: |
369 self._register_box = register.RegisterBox(self.logged) | 301 self._register_box = register.RegisterBox(self.logged) |
384 def logged(self): | 316 def logged(self): |
385 if self._register_box: | 317 if self._register_box: |
386 self._register_box.hide() | 318 self._register_box.hide() |
387 del self._register_box # don't work if self._register_box is None | 319 del self._register_box # don't work if self._register_box is None |
388 | 320 |
389 # display the real presence status panel | 321 # display the presence status panel and tab bar |
390 self.panel.header.remove(self.status_panel) | 322 self.presence_status_panel = main_panel.PresenceStatusPanel(self) |
391 self.status_panel = panels.PresenceStatusPanel(self) | 323 self.panel.addPresenceStatusPanel(self.presence_status_panel) |
392 self.panel.header.add(self.status_panel) | 324 self.panel.tab_panel.getTabBar().setVisible(True) |
325 | |
326 self.bridge_signals.call('getSignals', self.bridge_signals.signalHandler) | |
393 | 327 |
394 #it's time to fill the page | 328 #it's time to fill the page |
395 self.bridge.call('getContacts', self._getContactsCB) | 329 # self.bridge.call('getContacts', self._getContactsCB) |
396 self.bridge.call('getParamsUI', self._getParamsUICB) | 330 # self.bridge.call('getParamsUI', self._getParamsUICB) |
397 self.bridge_signals.call('getSignals', self._getSignalsCB) | 331 # self.bridge_signals.call('getSignals', self._getSignalsCB) |
398 #We want to know our own jid | 332 # #We want to know our own jid |
399 self.bridge.call('getProfileJid', self._getProfileJidCB) | 333 # self.bridge.call('getProfileJid', self._getProfileJidCB) |
400 | 334 |
401 def domain_cb(value): | 335 def domain_cb(value): |
402 self._defaultDomain = value | 336 self._defaultDomain = value |
403 log.info("new account domain: %s" % value) | 337 log.info("new account domain: %s" % value) |
404 | 338 |
405 def domain_eb(value): | 339 def domain_eb(value): |
406 self._defaultDomain = "libervia.org" | 340 self._defaultDomain = "libervia.org" |
407 | 341 |
408 self.bridge.call("getNewAccountDomain", (domain_cb, domain_eb)) | 342 self.bridge.getNewAccountDomain(callback=domain_cb, errback=domain_eb) |
409 self.discuss_panel.addWidget(panels.MicroblogPanel(self, [])) | 343 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. |
410 | 344 # self.discuss_panel.addWidget(panel.MicroblogPanel(self, [])) |
411 # get cached params and refresh the display | 345 |
412 def param_cb(cat, name, count): | 346 # # get cached params and refresh the display |
413 count[0] += 1 | 347 # def param_cb(cat, name, count): |
414 refresh = count[0] == len(C.CACHED_PARAMS) | 348 # count[0] += 1 |
415 return lambda value: self._paramUpdate(name, value, cat, refresh) | 349 # refresh = count[0] == len(C.CACHED_PARAMS) |
416 | 350 # return lambda value: self._paramUpdate(name, value, cat, refresh) |
417 count = [0] # used to do something similar to DeferredList | 351 |
418 for cat, name in C.CACHED_PARAMS: | 352 # count = [0] # used to do something similar to DeferredList |
419 self.bridge.call('asyncGetParamA', param_cb(cat, name, count), name, cat) | 353 # for cat, name in C.CACHED_PARAMS: |
354 # self.bridge.call('asyncGetParamA', param_cb(cat, name, count), name, cat) | |
355 | |
356 def profilePlugged(self, dummy): # FIXME: to be called as a "profilePlugged" listener? | |
357 QuickApp.profilePlugged(self, dummy) | |
358 | |
359 microblog_widget = self.displayWidget(blog.MicroblogPanel, ()) | |
360 self.setSelected(microblog_widget) | |
361 | |
362 # we fill the panels already here | |
363 for wid in self.widgets.getWidgets(blog.MicroblogPanel): | |
364 if wid.accept_all(): | |
365 self.bridge.getMassiveMblogs('ALL', (), None, profile=C.PROF_KEY_NONE, callback=wid.massiveInsert) | |
366 else: | |
367 self.bridge.getMassiveMblogs('GROUP', list(wid.accepted_groups), None, profile=C.PROF_KEY_NONE, callback=wid.massiveInsert) | |
368 | |
369 #we ask for our own microblogs: | |
370 self.loadOurMainEntries() | |
371 | |
372 def addContactList(self, dummy): | |
373 contact_list = ContactList(self) | |
374 self.panel.addContactList(contact_list) | |
375 | |
376 # FIXME: the contact list height has to be set manually the first time | |
377 self.resize() | |
378 | |
379 return contact_list | |
380 | |
381 def newWidget(self, wid): | |
382 log.debug("newWidget: {}".format(wid)) | |
383 self.addWidget(wid) | |
384 | |
385 def newMessageHandler(self, from_jid_s, msg, type_, to_jid_s, extra, profile=C.PROF_KEY_NONE): | |
386 if type_ == C.MESS_TYPE_HEADLINE: | |
387 from_jid = jid.JID(from_jid_s) | |
388 if from_jid.domain == self._defaultDomain: | |
389 # we display announcement from the server in a dialog for better visibility | |
390 try: | |
391 title = extra['subject'] | |
392 except KeyError: | |
393 title = _('Announcement from %s') % from_jid | |
394 msg = strings.addURLToText(html_tools.XHTML2Text(msg)) | |
395 dialog.InfoDialog(title, msg).show() | |
396 return | |
397 QuickApp.newMessageHandler(self, from_jid_s, msg, type_, to_jid_s, extra, profile) | |
398 | |
399 def disconnectedHandler(self, profile): | |
400 QuickApp.disconnectedHandler(self, profile) | |
401 Window.getLocation().reload() | |
402 | |
403 def setStatusOnline(self, online=True, show='', statuses={}, profile=C.PROF_KEY_NONE): | |
404 self.presence_status_panel.setPresence(show) | |
405 if statuses: | |
406 # FIXME: retrieve user language status or fallback to 'default' | |
407 self.presence_status_panel.setStatus(statuses.values()[0]) | |
420 | 408 |
421 def _tryAutoConnect(self, skip_validation=False): | 409 def _tryAutoConnect(self, skip_validation=False): |
422 """This method retrieve the eventual URL parameters to auto-connect the user. | 410 """This method retrieve the eventual URL parameters to auto-connect the user. |
423 @param skip_validation: if True, set the form values but do not validate it | 411 @param skip_validation: if True, set the form values but do not validate it |
424 """ | 412 """ |
445 ui = xmlui.create(self, xml_data=data['xmlui']) | 433 ui = xmlui.create(self, xml_data=data['xmlui']) |
446 ui.show() | 434 ui.show() |
447 elif "public_blog" in data: | 435 elif "public_blog" in data: |
448 # TODO: use the bare instead of node when all blogs can be retrieved | 436 # TODO: use the bare instead of node when all blogs can be retrieved |
449 node = jid.JID(data['public_blog']).node | 437 node = jid.JID(data['public_blog']).node |
450 self.addTab("%s's blog" % node, panels.WebPanel(self, "/blog/%s" % node)) | 438 # FIXME: "/blog/{}" won't work with unicode nodes |
439 self.displayWidget(widget.WebWidget, "/blog/{}".format(node), show_url=False, new_tab=_(u"{}'s blog").format(unicode(node))) | |
451 else: | 440 else: |
452 dialog.InfoDialog("Error", | 441 dialog.InfoDialog("Error", |
453 "Unmanaged action result", Width="400px").center() | 442 "Unmanaged action result", Width="400px").center() |
454 | 443 |
455 def _actionEb(self, err_data): | 444 def _actionEb(self, err_data): |
456 err_code, err_obj = err_data | 445 err_code, err_obj = err_data |
457 dialog.InfoDialog("Error", | 446 dialog.InfoDialog("Error", |
458 str(err_obj), Width="400px").center() | 447 unicode(err_obj), Width="400px").center() |
459 | 448 |
460 def launchAction(self, callback_id, data): | 449 def launchAction(self, callback_id, data=None, callback=None, profile=C.PROF_KEY_NONE): |
461 """ Launch a dynamic action | 450 """ Launch a dynamic action |
462 @param callback_id: id of the action to launch | 451 @param callback_id: id of the action to launch |
463 @param data: data needed only for certain actions | 452 @param data: data needed only for certain actions |
464 | 453 |
465 """ | 454 """ |
466 if data is None: | 455 if data is None: |
467 data = {} | 456 data = {} |
468 self.bridge.call('launchAction', (self._actionCb, self._actionEb), callback_id, data) | 457 self.bridge.launchAction(callback_id, data, profile=profile, callback=self._actionCb, errback=self._actionEb) |
469 | 458 |
470 def _getContactsCB(self, contacts_data): | 459 def _getContactsCB(self, contacts_data): |
471 for contact_ in contacts_data: | 460 for contact_ in contacts_data: |
472 jid, attributes, groups = contact_ | 461 jid, attributes, groups = contact_ |
473 self._newContactCb(jid, attributes, groups) | 462 self._newContactCb(jid, attributes, groups) |
474 | |
475 def _getSignalsCB(self, signal_data): | |
476 self.bridge_signals.call('getSignals', self._getSignalsCB) | |
477 if len(signal_data) == 1: | |
478 signal_data.append([]) | |
479 log.debug("Got signal ==> name: %s, params: %s" % (signal_data[0], signal_data[1])) | |
480 name, args = signal_data | |
481 if name == 'personalEvent': | |
482 self._personalEventCb(*args) | |
483 elif name == 'newMessage': | |
484 self._newMessageCb(*args) | |
485 elif name == 'presenceUpdate': | |
486 self._presenceUpdateCb(*args) | |
487 elif name == 'paramUpdate': | |
488 self._paramUpdate(*args) | |
489 elif name == 'roomJoined': | |
490 self._roomJoinedCb(*args) | |
491 elif name == 'roomLeft': | |
492 self._roomLeftCb(*args) | |
493 elif name == 'roomUserJoined': | |
494 self._roomUserJoinedCb(*args) | |
495 elif name == 'roomUserLeft': | |
496 self._roomUserLeftCb(*args) | |
497 elif name == 'roomUserChangedNick': | |
498 self._roomUserChangedNickCb(*args) | |
499 elif name == 'askConfirmation': | |
500 self._askConfirmation(*args) | |
501 elif name == 'newAlert': | |
502 self._newAlert(*args) | |
503 elif name == 'tarotGamePlayers': | |
504 self._tarotGameStartedCb(True, *args) | |
505 elif name == 'tarotGameStarted': | |
506 self._tarotGameStartedCb(False, *args) | |
507 elif name == 'tarotGameNew' or \ | |
508 name == 'tarotGameChooseContrat' or \ | |
509 name == 'tarotGameShowCards' or \ | |
510 name == 'tarotGameInvalidCards' or \ | |
511 name == 'tarotGameCardsPlayed' or \ | |
512 name == 'tarotGameYourTurn' or \ | |
513 name == 'tarotGameScore': | |
514 self._tarotGameGenericCb(name, args[0], args[1:]) | |
515 elif name == 'radiocolPlayers': | |
516 self._radioColStartedCb(True, *args) | |
517 elif name == 'radiocolStarted': | |
518 self._radioColStartedCb(False, *args) | |
519 elif name == 'radiocolPreload': | |
520 self._radioColGenericCb(name, args[0], args[1:]) | |
521 elif name == 'radiocolPlay': | |
522 self._radioColGenericCb(name, args[0], args[1:]) | |
523 elif name == 'radiocolNoUpload': | |
524 self._radioColGenericCb(name, args[0], args[1:]) | |
525 elif name == 'radiocolUploadOk': | |
526 self._radioColGenericCb(name, args[0], args[1:]) | |
527 elif name == 'radiocolSongRejected': | |
528 self._radioColGenericCb(name, args[0], args[1:]) | |
529 elif name == 'subscribe': | |
530 self._subscribeCb(*args) | |
531 elif name == 'contactDeleted': | |
532 self._contactDeletedCb(*args) | |
533 elif name == 'newContact': | |
534 self._newContactCb(*args) | |
535 elif name == 'entityDataUpdated': | |
536 self._entityDataUpdatedCb(*args) | |
537 elif name == 'chatStateReceived': | |
538 self._chatStateReceivedCb(*args) | |
539 | 463 |
540 def _getParamsUICB(self, xml_ui): | 464 def _getParamsUICB(self, xml_ui): |
541 """Hide the parameters item if there's nothing to display""" | 465 """Hide the parameters item if there's nothing to display""" |
542 if not xml_ui: | 466 if not xml_ui: |
543 self.panel.menu.removeItemParams() | 467 self.panel.menu.removeItemParams() |
556 continue | 480 continue |
557 if 'groups' in mblog: | 481 if 'groups' in mblog: |
558 _groups = set(mblog['groups'].split() if mblog['groups'] else []) | 482 _groups = set(mblog['groups'].split() if mblog['groups'] else []) |
559 else: | 483 else: |
560 _groups = None | 484 _groups = None |
561 mblog_entry = panels.MicroblogItem(mblog) | 485 mblog_entry = blog.MicroblogItem(mblog) |
562 cache.append((_groups, mblog_entry)) | 486 cache.append((_groups, mblog_entry)) |
563 | 487 |
564 self.mblog_cache.extend(cache) | 488 self.mblog_cache.extend(cache) |
565 if len(self.mblog_cache) > MAX_MBLOG_CACHE: | 489 if len(self.mblog_cache) > MAX_MBLOG_CACHE: |
566 del self.mblog_cache[0:len(self.mblog_cache - MAX_MBLOG_CACHE)] | 490 del self.mblog_cache[0:len(self.mblog_cache - MAX_MBLOG_CACHE)] |
567 | 491 |
568 widget_list = [mblog_panel] if mblog_panel else self.libervia_widgets | 492 widget_list = [mblog_panel] if mblog_panel else self.widgets.getWidgets(blog.MicroblogPanel) |
569 for lib_wid in widget_list: | 493 |
570 if isinstance(lib_wid, panels.MicroblogPanel): | 494 for wid in widget_list: |
571 self.fillMicroblogPanel(lib_wid, cache) | 495 self.fillMicroblogPanel(wid, cache) |
496 | |
497 # FIXME | |
572 | 498 |
573 if self.initialised: | 499 if self.initialised: |
574 return | 500 return |
575 self.initialised = True # initialisation phase is finished here | 501 self.initialised = True # initialisation phase is finished here |
576 for event_data in self.init_cache: # so we have to send all the cached events | 502 for event_data in self.init_cache: # so we have to send all the cached events |
577 self._personalEventCb(*event_data) | 503 self.personalEventHandler(*event_data) |
578 del self.init_cache | 504 del self.init_cache |
579 | 505 |
580 def _getProfileJidCB(self, jid_s): | 506 def _getProfileJidCB(self, jid_s): |
581 self.whoami = jid.JID(jid_s) | 507 # FIXME |
582 #we can now ask our status | 508 raise Exception("should not be here !") |
583 self.bridge.call('getPresenceStatuses', self._getPresenceStatusesCb) | 509 # self.whoami = jid.JID(jid_s) |
584 #the rooms where we are | 510 # #we can now ask our status |
585 self.bridge.call('getRoomsJoined', self._getRoomsJoinedCb) | 511 # self.bridge.call('getPresenceStatuses', self._getPresenceStatusesCb) |
586 #and if there is any subscription request waiting for us | 512 # #the rooms where we are |
587 self.bridge.call('getWaitingSub', self._getWaitingSubCb) | 513 # self.bridge.call('getRoomsJoined', self._getRoomsJoinedCb) |
588 #we fill the panels already here | 514 # #and if there is any subscription request waiting for us |
589 for lib_wid in self.libervia_widgets: | 515 # self.bridge.call('getWaitingSub', self._getWaitingSubCb) |
590 if isinstance(lib_wid, panels.MicroblogPanel): | 516 # #we fill the panels already here |
591 if lib_wid.accept_all(): | 517 # for lib_wid in self.libervia_widgets: |
592 self.bridge.call('getMassiveMblogs', lib_wid.massiveInsert, 'ALL', []) | 518 # if isinstance(lib_wid, panel.MicroblogPanel): |
593 else: | 519 # if lib_wid.accept_all(): |
594 self.bridge.call('getMassiveMblogs', lib_wid.massiveInsert, 'GROUP', lib_wid.accepted_groups) | 520 # self.bridge.call('getMassiveLastMblogs', lib_wid.massiveInsert, 'ALL', [], 10) |
595 | 521 # else: |
596 #we ask for our own microblogs: | 522 # self.bridge.call('getMassiveLastMblogs', lib_wid.massiveInsert, 'GROUP', lib_wid.accepted_groups, 10) |
597 self.loadOurMainEntries() | 523 |
598 | 524 # #we ask for our own microblogs: |
599 # initialize plugins which waited for the connection to be done | 525 # self.loadOurMainEntries() |
600 for plugin in self.plugins.values(): | 526 |
601 if hasattr(plugin, 'profileConnected'): | 527 # # initialize plugins which waited for the connection to be done |
602 plugin.profileConnected() | 528 # for plugin in self.plugins.values(): |
529 # if hasattr(plugin, 'profileConnected'): | |
530 # plugin.profileConnected() | |
603 | 531 |
604 def loadOurMainEntries(self, index=0, mblog_panel=None): | 532 def loadOurMainEntries(self, index=0, mblog_panel=None): |
605 """Load a page of our own blogs from the cache or ask them to the | 533 """Load a page of our own blogs from the cache or ask them to the |
606 backend. Then fill the panels with them. | 534 backend. Then fill the panels with them. |
607 | 535 |
608 @param index (int): starting index of the blog page to retrieve. | 536 @param index (int): starting index of the blog page to retrieve. |
609 @param mblog_panel (MicroblogPanel): the panel to fill, or all if None. | 537 @param mblog_panel (MicroblogPanel): the panel to fill, or all if None. |
610 """ | 538 """ |
611 delta = index - self.next_rsm_index | 539 delta = index - self.next_rsm_index |
612 if delta < 0: | 540 if delta < 0: |
613 assert(mblog_panel is not None) | 541 assert mblog_panel is not None |
614 self.fillMicroblogPanel(mblog_panel, self.mblog_cache[index:index + C.RSM_MAX_ITEMS]) | 542 self.fillMicroblogPanel(mblog_panel, self.mblog_cache[index:index + C.RSM_MAX_ITEMS]) |
615 return | 543 return |
616 | 544 |
617 def cb(result): | 545 def cb(result): |
618 self._ownBlogsFills(result, mblog_panel) | 546 self._ownBlogsFills(result, mblog_panel) |
619 | 547 |
620 rsm = {'max': str(delta + C.RSM_MAX_ITEMS), 'index': str(self.next_rsm_index)} | 548 rsm = {'max': str(delta + C.RSM_MAX_ITEMS), 'index': str(self.next_rsm_index)} |
621 self.bridge.call('getMassiveMblogs', cb, 'JID', [self.whoami.bare], rsm) | 549 self.bridge.getMassiveMblogs('JID', [unicode(self.whoami.bare)], rsm, callback=cb, profile=C.PROF_KEY_NONE) |
622 self.next_rsm_index = index + C.RSM_MAX_ITEMS | 550 self.next_rsm_index = index + C.RSM_MAX_ITEMS |
623 | 551 |
624 ## Signals callbacks ## | 552 ## Signals callbacks ## |
625 | 553 |
626 def _personalEventCb(self, sender, event_type, data): | 554 def personalEventHandler(self, sender, event_type, data): |
555 # FIXME: move some code from here to QuickApp | |
627 if not self.initialised: | 556 if not self.initialised: |
628 self.init_cache.append((sender, event_type, data)) | 557 self.init_cache.append((sender, event_type, data)) |
629 return | 558 return |
630 sender = jid.JID(sender).bare | 559 sender = jid.JID(sender).bare |
631 if event_type == "MICROBLOG": | 560 if event_type == "MICROBLOG": |
634 return | 563 return |
635 if 'groups' in data: | 564 if 'groups' in data: |
636 _groups = set(data['groups'].split() if data['groups'] else []) | 565 _groups = set(data['groups'].split() if data['groups'] else []) |
637 else: | 566 else: |
638 _groups = None | 567 _groups = None |
639 mblog_entry = panels.MicroblogItem(data) | 568 mblog_entry = blog.MicroblogItem(data) |
640 | 569 |
641 for lib_wid in self.libervia_widgets: | 570 for wid in self.widgets.getWidgets(blog.MicroblogPanel): |
642 if isinstance(lib_wid, panels.MicroblogPanel): | 571 wid.addEntryIfAccepted(sender, _groups, mblog_entry) |
643 self.addBlogEntry(lib_wid, sender, _groups, mblog_entry) | |
644 | 572 |
645 if sender == self.whoami.bare: | 573 if sender == self.whoami.bare: |
646 found = False | 574 found = False |
647 for index in xrange(0, len(self.mblog_cache)): | 575 for index in xrange(0, len(self.mblog_cache)): |
648 entry = self.mblog_cache[index] | 576 entry = self.mblog_cache[index] |
655 if not found: | 583 if not found: |
656 self.mblog_cache.append((_groups, mblog_entry)) | 584 self.mblog_cache.append((_groups, mblog_entry)) |
657 if len(self.mblog_cache) > MAX_MBLOG_CACHE: | 585 if len(self.mblog_cache) > MAX_MBLOG_CACHE: |
658 del self.mblog_cache[0:len(self.mblog_cache - MAX_MBLOG_CACHE)] | 586 del self.mblog_cache[0:len(self.mblog_cache - MAX_MBLOG_CACHE)] |
659 elif event_type == 'MICROBLOG_DELETE': | 587 elif event_type == 'MICROBLOG_DELETE': |
660 for lib_wid in self.libervia_widgets: | 588 for wid in self.widgets.getWidgets(blog.MicroblogPanel): |
661 if isinstance(lib_wid, panels.MicroblogPanel): | 589 wid.removeEntry(data['type'], data['id']) |
662 lib_wid.removeEntry(data['type'], data['id']) | |
663 log.debug("%s %s %s" % (self.whoami.bare, sender, data['type'])) | 590 log.debug("%s %s %s" % (self.whoami.bare, sender, data['type'])) |
664 | 591 |
665 if sender == self.whoami.bare and data['type'] == 'main_item': | 592 if sender == self.whoami.bare and data['type'] == 'main_item': |
666 for index in xrange(0, len(self.mblog_cache)): | 593 for index in xrange(0, len(self.mblog_cache)): |
667 entry = self.mblog_cache[index] | 594 entry = self.mblog_cache[index] |
668 if entry[1].id == data['id']: | 595 if entry[1].id == data['id']: |
669 self.mblog_cache.remove(entry) | 596 self.mblog_cache.remove(entry) |
670 break | 597 break |
671 | 598 |
672 def addBlogEntry(self, mblog_panel, sender, _groups, mblog_entry): | |
673 """Check if an entry can go in MicroblogPanel and add to it | |
674 @param mblog_panel: MicroblogPanel instance | |
675 @param sender: jid of the entry sender | |
676 @param _groups: groups which can receive this entry | |
677 @param mblog_entry: panels.MicroblogItem instance""" | |
678 if mblog_entry.type == "comment" or mblog_panel.isJidAccepted(sender) or (_groups == None and self.whoami and sender == self.whoami.bare) \ | |
679 or (_groups and _groups.intersection(mblog_panel.accepted_groups)): | |
680 mblog_panel.addEntry(mblog_entry) | |
681 | |
682 def fillMicroblogPanel(self, mblog_panel, mblogs): | 599 def fillMicroblogPanel(self, mblog_panel, mblogs): |
683 """Fill a microblog panel with entries in cache | 600 """Fill a microblog panel with entries in cache |
601 | |
684 @param mblog_panel: MicroblogPanel instance | 602 @param mblog_panel: MicroblogPanel instance |
685 """ | 603 """ |
686 #XXX: only our own entries are cached | 604 #XXX: only our own entries are cached |
687 for cache_entry in mblogs: | 605 for cache_entry in mblogs: |
688 _groups, mblog_entry = cache_entry | 606 _groups, mblog_entry = cache_entry |
689 self.addBlogEntry(mblog_panel, self.whoami.bare, *cache_entry) | 607 mblog_panel.addEntryIfAccepted(self.whoami.bare, *cache_entry) |
690 | 608 |
691 def getEntityMBlog(self, entity): | 609 def getEntityMBlog(self, entity): |
692 log.info("geting mblog for entity [%s]" % (entity,)) | 610 log.info("geting mblog for entity [%s]" % (entity,)) |
693 for lib_wid in self.libervia_widgets: | 611 for lib_wid in self.libervia_widgets: |
694 if isinstance(lib_wid, panels.MicroblogPanel): | 612 if isinstance(lib_wid, blog.MicroblogPanel): |
695 if lib_wid.isJidAccepted(entity): | 613 if lib_wid.isJidAccepted(entity): |
696 self.bridge.call('getMassiveMblogs', lib_wid.massiveInsert, 'JID', [entity]) | 614 self.bridge.call('getMassiveMblogs', lib_wid.massiveInsert, 'JID', [unicode(entity)]) |
697 | 615 |
698 def getLiberviaWidget(self, class_, entity, ignoreOtherTabs=True): | 616 # def getLiberviaWidget(self, class_, entity, ignoreOtherTabs=True): |
699 """Get the corresponding panel if it exists. | 617 # """Get the corresponding panel if it exists. |
700 @param class_ (class): class of the panel (ChatPanel, MicroblogPanel...) | 618 # @param class_ (class): class of the panel (ChatPanel, MicroblogPanel...) |
701 @param entity (dict): dictionnary to define the entity. | 619 # @param entity (dict): dictionnary to define the entity. |
702 @param ignoreOtherTabs (bool): if True, the widgets that are not | 620 # @param ignoreOtherTabs (bool): if True, the widgets that are not |
703 contained by the currently selected tab will be ignored | 621 # contained by the currently selected tab will be ignored |
704 @return: the existing widget that has been found or None.""" | 622 # @return: the existing widget that has been found or None.""" |
705 selected_tab = self.tab_panel.getCurrentPanel() | 623 # selected_tab = self.tab_panel.getCurrentPanel() |
706 for lib_wid in self.libervia_widgets: | 624 # for lib_wid in self.libervia_widgets: |
707 parent = lib_wid.getWidgetsPanel(expect=False) | 625 # parent = lib_wid.getWidgetsPanel(expect=False) |
708 if parent is None or (ignoreOtherTabs and parent != selected_tab): | 626 # if parent is None or (ignoreOtherTabs and parent != selected_tab): |
709 # do not return a widget that is not in the currently selected tab | 627 # # do not return a widget that is not in the currently selected tab |
710 continue | 628 # continue |
711 if isinstance(lib_wid, class_): | 629 # if isinstance(lib_wid, class_): |
712 try: | 630 # try: |
713 if lib_wid.matchEntity(*(entity.values())): # XXX: passing **entity bugs! | 631 # if lib_wid.matchEntity(*(entity.values())): # XXX: passing **entity bugs! |
714 log.debug("existing widget found: %s" % lib_wid.getDebugName()) | 632 # log.debug("existing widget found: %s" % lib_wid.getDebugName()) |
715 return lib_wid | 633 # return lib_wid |
716 except AttributeError as e: | 634 # except AttributeError as e: |
717 e.stack_list() | 635 # e.stack_list() |
718 return None | 636 # return None |
719 return None | 637 # return None |
720 | 638 |
721 def getOrCreateLiberviaWidget(self, class_, entity, select=True, new_tab=None): | 639 def displayWidget(self, class_, target, dropped=False, new_tab=None, *args, **kwargs): |
722 """Get the matching LiberviaWidget if it exists, or create a new one. | 640 """Get or create a LiberviaWidget and select it. When the user dropped |
723 @param class_ (class): class of the panel (ChatPanel, MicroblogPanel...) | 641 something, a new widget is always created, otherwise we look for an |
724 @param entity (dict): dictionnary to define the entity. | 642 existing widget and re-use it if it's in the current tab. |
725 @param select (bool): if True, select the widget that has been found or created | 643 |
726 @param new_tab (str): if not None, a widget which is created is created in | 644 @arg class_(class): see quick_widgets.getOrCreateWidget |
727 a new tab. In that case new_tab is a unicode to label that new tab. | 645 @arg target: see quick_widgets.getOrCreateWidget |
728 If new_tab is not None and a widget is found, no tab is created. | 646 @arg dropped(bool): if True, assume the widget has been dropped |
729 @return: the newly created wigdet if REUSE_EXISTING_LIBERVIA_WIDGETS | 647 @arg new_tab(unicode): if not None, it holds the name of a new tab to |
730 is set to False or if the widget has not been found, the existing | 648 open for the widget. If None, use the default behavior. |
731 widget that has been found otherwise.""" | 649 @param args(list): optional args to create a new instance of class_ |
732 lib_wid = None | 650 @param kwargs(list): optional kwargs to create a new instance of class_ |
733 tab = None | 651 @return: the widget |
734 if REUSE_EXISTING_LIBERVIA_WIDGETS: | 652 """ |
735 lib_wid = self.getLiberviaWidget(class_, entity, new_tab is None) | 653 kwargs['profile'] = C.PROF_KEY_NONE |
736 if lib_wid is None: # create a new widget | 654 |
737 lib_wid = class_.createPanel(self, *(entity.values())) # XXX: passing **entity bugs! | 655 if dropped: |
738 if new_tab is None: | 656 kwargs['on_new_widget'] = None |
739 self.addWidget(lib_wid) | 657 kwargs['on_existing_widget'] = C.WIDGET_RECREATE |
740 else: | 658 wid = self.widgets.getOrCreateWidget(class_, target, *args, **kwargs) |
741 tab = self.addTab(new_tab, lib_wid, False) | 659 self.setSelected(wid) |
742 else: # reuse existing widget | 660 return wid |
743 tab = lib_wid.getWidgetsPanel(expect=False) | 661 |
744 if new_tab is None: | 662 if new_tab: |
745 if tab is not None: | 663 kwargs['on_new_widget'] = None |
746 tab.removeWidget(lib_wid) | 664 kwargs['on_existing_widget'] = C.WIDGET_RECREATE |
747 self.addWidget(lib_wid) | 665 wid = self.widgets.getOrCreateWidget(class_, target, *args, **kwargs) |
748 if select: | 666 self.tab_panel.addWidgetsTab(new_tab) |
749 if new_tab is not None: | 667 self.addWidget(wid, tab_index=self.tab_panel.getWidgetCount() - 1) |
750 self.tab_panel.selectTab(tab) | 668 return wid |
751 # must be done after the widget is added, | 669 |
752 # for example to scroll to the bottom | 670 kwargs['on_existing_widget'] = C.WIDGET_RAISE |
753 self.setSelected(lib_wid) | |
754 lib_wid.refresh() | |
755 return lib_wid | |
756 | |
757 def getRoomWidget(self, target): | |
758 """Get the MUC widget for the given target. | |
759 | |
760 @param target (jid.JID): BARE jid of the MUC | |
761 @return: panels.ChatPanel instance or None | |
762 """ | |
763 entity = {'item': target, 'type_': 'group'} | |
764 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... | |
765 return self.getLiberviaWidget(panels.ChatPanel, entity, ignoreOtherTabs=False) | |
766 return None | |
767 | |
768 def getOrCreateRoomWidget(self, target): | |
769 """Get the MUC widget for the given target, create it if necessary. | |
770 | |
771 @param target (jid.JID): BARE jid of the MUC | |
772 @return: panels.ChatPanel instance | |
773 """ | |
774 lib_wid = self.getRoomWidget(target) | |
775 if lib_wid: | |
776 return lib_wid | |
777 | |
778 # XXX: target.node.startwith(...) raises an error "startswith is not a function" | |
779 # This happens when node a is property defined in the JID class | |
780 # FIXME: pyjamas doesn't handle the properties well | |
781 node = target.node | |
782 | |
783 # XXX: it's not really beautiful, but it works :) | |
784 if node.startswith('sat_tarot_'): | |
785 tab_name = "Tarot" | |
786 elif node.startswith('sat_radiocol_'): | |
787 tab_name = "Radio collective" | |
788 else: | |
789 tab_name = target.node | |
790 | |
791 self.room_list.append(target) | |
792 entity = {'item': target, 'type_': 'group'} | |
793 return self.getOrCreateLiberviaWidget(panels.ChatPanel, entity, new_tab=tab_name) | |
794 | |
795 def _newMessageCb(self, from_jid_s, msg, msg_type, to_jid_s, extra): | |
796 from_jid = jid.JID(from_jid_s) | |
797 to_jid = jid.JID(to_jid_s) | |
798 for plugin in self.plugins.values(): | |
799 if hasattr(plugin, 'messageReceivedTrigger'): | |
800 if not plugin.messageReceivedTrigger(from_jid, msg, msg_type, to_jid, extra): | |
801 return # plugin returned False to interrupt the process | |
802 self.newMessageCb(from_jid, msg, msg_type, to_jid, extra) | |
803 | |
804 def newMessageCb(self, from_jid, msg, msg_type, to_jid, extra): | |
805 other = to_jid if from_jid.bare == self.whoami.bare else from_jid | |
806 lib_wid = self.getLiberviaWidget(panels.ChatPanel, {'item': other}, ignoreOtherTabs=False) | |
807 self.displayNotification(from_jid, msg) | |
808 if msg_type == 'headline' and from_jid.full() == self._defaultDomain: | |
809 try: | |
810 assert extra['subject'] # subject is defined and not empty | |
811 title = extra['subject'] | |
812 except (KeyError, AssertionError): | |
813 title = _('Announcement from %s') % from_jid.full() | |
814 msg = strings.addURLToText(html_tools.XHTML2Text(msg)) | |
815 dialog.InfoDialog(title, msg).show() | |
816 return | |
817 if lib_wid is not None: | |
818 if msg_type == C.MESS_TYPE_INFO: | |
819 lib_wid.printInfo(msg) | |
820 else: | |
821 lib_wid.printMessage(from_jid, msg, extra) | |
822 if 'header_info' in extra: | |
823 lib_wid.setHeaderInfo(extra['header_info']) | |
824 else: | |
825 # FIXME: "info" message and header info will be lost here | |
826 if not self.contact_panel.isContactInRoster(other.bare): | |
827 self.contact_panel.updateContact(other.bare, {}, [C.GROUP_NOT_IN_ROSTER]) | |
828 # The message has not been shown, we must indicate it | |
829 self.contact_panel.setContactMessageWaiting(other.bare, True) | |
830 | |
831 def _presenceUpdateCb(self, entity, show, priority, statuses): | |
832 entity_jid = jid.JID(entity) | |
833 if self.whoami and self.whoami == entity_jid: # XXX: QnD way to get our presence/status | |
834 assert(isinstance(self.status_panel, panels.PresenceStatusPanel)) | |
835 self.status_panel.setPresence(show) # pylint: disable=E1103 | |
836 if statuses: | |
837 self.status_panel.setStatus(statuses.values()[0]) # pylint: disable=E1103 | |
838 else: | |
839 bare_jid = entity_jid.bareJID() | |
840 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... | |
841 wid = self.getRoomWidget(bare_jid) | |
842 else: | |
843 wid = self.contact_panel | |
844 if show == 'unavailable': # XXX: save some resources as for now we only need 'unavailable' | |
845 for plugin in self.plugins.values(): | |
846 if hasattr(plugin, 'presenceReceivedTrigger'): | |
847 plugin.presenceReceivedTrigger(entity_jid, show, priority, statuses) | |
848 if wid: | |
849 wid.setConnected(entity_jid.bare, entity_jid.resource, show, priority, statuses) | |
850 | |
851 def _roomJoinedCb(self, room_jid_s, room_nicks, user_nick): | |
852 chat_panel = self.getOrCreateRoomWidget(jid.JID(room_jid_s)) | |
853 chat_panel.setUserNick(user_nick) | |
854 chat_panel.setPresents(room_nicks) | |
855 chat_panel.refresh() | |
856 | |
857 def _roomLeftCb(self, room_jid_s, room_nicks, user_nick): | |
858 try: | 671 try: |
859 del self.room_list[room_jid_s] | 672 wid = self.widgets.getOrCreateWidget(class_, target, *args, **kwargs) |
860 except KeyError: | 673 except quick_widgets.WidgetAlreadyExistsError: |
861 try: # as JID is a string-based class, we don't know what will please Pyjamas... | 674 kwargs['on_existing_widget'] = C.WIDGET_KEEP |
862 del self.room_list[jid.JID(room_jid_s)] | 675 wid = self.widgets.getOrCreateWidget(class_, target, *args, **kwargs) |
863 except KeyError: | 676 widgets_panel = wid.getParent(libervia_widget.WidgetsPanel, expect=False) |
864 pass | 677 if widgets_panel is None: |
865 | 678 # The widget exists but is hidden |
866 def _roomUserJoinedCb(self, room_jid_s, user_nick, user_data): | 679 self.addWidget(wid) |
867 lib_wid = self.getOrCreateRoomWidget(jid.JID(room_jid_s)) | 680 elif widgets_panel != self.tab_panel.getCurrentPanel(): |
868 if lib_wid: | 681 # the widget is on an other tab, so we add a new one here |
869 lib_wid.userJoined(user_nick, user_data) | 682 kwargs['on_existing_widget'] = C.WIDGET_RECREATE |
870 | 683 wid = self.widgets.getOrCreateWidget(class_, target, *args, **kwargs) |
871 def _roomUserLeftCb(self, room_jid_s, user_nick, user_data): | 684 self.addWidget(wid) |
872 lib_wid = self.getRoomWidget(jid.JID(room_jid_s)) | 685 self.setSelected(wid) |
873 if lib_wid: | 686 return wid |
874 lib_wid.userLeft(user_nick, user_data) | 687 |
875 | 688 |
876 def _roomUserChangedNickCb(self, room_jid_s, old_nick, new_nick): | 689 # def getOrCreateLiberviaWidget(self, class_, entity, select=True, new_tab=None): |
877 """Called when an user joined a MUC room""" | 690 # """Get the matching LiberviaWidget if it exists, or create a new one. |
878 lib_wid = self.getRoomWidget(jid.JID(room_jid_s)) | 691 # @param class_ (class): class of the panel (ChatPanel, MicroblogPanel...) |
879 if lib_wid: | 692 # @param entity (dict): dictionnary to define the entity. |
880 lib_wid.changeUserNick(old_nick, new_nick) | 693 # @param select (bool): if True, select the widget that has been found or created |
881 | 694 # @param new_tab (unicode): if not None, a widget which is created is created in |
882 def _tarotGameStartedCb(self, waiting, room_jid_s, referee, players): | 695 # a new tab. In that case new_tab is a unicode to label that new tab. |
883 lib_wid = self.getRoomWidget(jid.JID(room_jid_s)) | 696 # If new_tab is not None and a widget is found, no tab is created. |
884 if lib_wid: | 697 # @return: the newly created wigdet if REUSE_EXISTING_LIBERVIA_WIDGETS |
885 lib_wid.startGame("Tarot", waiting, referee, players) | 698 # is set to False or if the widget has not been found, the existing |
886 | 699 # widget that has been found otherwise.""" |
887 def _tarotGameGenericCb(self, event_name, room_jid_s, args): | 700 # lib_wid = None |
888 lib_wid = self.getRoomWidget(jid.JID(room_jid_s)) | 701 # tab = None |
889 if lib_wid: | 702 # if REUSE_EXISTING_LIBERVIA_WIDGETS: |
890 getattr(lib_wid.getGame("Tarot"), event_name)(*args) | 703 # lib_wid = self.getLiberviaWidget(class_, entity, new_tab is None) |
891 | 704 # if lib_wid is None: # create a new widget |
892 def _radioColStartedCb(self, waiting, room_jid_s, referee, players, queue_data): | 705 # lib_wid = class_.createPanel(self, *(entity.values())) # XXX: passing **entity bugs! |
893 lib_wid = self.getRoomWidget(jid.JID(room_jid_s)) | 706 # if new_tab is None: |
894 if lib_wid: | 707 # self.addWidget(lib_wid) |
895 lib_wid.startGame("RadioCol", waiting, referee, players, queue_data) | 708 # else: |
896 | 709 # tab = self.addTab(new_tab, lib_wid, False) |
897 def _radioColGenericCb(self, event_name, room_jid_s, args): | 710 # else: # reuse existing widget |
898 lib_wid = self.getRoomWidget(jid.JID(room_jid_s)) | 711 # tab = lib_wid.getWidgetsPanel(expect=False) |
899 if lib_wid: | 712 # if new_tab is None: |
900 getattr(lib_wid.getGame("RadioCol"), event_name)(*args) | 713 # if tab is not None: |
714 # tab.removeWidget(lib_wid) | |
715 # self.addWidget(lib_wid) | |
716 # if select: | |
717 # if new_tab is not None: | |
718 # self.tab_panel.selectTab(tab) | |
719 # # must be done after the widget is added, | |
720 # # for example to scroll to the bottom | |
721 # self.setSelected(lib_wid) | |
722 # lib_wid.refresh() | |
723 # return lib_wid | |
724 | |
725 # def getRoomWidget(self, target): | |
726 # """Get the MUC widget for the given target. | |
727 | |
728 # @param target (jid.JID): BARE jid of the MUC | |
729 # @return: panel.ChatPanel instance or None | |
730 # """ | |
731 # entity = {'item': target, 'type_': 'group'} | |
732 # 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... | |
733 # return self.getLiberviaWidget(panel.ChatPanel, entity, ignoreOtherTabs=False) | |
734 # return None | |
735 | |
736 # def getOrCreateRoomWidget(self, target): | |
737 # """Get the MUC widget for the given target, create it if necessary. | |
738 | |
739 # @param target (jid.JID): BARE jid of the MUC | |
740 # @return: panel.ChatPanel instance | |
741 # """ | |
742 # lib_wid = self.getRoomWidget(target) | |
743 # if lib_wid: | |
744 # return lib_wid | |
745 | |
746 # # XXX: target.node.startwith(...) raises an error "startswith is not a function" | |
747 # # This happens when node a is property defined in the JID class | |
748 # # FIXME: pyjamas doesn't handle the properties well | |
749 # node = target.node | |
750 | |
751 # # XXX: it's not really beautiful, but it works :) | |
752 # if node.startswith('sat_tarot_'): | |
753 # tab_name = "Tarot" | |
754 # elif node.startswith('sat_radiocol_'): | |
755 # tab_name = "Radio collective" | |
756 # else: | |
757 # tab_name = target.node | |
758 | |
759 # self.room_list.append(target) | |
760 # entity = {'item': target, 'type_': 'group'} | |
761 # return self.getOrCreateLiberviaWidget(panel.ChatPanel, entity, new_tab=tab_name) | |
762 | |
763 # def _newMessageCb(self, from_jid_s, msg, msg_type, to_jid_s, extra): | |
764 # from_jid = jid.JID(from_jid_s) | |
765 # to_jid = jid.JID(to_jid_s) | |
766 # for plugin in self.plugins.values(): | |
767 # if hasattr(plugin, 'messageReceivedTrigger'): | |
768 # if not plugin.messageReceivedTrigger(from_jid, msg, msg_type, to_jid, extra): | |
769 # return # plugin returned False to interrupt the process | |
770 # self.newMessageCb(from_jid, msg, msg_type, to_jid, extra) | |
771 | |
772 # def newMessageCb(self, from_jid, msg, msg_type, to_jid, extra): | |
773 # other = to_jid if from_jid.bare == self.whoami.bare else from_jid | |
774 # lib_wid = self.getLiberviaWidget(panel.ChatPanel, {'item': other}, ignoreOtherTabs=False) | |
775 # self.displayNotification(from_jid, msg) | |
776 # if msg_type == 'headline' and from_jid.full() == self._defaultDomain: | |
777 # try: | |
778 # assert extra['subject'] # subject is defined and not empty | |
779 # title = extra['subject'] | |
780 # except (KeyError, AssertionError): | |
781 # title = _('Announcement from %s') % from_jid.full() | |
782 # msg = strings.addURLToText(html_tools.XHTML2Text(msg)) | |
783 # dialog.InfoDialog(title, msg).show() | |
784 # return | |
785 # if lib_wid is not None: | |
786 # if msg_type == C.MESS_TYPE_INFO: | |
787 # lib_wid.printInfo(msg) | |
788 # else: | |
789 # lib_wid.printMessage(from_jid, msg, extra) | |
790 # if 'header_info' in extra: | |
791 # lib_wid.setHeaderInfo(extra['header_info']) | |
792 # else: | |
793 # # FIXME: "info" message and header info will be lost here | |
794 # if not self.contact_panel.isContactInRoster(other.bare): | |
795 # self.contact_panel.updateContact(other.bare, {}, [C.GROUP_NOT_IN_ROSTER]) | |
796 # # The message has not been shown, we must indicate it | |
797 # self.contact_panel.setContactMessageWaiting(other.bare, True) | |
798 | |
799 # def _presenceUpdateCb(self, entity, show, priority, statuses): | |
800 # entity_jid = jid.JID(entity) | |
801 # if self.whoami and self.whoami == entity_jid: # XXX: QnD way to get our presence/status | |
802 # assert(isinstance(self.status_panel, main_panel.PresenceStatusPanel)) | |
803 # self.status_panel.setPresence(show) # pylint: disable=E1103 | |
804 # if statuses: | |
805 # self.status_panel.setStatus(statuses.values()[0]) # pylint: disable=E1103 | |
806 # else: | |
807 # bare_jid = entity_jid.bareJID() | |
808 # 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... | |
809 # wid = self.getRoomWidget(bare_jid) | |
810 # else: | |
811 # wid = self.contact_panel | |
812 # if show == 'unavailable': # XXX: save some resources as for now we only need 'unavailable' | |
813 # for plugin in self.plugins.values(): | |
814 # if hasattr(plugin, 'presenceReceivedTrigger'): | |
815 # plugin.presenceReceivedTrigger(entity_jid, show, priority, statuses) | |
816 # if wid: | |
817 # wid.setConnected(entity_jid.bare, entity_jid.resource, show, priority, statuses) | |
818 | |
819 # def _roomJoinedCb(self, room_jid_s, room_nicks, user_nick): | |
820 # chat_panel = self.getOrCreateRoomWidget(jid.JID(room_jid_s)) | |
821 # chat_panel.setUserNick(user_nick) | |
822 # chat_panel.setPresents(room_nicks) | |
823 # chat_panel.refresh() | |
824 | |
825 # def _roomLeftCb(self, room_jid_s, room_nicks, user_nick): | |
826 # try: | |
827 # del self.room_list[room_jid_s] | |
828 # except KeyError: | |
829 # try: # as JID is a string-based class, we don't know what will please Pyjamas... | |
830 # del self.room_list[jid.JID(room_jid_s)] | |
831 # except KeyError: | |
832 # pass | |
833 | |
834 # def _roomUserJoinedCb(self, room_jid_s, user_nick, user_data): | |
835 # lib_wid = self.getOrCreateRoomWidget(jid.JID(room_jid_s)) | |
836 # if lib_wid: | |
837 # lib_wid.userJoined(user_nick, user_data) | |
838 | |
839 # def _roomUserLeftCb(self, room_jid_s, user_nick, user_data): | |
840 # lib_wid = self.getRoomWidget(jid.JID(room_jid_s)) | |
841 # if lib_wid: | |
842 # lib_wid.userLeft(user_nick, user_data) | |
843 | |
844 # def _roomUserChangedNickCb(self, room_jid_s, old_nick, new_nick): | |
845 # """Called when an user joined a MUC room""" | |
846 # lib_wid = self.getRoomWidget(jid.JID(room_jid_s)) | |
847 # if lib_wid: | |
848 # lib_wid.changeUserNick(old_nick, new_nick) | |
849 | |
850 # def _tarotGameStartedCb(self, waiting, room_jid_s, referee, players): | |
851 # lib_wid = self.getRoomWidget(jid.JID(room_jid_s)) | |
852 # if lib_wid: | |
853 # lib_wid.startGame("Tarot", waiting, referee, players) | |
854 | |
855 # def _tarotGameGenericCb(self, event_name, room_jid_s, args): | |
856 # lib_wid = self.getRoomWidget(jid.JID(room_jid_s)) | |
857 # if lib_wid: | |
858 # getattr(lib_wid.getGame("Tarot"), event_name)(*args) | |
859 | |
860 # def _radioColStartedCb(self, waiting, room_jid_s, referee, players, queue_data): | |
861 # lib_wid = self.getRoomWidget(jid.JID(room_jid_s)) | |
862 # if lib_wid: | |
863 # lib_wid.startGame("RadioCol", waiting, referee, players, queue_data) | |
864 | |
865 # def _radioColGenericCb(self, event_name, room_jid_s, args): | |
866 # lib_wid = self.getRoomWidget(jid.JID(room_jid_s)) | |
867 # if lib_wid: | |
868 # getattr(lib_wid.getGame("RadioCol"), event_name)(*args) | |
901 | 869 |
902 def _getPresenceStatusesCb(self, presence_data): | 870 def _getPresenceStatusesCb(self, presence_data): |
903 for entity in presence_data: | 871 for entity in presence_data: |
904 for resource in presence_data[entity]: | 872 for resource in presence_data[entity]: |
905 args = presence_data[entity][resource] | 873 args = presence_data[entity][resource] |
927 #The user want to subscribe to our presence | 895 #The user want to subscribe to our presence |
928 _dialog = None | 896 _dialog = None |
929 msg = HTML('The contact <b>%s</b> want to add you in his/her contact list, do you accept ?' % html_tools.html_sanitize(entity)) | 897 msg = HTML('The contact <b>%s</b> want to add you in his/her contact list, do you accept ?' % html_tools.html_sanitize(entity)) |
930 | 898 |
931 def ok_cb(ignore): | 899 def ok_cb(ignore): |
932 self.bridge.call('subscription', None, "subscribed", entity, '', _dialog.getSelectedGroups()) | 900 self.bridge.call('subscription', None, "subscribed", entity) |
901 self.bridge.updateContact(entity, '', _dialog.getSelectedGroups()) | |
933 | 902 |
934 def cancel_cb(ignore): | 903 def cancel_cb(ignore): |
935 self.bridge.call('subscription', None, "unsubscribed", entity, '', '') | 904 self.bridge.call('subscription', None, "unsubscribed", entity, '', '') |
936 | 905 |
937 _dialog = dialog.GroupSelector([msg], self.contact_panel.getGroups(), [], "Add", ok_cb, cancel_cb) | 906 _dialog = dialog.GroupSelector([msg], self.contact_panel.getGroups(), [], "Add", ok_cb, cancel_cb) |
943 | 912 |
944 def _newContactCb(self, contact_jid, attributes, groups): | 913 def _newContactCb(self, contact_jid, attributes, groups): |
945 self.contact_panel.updateContact(contact_jid, attributes, groups) | 914 self.contact_panel.updateContact(contact_jid, attributes, groups) |
946 | 915 |
947 def _entityDataUpdatedCb(self, entity_jid_s, key, value): | 916 def _entityDataUpdatedCb(self, entity_jid_s, key, value): |
917 raise Exception # FIXME should not be here | |
948 if key == "avatar": | 918 if key == "avatar": |
949 avatar = '/' + C.AVATARS_DIR + value | 919 avatar = '/' + C.AVATARS_DIR + value |
950 self.avatars_cache[entity_jid_s] = avatar | 920 self.avatars_cache[entity_jid_s] = avatar |
951 self.contact_panel.updateAvatar(entity_jid_s, avatar) | 921 self.contact_panel.updateAvatar(entity_jid_s, avatar) |
952 | 922 |
953 for lib_wid in self.libervia_widgets: | 923 for lib_wid in self.libervia_widgets: |
954 if isinstance(lib_wid, panels.MicroblogPanel): | 924 if isinstance(lib_wid, blog.MicroblogPanel): |
955 if lib_wid.isJidAccepted(entity_jid_s) or (self.whoami and entity_jid_s == self.whoami.bare): | 925 if lib_wid.isJidAccepted(entity_jid_s) or (self.whoami and entity_jid_s == self.whoami.bare): |
956 lib_wid.updateValue('avatar', entity_jid_s, avatar) | 926 lib_wid.updateValue('avatar', entity_jid_s, avatar) |
957 | 927 |
958 def _chatStateReceivedCb(self, from_jid_s, state): | 928 # def _chatStateReceivedCb(self, from_jid_s, state): |
959 """Callback when a new chat state is received. | 929 # """Callback when a new chat state is received. |
960 @param from_jid_s: JID of the contact who sent his state, or '@ALL@' | 930 # @param from_jid_s: JID of the contact who sent his state, or '@ALL@' |
961 @param state: new state (string) | 931 # @param state (unicode): new state |
962 """ | 932 # """ |
963 if from_jid_s == '@ALL@': | 933 # if from_jid_s == '@ALL@': |
964 for lib_wid in self.libervia_widgets: | 934 # for lib_wid in self.libervia_widgets: |
965 if isinstance(lib_wid, panels.ChatPanel): | 935 # if isinstance(lib_wid, panel.ChatPanel): |
966 lib_wid.setState(state, nick=C.ALL_OCCUPANTS) | 936 # lib_wid.setState(state, nick=C.ALL_OCCUPANTS) |
967 return | 937 # return |
968 from_jid = jid.JID(from_jid_s) | 938 # from_jid = jid.JID(from_jid_s) |
969 lib_wid = self.getLiberviaWidget(panels.ChatPanel, {'item': from_jid}, ignoreOtherTabs=False) | 939 # lib_wid = self.getLiberviaWidget(panel.ChatPanel, {'item': from_jid}, ignoreOtherTabs=False) |
970 lib_wid.setState(state, nick=from_jid.resource) | 940 # lib_wid.setState(state, nick=from_jid.resource) |
971 | 941 |
972 def _askConfirmation(self, confirmation_id, confirmation_type, data): | 942 def askConfirmationHandler(self, confirmation_id, confirmation_type, data): |
973 answer_data = {} | 943 answer_data = {} |
974 | 944 |
975 def confirm_cb(result): | 945 def confirm_cb(result): |
976 self.bridge.call('confirmationAnswer', None, confirmation_id, result, answer_data) | 946 self.bridge.call('confirmationAnswer', None, confirmation_id, result, answer_data) |
977 | 947 |
994 break | 964 break |
995 | 965 |
996 def getCachedParam(self, category, name): | 966 def getCachedParam(self, category, name): |
997 """Return a parameter cached value (e.g for refreshing the UI) | 967 """Return a parameter cached value (e.g for refreshing the UI) |
998 | 968 |
999 @param category (str): the parameter category | 969 @param category (unicode): the parameter category |
1000 @pram name (str): the parameter name | 970 @pram name (unicode): the parameter name |
1001 """ | 971 """ |
1002 return self.cached_params[(category, name)] if (category, name) in self.cached_params else None | 972 return self.cached_params[(category, name)] if (category, name) in self.cached_params else None |
1003 | 973 |
1004 def sendError(self, errorData): | 974 def sendError(self, errorData): |
1005 dialog.InfoDialog("Error while sending message", | 975 dialog.InfoDialog("Error while sending message", |
1006 "Your message can't be sent", Width="400px").center() | 976 "Your message can't be sent", Width="400px").center() |
1007 log.error("sendError: %s" % str(errorData)) | 977 log.error("sendError: %s" % unicode(errorData)) |
1008 | 978 |
1009 def send(self, targets, text, extra={}): | 979 # FIXME: this method is fat too complicated and depend of widget type |
1010 """Send a message to any target type. | 980 # must be refactored and moved to each widget instead |
1011 @param targets: list of tuples (type, entities, addr) with: | 981 # def send(self, targets, text, extra={}): |
1012 - type in ("PUBLIC", "GROUP", "COMMENT", "STATUS" , "groupchat" , "chat") | 982 # """Send a message to any target type. |
1013 - entities could be a JID, a list groups, a node hash... depending the target | 983 # @param targets: list of tuples (type, entities, addr) with: |
1014 - addr in ("To", "Cc", "Bcc") - ignore case | 984 # - type in ("PUBLIC", "GROUP", "COMMENT", "STATUS" , "groupchat" , "chat") |
1015 @param text: the message content | 985 # - entities could be a JID, a list groups, a node hash... depending the target |
1016 @param extra: options | 986 # - addr in ("To", "Cc", "Bcc") - ignore case |
1017 """ | 987 # @param text: the message content |
1018 # FIXME: too many magic strings, we should use constants instead | 988 # @param extra: options |
1019 addresses = [] | 989 # """ |
1020 for target in targets: | 990 # # FIXME: too many magic strings, we should use constants instead |
1021 type_, entities, addr = target[0], target[1], 'to' if len(target) < 3 else target[2].lower() | 991 # addresses = [] |
1022 if type_ in ("PUBLIC", "GROUP"): | 992 # for target in targets: |
1023 self.bridge.call("sendMblog", None, type_, entities if type_ == "GROUP" else None, text, extra) | 993 # type_, entities, addr = target[0], target[1], 'to' if len(target) < 3 else target[2].lower() |
1024 elif type_ == "COMMENT": | 994 # if type_ in ("PUBLIC", "GROUP"): |
1025 self.bridge.call("sendMblogComment", None, entities, text, extra) | 995 # self.bridge.call("sendMblog", None, type_, entities if type_ == "GROUP" else None, text, extra) |
1026 elif type_ == "STATUS": | 996 # elif type_ == "COMMENT": |
1027 assert(isinstance(self.status_panel, panels.PresenceStatusPanel)) | 997 # self.bridge.call("sendMblogComment", None, entities, text, extra) |
1028 self.bridge.call('setStatus', None, self.status_panel.presence, text) # pylint: disable=E1103 | 998 # elif type_ == "STATUS": |
1029 elif type_ in ("groupchat", "chat"): | 999 # assert(isinstance(self.status_panel, main_panel.PresenceStatusPanel)) |
1030 addresses.append((addr, entities)) | 1000 # self.bridge.call('setStatus', None, self.status_panel.presence, text) # pylint: disable=E1103 |
1031 else: | 1001 # elif type_ in ("groupchat", "chat"): |
1032 log.error("Unknown target type") | 1002 # addresses.append((addr, entities)) |
1033 if addresses: | 1003 # else: |
1034 if len(addresses) == 1 and addresses[0][0] == 'to': | 1004 # log.error("Unknown target type") |
1035 to_jid_s = addresses[0][1] | 1005 # if addresses: |
1036 for plugin in self.plugins.values(): | 1006 # if len(addresses) == 1 and addresses[0][0] == 'to': |
1037 if hasattr(plugin, 'sendMessageTrigger'): | 1007 # to_jid_s = addresses[0][1] |
1038 if not plugin.sendMessageTrigger(jid.JID(to_jid_s), text, type_, extra): | 1008 # for plugin in self.plugins.values(): |
1039 return # plugin returned False to interrupt the process | 1009 # if hasattr(plugin, 'sendMessageTrigger'): |
1040 self.bridge.call('sendMessage', (None, self.sendError), to_jid_s, text, '', type_, extra) | 1010 # if not plugin.sendMessageTrigger(jid.JID(to_jid_s), text, type_, extra): |
1041 else: | 1011 # return # plugin returned False to interrupt the process |
1042 extra.update({'address': '\n'.join([('%s:%s' % entry) for entry in addresses])}) | 1012 # self.bridge.call('sendMessage', (None, self.sendError), to_jid_s, text, '', type_, extra) |
1043 self.bridge.call('sendMessage', (None, self.sendError), self.whoami.domain, text, '', type_, extra) | 1013 # else: |
1014 # extra.update({'address': '\n'.join([('%s:%s' % entry) for entry in addresses])}) | |
1015 # self.bridge.call('sendMessage', (None, self.sendError), self.whoami.domain, text, '', type_, extra) | |
1044 | 1016 |
1045 def showWarning(self, type_=None, msg=None): | 1017 def showWarning(self, type_=None, msg=None): |
1046 """Display a popup information message, e.g. to notify the recipient of a message being composed. | 1018 """Display a popup information message, e.g. to notify the recipient of a message being composed. |
1047 If type_ is None, a popup being currently displayed will be hidden. | 1019 If type_ is None, a popup being currently displayed will be hidden. |
1048 @type_: a type determining the CSS style to be applied (see WarningPopup.showWarning) | 1020 @type_: a type determining the CSS style to be applied (see WarningPopup.showWarning) |
1049 @msg: message to be displayed | 1021 @msg: message to be displayed |
1050 """ | 1022 """ |
1051 if not hasattr(self, "warning_popup"): | 1023 if not hasattr(self, "warning_popup"): |
1052 self.warning_popup = panels.WarningPopup() | 1024 self.warning_popup = main_panel.WarningPopup() |
1053 self.warning_popup.showWarning(type_, msg) | 1025 self.warning_popup.showWarning(type_, msg) |
1026 | |
1027 def showDialog(self, message, title="", type_="info", answer_cb=None, answer_data=None): | |
1028 if type_ == 'info': | |
1029 popup = dialog.InfoDialog(unicode(title), unicode(message), callback=answer_cb) | |
1030 elif type_ == 'error': | |
1031 popup = dialog.InfoDialog(unicode(title), unicode(message), callback=answer_cb) | |
1032 elif type_ == 'yes/no': | |
1033 popup = dialog.ConfirmDialog(lambda answer: answer_cb(answer, answer_data), | |
1034 text=unicode(message), title=unicode(title)) | |
1035 popup.cancel_button.setText(_("No")) | |
1036 else: | |
1037 popup = dialog.InfoDialog(unicode(title), unicode(message), callback=answer_cb) | |
1038 log.error(_('unmanaged dialog type: %s'), type_) | |
1039 popup.show() | |
1054 | 1040 |
1055 | 1041 |
1056 if __name__ == '__main__': | 1042 if __name__ == '__main__': |
1057 app = SatWebFrontend() | 1043 app = SatWebFrontend() |
1058 app.onModuleLoad() | 1044 app.onModuleLoad() |
1059 pyjd.run() | 1045 host_listener.callListeners(app) |