1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 __maintainer__ = 'Lionel Martin <lionel@fluendo.com>'
19 __maintainer2__ = 'Florian Boucault <florian@fluendo.com>'
20
21
22 from elisa.core.component import Component, ComponentError
23 from elisa.base_components.model import Model
24 from elisa.core.observers.observer import Observer
25 from elisa.core.observers.observable import Observable
26 from elisa.core import common
27 from elisa.core.input_event import *
28 from elisa.core.interface_controller import UndefinedMVCAssociation
29
30
33
34
36 """
37 Connects to a compatible L{elisa.base_components.model.Model} and
38 holds extra information useful for a L{elisa.base_components.view.View} to
39 render the model.
40 It is notified of all the changes occuring to L{model}. Part of these
41 changes can be treated automatically using the bindings system.
42 A Controller can be part of a hierarchy of Controllers thus potentially
43 having a reference to its L{parent} and to its children defined in
44 L{bindings}.
45
46 DOCME: focus, focused, branch of focused controllers, backend.
47
48 @cvar supported_models: list of models that are compatible with the
49 controller identified by their path: 'plugin:model'
50 @type supported_models: tuple of strings
51 @cvar bindings: associations between L{model}'s attribute and
52 Controller's attributes; if an attribute
53 contained in L{bindings}' keys is changed or
54 created in L{model}, it is replicated in all
55 the corresponding attributes of the
56 controller defined in L{bindings} values
57 @type bindings: dictionary: keys: strings; values: list of
58 strings or strings
59 @ivar model: model to which the controller is connected;
60 setting it to an incompatible model will fail
61 @type model: L{elisa.base_components.model.Model}
62 @ivar parent: parent controller; None if the controller is a root
63 @type parent: L{elisa.base_components.controller.Controller}
64 @ivar focused: DOCME
65 @type focused: boolean
66 @ivar backend: backend to which the controller belongs
67 @type backend: L{elisa.core.backend.Backend}
68 """
69
70 supported_models = ('base:model',)
71 bindings = {}
72
84
90
92 """
93 Grab the focus. The controller previously owning the focus loses it.
94 """
95 self.backend.focused_controller = self
96
99
108
110 """
111 Called when L{focused} is set to a new value.
112
113 Override if you wish to react to that change. Do not forget to call
114 the parent class method.
115
116 @param old_focused: value of focused before
117 @type old_focused: bool
118 @param new_focused: value of focused now
119 @type new_focused: bool
120 """
121 pass
122
125
127 old_backend, self._backend = self._backend, new_backend
128 if old_backend != new_backend:
129 self.backend_changed(old_backend, new_backend)
130
132 """
133 Called when L{backend} is set to a new value.
134
135 Override if you wish to react to that change. Do not forget to call
136 the parent class method.
137
138 @param old_backend: value of backend before
139 @type old_backend: L{elisa.core.backend.Backend}
140 @param new_backend: value of backend now
141 @type new_backend: L{elisa.core.backend.Backend}
142 """
143 pass
144
149
152
155
181
183 """
184 Called when L{model} is set to a new value.
185
186 Override if you wish to react to that change. Do not forget to call
187 the parent class method.
188
189 @param old_model: value of model before
190 @type old_model: L{elisa.base_components.model.Model}
191 @param new_model: value of model now
192 @type new_model: L{elisa.base_components.model.Model}
193 """
194 pass
195
211
213 """
214 Called when an attribute of the model to which it is connected changes.
215
216 @param key: attribute changed
217 @type key: string
218 @param old_value: value of the attribute before being set; None if
219 attribute was not existing
220 @type old_value: any
221 @param new_value: value of the attribute after being set
222 @type new_value: any
223 """
224
225 if key in self.bindings.keys():
226 self._update_bound_attributes(key)
227
229 """
230 Delete controller's attributes bound to L{model_attribute}.
231 """
232 child_attributes = self.bindings[model_attribute]
233 if isinstance(child_attributes, str):
234 child_attributes = [child_attributes]
235
236 for child_attribute in child_attributes:
237 try:
238 delattr(self, child_attribute)
239 except AttributeError:
240 pass
241
243 """
244 Update (create or delete) controller's attribute bound to
245 L{model_attribute}.
246 """
247 try:
248 model_child_value = getattr(self._model, model_attribute)
249 except AttributeError:
250 self._delete_bound_attributes(model_attribute)
251 return
252
253 child_attributes = self.bindings[model_attribute]
254 if isinstance(child_attributes, str):
255 child_attributes = [child_attributes]
256
257 if isinstance(model_child_value, Model):
258 for attribute in child_attributes:
259 self._update_bound_controller(attribute, model_child_value)
260 else:
261 for attribute in child_attributes:
262 setattr(self, attribute, model_child_value)
263
284
286 """
287 Create a Controller of type L{path} and make it a child of
288 self stored as an instance variable named after the content of
289 L{attribute}.
290
291 @param attribute: attribute of self where to store the newly
292 created controller
293 @type attribute: string
294 @param path: path to the type of controller which is to be
295 created; syntax: plugin:component
296 @type path: string
297 """
298
299 registry = common.application.plugin_registry
300 new_controller = registry.create_component(path)
301
302
303 self._add_child_controller(attribute, new_controller)
304
305 return new_controller
306
308 """
309 Make L{controller} a child of self stored as an instance variable named
310 after the content of L{attribute}.
311
312 @param attribute: attribute of self where to store the controller
313 @type attribute: string
314 @param controller: controller to be made child
315 @type path: L{elisa.base_components.controller.Controller}
316 """
317 controller.backend = self.backend
318 controller.parent = self
319 setattr(self, attribute, controller)
320