Mercurial > libervia-backend
comparison frontends/src/quick_frontend/quick_app.py @ 1345:b26dd78de495 frontends_multi_profiles
quick frontends: signal cache: if a signal arrives between the beginning of profile plugging, and the when the profile is actually ready, it is cached and replayed when the profile is ready.
author | Goffi <goffi@goffi.org> |
---|---|
date | Tue, 24 Feb 2015 20:29:57 +0100 |
parents | e31a07a5614d |
children | ba41a81d14c2 |
comparison
equal
deleted
inserted
replaced
1344:1679ac59f701 | 1345:b26dd78de495 |
---|---|
202 @param create_bridge: method to use to create the Bridge | 202 @param create_bridge: method to use to create the Bridge |
203 @param check_options: method to call to check options (usually command line arguments) | 203 @param check_options: method to call to check options (usually command line arguments) |
204 """ | 204 """ |
205 ProfileManager.host = self | 205 ProfileManager.host = self |
206 self.profiles = ProfilesManager() | 206 self.profiles = ProfilesManager() |
207 self.ready_profiles = set() # profiles which are connected and ready | |
208 self.signals_cache = {} # used to keep signal received between start of plug_profile and when the profile is actualy ready | |
207 self.contact_lists = {} | 209 self.contact_lists = {} |
208 self.widgets = QuickWidgetsManager(self) | 210 self.widgets = QuickWidgetsManager(self) |
209 if check_options is not None: | 211 if check_options is not None: |
210 self.options = check_options() | 212 self.options = check_options() |
211 else: | 213 else: |
279 @property | 281 @property |
280 def visible_widgets(self): | 282 def visible_widgets(self): |
281 """widgets currently visible (must be implemented by frontend)""" | 283 """widgets currently visible (must be implemented by frontend)""" |
282 raise NotImplementedError | 284 raise NotImplementedError |
283 | 285 |
284 def registerSignal(self, functionName, handler=None, iface="core", with_profile=True): | 286 def registerSignal(self, function_name, handler=None, iface="core", with_profile=True): |
285 """Register a handler for a signal | 287 """Register a handler for a signal |
286 | 288 |
287 @param functionName (str): name of the signal to handle | 289 @param function_name (str): name of the signal to handle |
288 @param handler (instancemethod): method to call when the signal arrive, None for calling an automatically named handler (functionName + 'Handler') | 290 @param handler (instancemethod): method to call when the signal arrive, None for calling an automatically named handler (function_name + 'Handler') |
289 @param iface (str): interface of the bridge to use ('core' or 'plugin') | 291 @param iface (str): interface of the bridge to use ('core' or 'plugin') |
290 @param with_profile (boolean): True if the signal concerns a specific profile, in that case the profile name has to be passed by the caller | 292 @param with_profile (boolean): True if the signal concerns a specific profile, in that case the profile name has to be passed by the caller |
291 """ | 293 """ |
292 if handler is None: | 294 if handler is None: |
293 handler = getattr(self, "{}{}".format(functionName, 'Handler')) | 295 handler = getattr(self, "{}{}".format(function_name, 'Handler')) |
294 if not with_profile: | 296 if not with_profile: |
295 self.bridge.register(functionName, handler, iface) | 297 self.bridge.register(function_name, handler, iface) |
296 return | 298 return |
297 | 299 |
298 def signalReceived(*args, **kwargs): | 300 def signalReceived(*args, **kwargs): |
299 profile = kwargs.get('profile') | 301 profile = kwargs.get('profile') |
300 if profile is None: | 302 if profile is None: |
301 if not args: | 303 if not args: |
302 raise exceptions.ProfileNotSetError | 304 raise exceptions.ProfileNotSetError |
303 profile = args[-1] | 305 profile = args[-1] |
304 if profile is not None and not self.check_profile(profile): | 306 if profile is not None: |
305 return # we ignore signal for profiles we don't manage | 307 if not self.check_profile(profile): |
308 if profile in self.profiles: | |
309 # profile is not ready but is in self.profiles, that's mean that it's being connecting and we need to cache the signal | |
310 self.signals_cache.setdefault(profile, []).append((function_name, handler, args, kwargs)) | |
311 return # we ignore signal for profiles we don't manage | |
306 handler(*args, **kwargs) | 312 handler(*args, **kwargs) |
307 self.bridge.register(functionName, signalReceived, iface) | 313 self.bridge.register(function_name, signalReceived, iface) |
308 | 314 |
309 def addListener(self, type_, callback, profiles_filter=None): | 315 def addListener(self, type_, callback, profiles_filter=None): |
310 """Add a listener for an event | 316 """Add a listener for an event |
311 | 317 |
312 /!\ don't forget to remove listener when not used anymore (e.g. if you delete a widget) | 318 /!\ don't forget to remove listener when not used anymore (e.g. if you delete a widget) |
352 for listener, profiles_filter in listeners.iteritems(): | 358 for listener, profiles_filter in listeners.iteritems(): |
353 if profile is None or not profiles_filter or profile in profiles_filter: | 359 if profile is None or not profiles_filter or profile in profiles_filter: |
354 listener(*args, **kwargs) | 360 listener(*args, **kwargs) |
355 | 361 |
356 def check_profile(self, profile): | 362 def check_profile(self, profile): |
357 """Tell if the profile is currently followed by the application""" | 363 """Tell if the profile is currently followed by the application, and ready""" |
358 return profile in self.profiles | 364 return profile in self.ready_profiles |
359 | 365 |
360 def postInit(self, profile_manager): | 366 def postInit(self, profile_manager): |
361 """Must be called after initialization is done, do all automatic task (auto plug profile) | 367 """Must be called after initialization is done, do all automatic task (auto plug profile) |
362 | 368 |
363 @param profile_manager: instance of a subclass of Quick_frontend.QuickProfileManager | 369 @param profile_manager: instance of a subclass of Quick_frontend.QuickProfileManager |
366 profile_manager.autoconnect([self.options.profile]) | 372 profile_manager.autoconnect([self.options.profile]) |
367 | 373 |
368 def profilePlugged(self, profile): | 374 def profilePlugged(self, profile): |
369 """Method called when the profile is fully plugged, to launch frontend specific workflow | 375 """Method called when the profile is fully plugged, to launch frontend specific workflow |
370 | 376 |
377 /!\ if you override the method and don't call the parent, be sure to add the profile to ready_profiles ! | |
378 if you don't, all signals will stay in cache | |
379 | |
371 @param profile(unicode): %(doc_profile)s | 380 @param profile(unicode): %(doc_profile)s |
372 """ | 381 """ |
373 pass | 382 self.ready_profiles.add(profile) |
383 | |
384 # profile is ready, we can call send signals that where is cache | |
385 cached_signals = self.signals_cache.pop(profile, []) | |
386 for function_name, handler, args, kwargs in cached_signals: | |
387 log.debug(u"Calling cached signal [%s] with args %s and kwargs %s" % (function_name, args, kwargs)) | |
374 | 388 |
375 def asyncConnect(self, profile, callback=None, errback=None): | 389 def asyncConnect(self, profile, callback=None, errback=None): |
376 if not callback: | 390 if not callback: |
377 callback = lambda dummy: None | 391 callback = lambda dummy: None |
378 if not errback: | 392 if not errback: |