1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 __maintainer__ = 'Florian Boucault <florian@fluendo.com>'
19 __maintainer2__ = 'Lionel Martin <lionel@fluendo.com>'
20
21
22 from elisa.core.component import Component, ComponentError
23 from elisa.base_components.controller import Controller
24 from elisa.core.observers.observer import Observer
25 from elisa.core import common
26 from elisa.core.interface_controller import UndefinedMVCAssociation
27
28
31
32 -class View(Component, Observer):
33 """
34 A View is responsible for rendering a Model. It can be of various nature
35 such as graphics, audio or even network output. A View does not hold a
36 direct reference to the Model it renders but accesses it through
37 L{controller}.
38 It is notified of all the changes occuring to L{controller}. Part of these
39 changes can be treated automatically using the bindings system.
40 A View can be part of a hierarchy of Views thus potentially having a
41 reference to its L{parent} and to its children defined in L{bindings}.
42 A View belongs to its L{frontend} which encapsulates objects necessary for
43 a View to be rendered (rendering context, theme, etc.)
44
45 @cvar supported_controllers: list of controllers that are compatible with
46 the view identified by their path:
47 'plugin:controller'
48 @type supported_controllers: tuple of strings
49
50 @cvar bindings: associations between L{model}'s attribute and
51 Controller's attributes; if an attribute
52 contained in L{bindings}' keys is changed or
53 created in L{model}, it is replicated in all
54 the corresponding attributes of the
55 controller defined in L{bindings} values
56 @type bindings: dictionary: keys: strings; values: list of
57 strings or strings
58 @ivar controller: controller to which the view is connected in
59 order to access the model; setting it to an
60 incompatible controller will fail
61 @type controller: L{elisa.base_components.controller.Controller}
62 @ivar parent: parent view; None if the view is a root
63 @type parent: L{elisa.base_components.view.View}
64 @ivar frontend: frontend to which the view belongs
65 @type frontend: L{elisa.core.frontend.Frontend}
66 @ivar context_handle: DOCME
67 @type context_handle: any
68 """
69
70 supported_controllers = ('base:controller',)
71 bindings = {}
72
73 context_path = None
74
76 super(View, self).__init__()
77 self._controller = None
78 self.context_handle = None
79 self._frontend = None
80 self._parent_view = None
81 self._supported_controller_classes = ()
82
83
90
96
99
101 previous_frontend, self._frontend = self._frontend, new_frontend
102 if previous_frontend != new_frontend:
103 self.frontend_changed(previous_frontend, new_frontend)
104
106 """
107 Called when L{frontend} is set to a new value.
108
109 Override if you wish to react to that change. Do not forget to call
110 the parent class method.
111
112 @param old_frontend: value of frontend before
113 @type old_frontend: L{elisa.core.frontend.Frontend}
114 @param new_frontend: value of frontend now
115 @type new_frontend: L{elisa.core.frontend.Frontend}
116 """
117 pass
118
120 return self._controller
121
147
149 """
150 Called when L{controller} is set to a new value.
151
152 Override if you wish to react to that change. Do not forget to call
153 the parent class method.
154
155 @param old_controller: value of controller before
156 @type old_controller: L{elisa.base_components.controller.Controller}
157 @param new_controller: value of controller now
158 @type new_controller: L{elisa.base_components.controller.Controller}
159 """
160 pass
161
163 """
164 Refresh completely the rendering of the associated Controller. This should
165 be called when the Controller has changed.
166 """
167 pass
168
173
175
176
177 return self._parent_view
178
180 """
181 Called when an attribute of the controller to which it is connected
182 changes.
183
184 @param key: attribute changed
185 @type key: string
186 @param old_value: value of the attribute before being set; None if
187 attribute was not existing
188 @type old_value: any
189 @param new_value: value of the attribute after being set
190 @type new_value: any
191 """
192
193 if key in self.bindings.keys():
194 self._update_bound_attributes(key)
195
197 """
198 Delete view's attributes bound to L{controller_attribute}.
199 """
200 child_attributes = self.bindings[controller_attribute]
201 if isinstance(child_attributes, str):
202 child_attributes = [child_attributes]
203
204 for child_attribute in child_attributes:
205 try:
206 delattr(self, child_attribute)
207 except AttributeError:
208 pass
209
211 """
212 Update (create or delete) view's attribute bound to
213 L{controller_attribute}.
214 """
215 try:
216 controller_child_value = getattr(self._controller,
217 controller_attribute)
218 except AttributeError:
219 self._delete_bound_attributes(controller_attribute)
220 return
221
222 child_attributes = self.bindings[controller_attribute]
223 if isinstance(child_attributes, str):
224 child_attributes = [child_attributes]
225
226 if isinstance(controller_child_value, Controller):
227 for attribute in child_attributes:
228 self._update_bound_view(attribute, controller_child_value)
229 else:
230 for child_attribute in child_attributes:
231 setattr(self, child_attribute, controller_child_value)
232
253
255 """
256 Create a View of type L{path} and make it a child of
257 self stored as an instance variable named after the content of
258 L{attribute}.
259
260 @param attribute: attribute of self where to store the newly
261 created view
262 @type attribute: string
263 @param path: path to the type of view which is to be
264 created; syntax: plugin:component
265 @type path: string
266 """
267
268 registry = common.application.plugin_registry
269 new_view = registry.create_component(path)
270
271
272 self._add_child_view(attribute, new_view)
273
274 return new_view
275
277 """
278 Make L{view} a child of self stored as an instance variable named
279 after the content of L{attribute}.
280
281 @param attribute: attribute of self where to store the view
282 @type attribute: string
283 @param view: view to be made child
284 @type path: L{elisa.base_components.view.View}
285 """
286 view.frontend = self.frontend
287 view.parent = self
288 setattr(self, attribute, view)
289