# HG changeset patch # User Goffi # Date 1424806197 -3600 # Node ID b26dd78de495e441cbb71be6a1396ae9075ca95f # Parent 1679ac59f701fd02c7e529a4d343f75373fab817 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. diff -r 1679ac59f701 -r b26dd78de495 frontends/src/quick_frontend/quick_app.py --- a/frontends/src/quick_frontend/quick_app.py Tue Feb 24 18:21:03 2015 +0100 +++ b/frontends/src/quick_frontend/quick_app.py Tue Feb 24 20:29:57 2015 +0100 @@ -204,6 +204,8 @@ """ ProfileManager.host = self self.profiles = ProfilesManager() + self.ready_profiles = set() # profiles which are connected and ready + self.signals_cache = {} # used to keep signal received between start of plug_profile and when the profile is actualy ready self.contact_lists = {} self.widgets = QuickWidgetsManager(self) if check_options is not None: @@ -281,18 +283,18 @@ """widgets currently visible (must be implemented by frontend)""" raise NotImplementedError - def registerSignal(self, functionName, handler=None, iface="core", with_profile=True): + def registerSignal(self, function_name, handler=None, iface="core", with_profile=True): """Register a handler for a signal - @param functionName (str): name of the signal to handle - @param handler (instancemethod): method to call when the signal arrive, None for calling an automatically named handler (functionName + 'Handler') + @param function_name (str): name of the signal to handle + @param handler (instancemethod): method to call when the signal arrive, None for calling an automatically named handler (function_name + 'Handler') @param iface (str): interface of the bridge to use ('core' or 'plugin') @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 """ if handler is None: - handler = getattr(self, "{}{}".format(functionName, 'Handler')) + handler = getattr(self, "{}{}".format(function_name, 'Handler')) if not with_profile: - self.bridge.register(functionName, handler, iface) + self.bridge.register(function_name, handler, iface) return def signalReceived(*args, **kwargs): @@ -301,10 +303,14 @@ if not args: raise exceptions.ProfileNotSetError profile = args[-1] - if profile is not None and not self.check_profile(profile): - return # we ignore signal for profiles we don't manage + if profile is not None: + if not self.check_profile(profile): + if profile in self.profiles: + # profile is not ready but is in self.profiles, that's mean that it's being connecting and we need to cache the signal + self.signals_cache.setdefault(profile, []).append((function_name, handler, args, kwargs)) + return # we ignore signal for profiles we don't manage handler(*args, **kwargs) - self.bridge.register(functionName, signalReceived, iface) + self.bridge.register(function_name, signalReceived, iface) def addListener(self, type_, callback, profiles_filter=None): """Add a listener for an event @@ -354,8 +360,8 @@ listener(*args, **kwargs) def check_profile(self, profile): - """Tell if the profile is currently followed by the application""" - return profile in self.profiles + """Tell if the profile is currently followed by the application, and ready""" + return profile in self.ready_profiles def postInit(self, profile_manager): """Must be called after initialization is done, do all automatic task (auto plug profile) @@ -368,9 +374,17 @@ def profilePlugged(self, profile): """Method called when the profile is fully plugged, to launch frontend specific workflow + /!\ if you override the method and don't call the parent, be sure to add the profile to ready_profiles ! + if you don't, all signals will stay in cache + @param profile(unicode): %(doc_profile)s """ - pass + self.ready_profiles.add(profile) + + # profile is ready, we can call send signals that where is cache + cached_signals = self.signals_cache.pop(profile, []) + for function_name, handler, args, kwargs in cached_signals: + log.debug(u"Calling cached signal [%s] with args %s and kwargs %s" % (function_name, args, kwargs)) def asyncConnect(self, profile, callback=None, errback=None): if not callback: