comparison frontends/src/quick_frontend/quick_widgets.py @ 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 faa1129559b8
children d3ef3894254d
comparison
equal deleted inserted replaced
1300:ba73798317a7 1301:afc57b34c0a3
19 19
20 from sat.core.log import getLogger 20 from sat.core.log import getLogger
21 log = getLogger(__name__) 21 log = getLogger(__name__)
22 from sat.core import exceptions 22 from sat.core import exceptions
23 23
24 from sat_frontends.quick_frontend.constants import Const as C
24 25
25 classes_map = {} 26 classes_map = {}
26 27
27 28
28 try: 29 try:
38 @param base_cls: "Quick..." base class (like QuickChat or QuickContact), must inherit from QuickWidget 39 @param base_cls: "Quick..." base class (like QuickChat or QuickContact), must inherit from QuickWidget
39 @param child_cls: inherited class to use when Quick... class is requested, must inherit from base_cls. 40 @param child_cls: inherited class to use when Quick... class is requested, must inherit from base_cls.
40 Can be None if it's the base_cls itself which register 41 Can be None if it's the base_cls itself which register
41 """ 42 """
42 classes_map[base_cls] = child_cls 43 classes_map[base_cls] = child_cls
44 class WidgetAlreadyExistsError(Exception):
45 pass
43 46
44 47
45 class QuickWidgetsManager(object): 48 class QuickWidgetsManager(object):
46 """This class is used to manage all the widgets of a frontend 49 """This class is used to manage all the widgets of a frontend
47 A widget can be a window, a graphical thing, or someting else depending of the frontend""" 50 A widget can be a window, a graphical thing, or someting else depending of the frontend"""
93 @param args(list): optional args to create a new instance of class_ 96 @param args(list): optional args to create a new instance of class_
94 @param kwargs(list): optional kwargs to create anew instance of class_ 97 @param kwargs(list): optional kwargs to create anew instance of class_
95 if 'profile' key is present, it will be popped and put in 'profiles' 98 if 'profile' key is present, it will be popped and put in 'profiles'
96 if there is neither 'profile' nor 'profiles', None will be used for 'profiles' 99 if there is neither 'profile' nor 'profiles', None will be used for 'profiles'
97 if 'on_new_widget' is present it can have the following values: 100 if 'on_new_widget' is present it can have the following values:
98 'NEW_WIDGET' [default]: self.host.newWidget will be called on widget creation 101 C.WIDGET_NEW [default]: self.host.newWidget will be called on widget creation
99 [callable]: this method will be called instead of self.host.newWidget 102 [callable]: this method will be called instead of self.host.newWidget
100 None: do nothing 103 None: do nothing
104 if 'on_existing_widget' is present it can have the following values:
105 C.WIDGET_KEEP [default]: return the existing widget
106 C.WIDGET_RAISE: raise WidgetAlreadyExistsError
107 C.WIDGET_RECREATE: create a new widget *WITH A NEW HASH*
101 if 'force_hash' is present, the hash given in value will be used instead of the one returned by class_.getWidgetHash 108 if 'force_hash' is present, the hash given in value will be used instead of the one returned by class_.getWidgetHash
102 @return: a class_ instance, either new or already existing 109 @return: a class_ instance, either new or already existing
103 """ 110 """
104 cls = self.getRealClass(class_) 111 cls = self.getRealClass(class_)
105 112
106 # arguments management 113 ## arguments management ##
107 _args = [self.host, target] + list(args) or [] # FIXME: check if it's really necessary to use optional args 114 _args = [self.host, target] + list(args) or [] # FIXME: check if it's really necessary to use optional args
108 _kwargs = kwargs or {} 115 _kwargs = kwargs or {}
109 if 'profiles' in _kwargs and 'profile' in _kwargs: 116 if 'profiles' in _kwargs and 'profile' in _kwargs:
110 raise ValueError("You can't have 'profile' and 'profiles' keys at the same time") 117 raise ValueError("You can't have 'profile' and 'profiles' keys at the same time")
111 try: 118 try:
112 _kwargs['profiles'] = _kwargs.pop('profile') 119 _kwargs['profiles'] = _kwargs.pop('profile')
113 except KeyError: 120 except KeyError:
114 if not 'profiles' in _kwargs: 121 if not 'profiles' in _kwargs:
115 _kwargs['profiles'] = None 122 _kwargs['profiles'] = None
116 123
117 # we get the hash 124 #on_new_widget tell what to do for the new widget creation
125 try:
126 on_new_widget = _kwargs.pop('on_new_widget')
127 except KeyError:
128 on_new_widget = C.WIDGET_NEW
129
130 #on_existing_widget tell what to do when the widget already exists
131 try:
132 on_existing_widget = _kwargs.pop('on_existing_widget')
133 except KeyError:
134 on_existing_widget = C.WIDGET_KEEP
135
136 ## we get the hash ##
118 try: 137 try:
119 hash_ = _kwargs.pop('force_hash') 138 hash_ = _kwargs.pop('force_hash')
120 except KeyError: 139 except KeyError:
121 hash_ = cls.getWidgetHash(target, _kwargs['profiles']) 140 hash_ = cls.getWidgetHash(target, _kwargs['profiles'])
122 141
131 except KeyError: 150 except KeyError:
132 widget = None 151 widget = None
133 152
134 if widget is None: 153 if widget is None:
135 # we need to create a new widget 154 # we need to create a new widget
136 try:
137 #on_new_widget tell what to do for the new widget creation
138 on_new_widget = _kwargs.pop('on_new_widget')
139 except KeyError:
140 on_new_widget = 'NEW_WIDGET'
141
142 log.debug(u"Creating new widget for target {} {}".format(target, cls)) 155 log.debug(u"Creating new widget for target {} {}".format(target, cls))
143 widget = cls(*_args, **_kwargs) 156 widget = cls(*_args, **_kwargs)
144 widgets_map[hash_] = widget 157 widgets_map[hash_] = widget
145 158
146 if on_new_widget == 'NEW_WIDGET': 159 if on_new_widget == C.WIDGET_NEW:
147 self.host.newWidget(widget) 160 self.host.newWidget(widget)
148 elif callable(on_new_widget): 161 elif callable(on_new_widget):
149 on_new_widget(widget) 162 on_new_widget(widget)
150 else: 163 else:
151 assert on_new_widget is None 164 assert on_new_widget is None
152 165 else:
166 # the widget already exists
167 if on_existing_widget == C.WIDGET_RAISE:
168 raise WidgetAlreadyExistsError(hash_)
169 elif on_existing_widget == C.WIDGET_RECREATE:
170 # we use getOrCreateWidget to recreate the new widget
171 # /!\ we use args and kwargs and not _args and _kwargs because we need the original args
172 # we need to get rid of kwargs special options
173 new_kwargs = kwargs.copy()
174 try:
175 new_kwargs.pop('force_hash') # FIXME: we use pop instead of del here because pyjamas doesn't raise error on del
176 except KeyError:
177 pass
178 else:
179 raise ValueError("force_hash option can't be used with on_existing_widget=RECREATE")
180
181 # XXX: keep up-to-date if new special kwargs are added (i.e.: delete these keys here)
182 new_kwargs['on_new_widget'] = None
183 new_kwargs['on_existing_widget'] = C.WIDGET_RAISE
184 hash_idx = 1
185 while True:
186 new_kwargs['force_hash'] = hash_ + "_new_instance_{}".format(hash_idx)
187 try:
188 widget = self.getOrCreateWidget(class_, target, *args, **new_kwargs)
189 except WidgetAlreadyExistsError:
190 hash_idx += 1
191 else:
192 log.debug(u"Widget already exists, a new one has been recreated with hash {}".format(new_kwargs['force_hash']))
193 break
153 return widget 194 return widget
154 195
155 196
156 class QuickWidget(object): 197 class QuickWidget(object):
157 """generic widget base""" 198 """generic widget base"""