changeset 2862:b2e898384c25

quick_frontend (app): progress callbacks handling: in addition to listeners, a frontend can now register progression callback and errback which are called when the given progressing action is finished. Those callbacks can be registered using registerProgressCbs or specified in actionManager.
author Goffi <goffi@goffi.org>
date Wed, 20 Mar 2019 09:08:47 +0100
parents e9e33e05d143
children a97a5c73594d
files sat_frontends/quick_frontend/quick_app.py
diffstat 1 files changed, 52 insertions(+), 6 deletions(-) [+]
line wrap: on
line diff
--- a/sat_frontends/quick_frontend/quick_app.py	Wed Mar 20 09:08:47 2019 +0100
+++ b/sat_frontends/quick_frontend/quick_app.py	Wed Mar 20 09:08:47 2019 +0100
@@ -313,7 +313,7 @@
         # widget currently selected (must be filled by frontend)
         self.selected_widget = None
 
-        # listeners
+        # listeners are callable watching events
         self._listeners = {}  # key: listener type ("avatar", "selected", etc),
                               # value: list of callbacks
 
@@ -328,12 +328,20 @@
         if connect_bridge:
             self.connectBridge()
 
+        # frontend notifications
         self._notif_id = 0
         self._notifications = OrderedDict()
+        # watched progresses and associated callbacks
+        self._progress_ids = {}
+        # available features
+        # FIXME: features are profile specific, to be checked
         self.features = None
-        self.ns_map = {}  # map of short name to namespaces
+        #: map of short name to namespaces
+        self.ns_map = {}
+        #: available encryptions
         self.encryption_plugins = []
-        self._sync = True  # state of synchronisation with backend
+        # state of synchronisation with backend
+        self._sync = True
 
     def connectBridge(self):
         self.bridge.bridgeConnect(callback=self._bridgeCb, errback=self._bridgeEb)
@@ -436,7 +444,7 @@
 
     @property
     def sync(self):
-        """Get synchronization flag
+        """Synchronization flag
 
         True if this frontend is synchronised with backend
         """
@@ -1042,15 +1050,44 @@
             else:
                 log.warning("Unmanaged PubSub event type {}".format(event_type))
 
+    def registerProgressCbs(self, progress_id, callback, errback):
+        """Register progression callbacks
+
+        @param progress_id(unicode): id of the progression to check
+        @param callback(callable, None): method to call when progressing action
+            successfuly finished.
+            None to ignore
+        @param errback(callable, None): method to call when progressions action failed
+            None to ignore
+        """
+        callbacks = self._progress_ids.setdefault(progress_id, [])
+        callbacks.append((callback, errback))
+
     def progressStartedHandler(self, pid, metadata, profile):
         log.info(u"Progress {} started".format(pid))
 
     def progressFinishedHandler(self, pid, metadata, profile):
         log.info(u"Progress {} finished".format(pid))
+        try:
+            callbacks = self._progress_ids.pop(pid)
+        except KeyError:
+            pass
+        else:
+            for callback, __ in callbacks:
+                if callback is not None:
+                    callback(metadata, profile=profile)
         self.callListeners("progressFinished", pid, metadata, profile=profile)
 
     def progressErrorHandler(self, pid, err_msg, profile):
         log.warning(u"Progress {pid} error: {err_msg}".format(pid=pid, err_msg=err_msg))
+        try:
+            callbacks = self._progress_ids.pop(pid)
+        except KeyError:
+            pass
+        else:
+            for __, errback in callbacks:
+                if errback is not None:
+                    errback(err_msg, profile=profile)
         self.callListeners("progressError", pid, err_msg, profile=profile)
 
     def _subscribe_cb(self, answer, data):
@@ -1166,7 +1203,7 @@
                 self.getAvatar(entity, ignore_cache=True, profile=profile)
 
     def actionManager(self, action_data, callback=None, ui_show_cb=None, user_action=True,
-                      profile=C.PROF_KEY_NONE):
+                      progress_cb=None, progress_eb=None, profile=C.PROF_KEY_NONE):
         """Handle backend action
 
         @param action_data(dict): action dict as sent by launchAction or returned by an
@@ -1174,7 +1211,14 @@
         @param callback(None, callback): if not None, callback to use on XMLUI answer
         @param ui_show_cb(None, callback): if not None, method to call to show the XMLUI
         @param user_action(bool): if True, the action is a result of a user interaction
-            else the action come from backend direclty (i.e. actionNew)
+            else the action come from backend direclty (i.e. actionNew).
+            This is useful to know if the frontend can display a popup immediately (if
+            True) or if it should add it to a queue that the user can activate later.
+        @param progress_cb(None, callable): method to call when progression is finished.
+            Only make sense if a progress is expected in this action
+        @param progress_eb(None, callable): method to call when something went wrong
+            during progression.
+            Only make sense if a progress is expected in this action
         """
         try:
             xmlui = action_data.pop("xmlui")
@@ -1198,6 +1242,8 @@
         except KeyError:
             pass
         else:
+            if progress_cb or progress_eb:
+                self.registerProgressCbs(progress_id, progress_cb, progress_eb)
             self.progressIdHandler(progress_id, profile)
 
         # we ignore metadata