changeset 1301:afc57b34c0a3 frontends_multi_profiles

Quick Frontend (quick_widgets): added on_existing_widget in getOrCreateWidget (see docstring for more infos) + use of constants
author Goffi <goffi@goffi.org>
date Fri, 06 Feb 2015 19:01:06 +0100
parents ba73798317a7
children 447d28b1b4ec
files frontends/src/constants.py frontends/src/quick_frontend/quick_widgets.py
diffstat 2 files changed, 60 insertions(+), 11 deletions(-) [+]
line wrap: on
line diff
--- a/frontends/src/constants.py	Fri Feb 06 18:54:44 2015 +0100
+++ b/frontends/src/constants.py	Fri Feb 06 19:01:06 2015 +0100
@@ -62,6 +62,14 @@
     # Roster
     GROUP_NOT_IN_ROSTER = D_('Not in roster')
 
-    #Chats
+    # Chats
     CHAT_ONE2ONE = 'one2one'
     CHAT_GROUP = 'group'
+
+    # Widgets management
+    # FIXME: should be in quick_frontend.constant, but Libervia doesn't inherit from it
+    WIDGET_NEW = 'NEW'
+    WIDGET_KEEP = 'KEEP'
+    WIDGET_RAISE = 'RAISE'
+    WIDGET_RECREATE = 'RECREATE'
+
--- a/frontends/src/quick_frontend/quick_widgets.py	Fri Feb 06 18:54:44 2015 +0100
+++ b/frontends/src/quick_frontend/quick_widgets.py	Fri Feb 06 19:01:06 2015 +0100
@@ -21,6 +21,7 @@
 log = getLogger(__name__)
 from sat.core import exceptions
 
+from sat_frontends.quick_frontend.constants import Const as C
 
 classes_map = {}
 
@@ -40,6 +41,8 @@
         Can be None if it's the base_cls itself which register
     """
     classes_map[base_cls] = child_cls
+class WidgetAlreadyExistsError(Exception):
+    pass
 
 
 class QuickWidgetsManager(object):
@@ -95,15 +98,19 @@
             if 'profile' key is present, it will be popped and put in 'profiles'
             if there is neither 'profile' nor 'profiles', None will be used for 'profiles'
             if 'on_new_widget' is present it can have the following values:
-                'NEW_WIDGET' [default]: self.host.newWidget will be called on widget creation
+                C.WIDGET_NEW [default]: self.host.newWidget will be called on widget creation
                 [callable]: this method will be called instead of self.host.newWidget
                 None: do nothing
+            if 'on_existing_widget' is present it can have the following values:
+                C.WIDGET_KEEP  [default]: return the existing widget
+                C.WIDGET_RAISE: raise WidgetAlreadyExistsError
+                C.WIDGET_RECREATE: create a new widget *WITH A NEW HASH*
             if 'force_hash' is present, the hash given in value will be used instead of the one returned by class_.getWidgetHash
         @return: a class_ instance, either new or already existing
         """
         cls = self.getRealClass(class_)
 
-        # arguments management
+        ## arguments management ##
         _args = [self.host, target] + list(args) or [] # FIXME: check if it's really necessary to use optional args
         _kwargs = kwargs or {}
         if 'profiles' in _kwargs and 'profile' in _kwargs:
@@ -114,7 +121,19 @@
             if not 'profiles' in _kwargs:
                 _kwargs['profiles'] = None
 
-        # we get the hash
+        #on_new_widget tell what to do for the new widget creation
+        try:
+            on_new_widget = _kwargs.pop('on_new_widget')
+        except KeyError:
+            on_new_widget = C.WIDGET_NEW
+
+        #on_existing_widget tell what to do when the widget already exists
+        try:
+            on_existing_widget = _kwargs.pop('on_existing_widget')
+        except KeyError:
+            on_existing_widget = C.WIDGET_KEEP
+
+        ## we get the hash ##
         try:
             hash_ = _kwargs.pop('force_hash')
         except KeyError:
@@ -133,23 +152,45 @@
 
         if widget is None:
             # we need to create a new widget
-            try:
-                #on_new_widget tell what to do for the new widget creation
-                on_new_widget = _kwargs.pop('on_new_widget')
-            except KeyError:
-                on_new_widget = 'NEW_WIDGET'
-
             log.debug(u"Creating new widget for target {} {}".format(target, cls))
             widget = cls(*_args, **_kwargs)
             widgets_map[hash_] = widget
 
-            if on_new_widget == 'NEW_WIDGET':
+            if on_new_widget == C.WIDGET_NEW:
                 self.host.newWidget(widget)
             elif callable(on_new_widget):
                 on_new_widget(widget)
             else:
                 assert on_new_widget is None
+        else:
+            # the widget already exists
+            if on_existing_widget == C.WIDGET_RAISE:
+                raise WidgetAlreadyExistsError(hash_)
+            elif on_existing_widget == C.WIDGET_RECREATE:
+                # we use getOrCreateWidget to recreate the new widget
+                # /!\ we use args and kwargs and not _args and _kwargs because we need the original args
+                #     we need to get rid of kwargs special options
+                new_kwargs = kwargs.copy()
+                try:
+                    new_kwargs.pop('force_hash')  # FIXME: we use pop instead of del here because pyjamas doesn't raise error on del
+                except KeyError:
+                    pass
+                else:
+                    raise ValueError("force_hash option can't be used with on_existing_widget=RECREATE")
 
+                # XXX: keep up-to-date if new special kwargs are added (i.e.: delete these keys here)
+                new_kwargs['on_new_widget'] = None
+                new_kwargs['on_existing_widget'] = C.WIDGET_RAISE
+                hash_idx = 1
+                while True:
+                    new_kwargs['force_hash'] = hash_ + "_new_instance_{}".format(hash_idx)
+                    try:
+                        widget = self.getOrCreateWidget(class_, target, *args, **new_kwargs)
+                    except WidgetAlreadyExistsError:
+                        hash_idx += 1
+                    else:
+                        log.debug(u"Widget already exists, a new one has been recreated with hash {}".format(new_kwargs['force_hash']))
+                        break
         return widget