1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 """widget holder displaying a component specific views"""
23
24 import gettext
25 import os
26
27 import gobject
28 import gtk
29
30 from flumotion.common import componentui, log, errors, messages
31 from flumotion.common.common import pathToModuleName
32 from flumotion.common.planet import AdminComponentState, moods
33 from flumotion.common.i18n import N_, gettexter
34 from twisted.internet import defer
35 from gettext import gettext as _
36
37 T_ = gettexter()
38
39
40 componentui
41
42 __version__ = "$Rev$"
43 _ = gettext.gettext
44 _DEBUG_ONLY_PAGES = ['Eaters', 'Feeders', 'Properties']
45 (COMPONENT_UNSET,
46 COMPONENT_INACTIVE,
47 COMPONENT_ACTIVE) = range(3)
48
49
51 """A placeholder contains a Widget subclass of a specific
52 component.
53 """
54
58
60 """Set if debug should be enabled.
61 Not all pages are visible unless debugging is set to true
62 @param enable: if debug should be enabled
63 """
64
66 """Called when the placeholder is inactivated, eg
67 detached from the parent"""
68
69
71 """This is a placeholder containing a vbox
72 """
73 logCategory = 'nodebook'
74
76 """
77 @param admingtk: the GTK Admin with its nodes
78 @type admingtk: L{flumotion.component.base.admin_gtk.BaseAdminGtk}
79 """
80 self._debugEnabled = False
81 self._admingtk = admingtk
82 self.widget = self._admingtk.getWidget()
83 self.widget.show()
84
85
86
89
91 if self._admingtk:
92
93 if hasattr(self._admingtk, 'cleanup'):
94 self._admingtk.cleanup()
95 self._admingtk = None
96
97
99 """This is a placeholder containing a notebook with tabs
100 """
101 logCategory = 'nodebook'
102
104 """
105 @param admingtk: the GTK Admin with its nodes
106 @type admingtk: L{flumotion.component.base.admin_gtk.BaseAdminGtk}
107 """
108 self._debugEnabled = False
109 self._admingtk = admingtk
110 self._notebook = None
111 self._pageWidgets = {}
112
113 self._notebook = gtk.Notebook()
114 admingtk.setup()
115 self.nodes = admingtk.getNodes()
116 self._appendPages()
117 self._notebook.show()
118
119
120
123
125 if self._admingtk:
126
127 if hasattr(self._admingtk, 'cleanup'):
128 self._admingtk.cleanup()
129 self._admingtk = None
130
132 self._debugEnabled = enabled
133 if self._admingtk:
134 self._admingtk.setDebugEnabled(enabled)
135 for name in _DEBUG_ONLY_PAGES:
136 widget = self._pageWidgets.get(name)
137 if widget is None:
138 continue
139 widget.set_property('visible', enabled)
140
149
150 - def _addPage(self, name):
151 node = self.nodes.get(name)
152 assert node is not None, name
153
154 table = gtk.Table(1, 1)
155 table.add(gtk.Label(_('Loading UI for %s...') % name))
156 label = self._getTitleLabel(node, name)
157 label.show()
158 self._notebook.append_page(table, label)
159
160 d = node.render()
161 d.addCallback(self._renderWidget, table)
162 return table
163
164 - def _appendPages(self):
165 for name in self.nodes.keys():
166 table = self._addPage(name)
167 self._pageWidgets[name] = table
168
169 if name in _DEBUG_ONLY_PAGES:
170 if self._debugEnabled:
171 continue
172 table.show()
173
186
187
189 """This is a placeholder with a label, with or without a text"""
190
193
196
197
199 """This is a placeholder used to display a Planet"""
200
202 self._widget = gtk.Label('')
203
206
207
209 """
210 I represent the state of a list of components in the admin client.
211 See L{flumotion.common.planet.AdminComponentState}.
212 """
213
215 self._componentStates = states
216 self._state = dict(mood=moods.happy,
217 name='multiple-components',
218 type='MultipleComponents')
219
221 for state in self._componentStates:
222 try:
223 state.addListener(*args, **kwargs)
224 except KeyError, e:
225 self.debug('Error adding listener for component %s',
226 state.get('name'))
227
229 for state in self._componentStates:
230 try:
231 state.removeListener(listener)
232 except KeyError:
233 self.debug('Error removing listener for component %s',
234 state.get('name'))
235
237 return key in self._state.keys()
238
239 - def get(self, key):
240 return self._state.get(key, None)
241
243 return self._componentStates
244
245
247 logCategory = 'componentview'
248
250 gtk.VBox.__init__(self)
251 self._admin = None
252 self._currentComponentState = None
253 self._currentPlaceholder = None
254 self._debugEnabled = False
255 self._state = COMPONENT_UNSET
256
257 self._planetPlaceholder = PlanetPlaceholder()
258 self._addPlaceholder(self._planetPlaceholder)
259
260
261
263 """Find out if debug is enabled
264 @returns: if debug is enabled
265 @rtype: bool
266 """
267 return self._debugEnabled
268
270 """Sets if debug should be enabled
271 @param enabled: if debug should be enabled
272 @type enabled: bool
273 """
274 self._debugEnabled = enabled
275 if self._currentPlaceholder:
276 self._currentPlaceholder.setDebugEnabled(enabled)
277
287
289 """
290 Sets a single global admin for the component view
291
292 @param admin: the admin
293 @type admin: L{flumotion.admin.admin.AdminModel}
294 """
295 self._admin = admin
296
298 """
299 Get the admin for a specific component
300
301 @param component: component
302 @type component: L{flumotion.common.component.AdminComponentState}
303
304 @returns: the admin
305 @rtype: L{flumotion.admin.admin.AdminModel}
306 """
307
308 return self._admin
309
310
311
313 if not isinstance(placeholder, Placeholder):
314 raise AssertionError(
315 "placeholder must be a Placeholder subclass, not %r" % (
316 placeholder, ))
317
318 widget = placeholder.getWidget()
319 widget.show()
320 map(self.remove, self.get_children())
321 self.pack_start(widget, True, True)
322
323 placeholder.setDebugEnabled(self._debugEnabled)
324 self._currentPlaceholder = placeholder
325
331
339
340 def oldVersion(failure):
341
342
343
344
345
346
347
348 failure.trap(AttributeError)
349
350 return admin.callRemote(
351 'getEntryByType', componentState, 'admin/gtk')
352
353 def gotEntryPoint((filename, procname)):
354
355
356
357 filename = filename.replace('/', os.path.sep)
358
359
360
361 modname = pathToModuleName(filename)
362
363
364 d = admin.getBundledFunction(modname, procname)
365 d.addErrback(admin.bundleErrback, filename)
366
367 def handleSyntaxError(failure):
368 failure.trap(errors.EntrySyntaxError)
369 msg = failure.value.args[0]
370
371 m = messages.Error(T_(
372 N_("This component has a UI bug.")), debug=msg)
373 componentState.observe_append('messages', m)
374
375 raise errors.HandledException(failure.value)
376
377 d.addErrback(handleSyntaxError)
378
379 return d
380
381 def gotFactory(factory, placeholder=NotebookPlaceholder):
382
383 widget = factory(componentState, admin)
384 return placeholder(widget)
385
386 def sleepingComponent(failure):
387 failure.trap(errors.SleepingComponentError)
388 return LabelPlaceholder(_("Component '%s' is still sleeping.") %
389 componentState.get('name'))
390
391 def noMultipleComponents(failure):
392
393
394 failure.trap(errors.RemoteRunError)
395 return LabelPlaceholder()
396
397 def handledExceptionErrback(failure):
398
399
400 failure.trap(errors.HandledException)
401 return LabelPlaceholder(_("Component '%s' has a UI bug.") %
402 componentState.get('name'))
403
404 if isinstance(componentState, AdminComponentState):
405 admin = self.getAdminForComponent(componentState)
406 componentType = componentState.get('type')
407 d = admin.callRemote('getEntryByType', componentType, 'admin/gtk')
408 d.addErrback(oldVersion)
409 d.addErrback(noBundle)
410 d.addCallback(gotEntryPoint)
411 d.addCallback(gotFactory)
412 d.addErrback(sleepingComponent)
413 d.addErrback(handledExceptionErrback)
414 return d
415 elif isinstance(componentState, MultipleAdminComponentStates):
416 admin = self.getAdminForComponent(componentState)
417 d = gotEntryPoint(("flumotion/component/base/multiple.py",
418 "MultipleComponentsAdminGtk"))
419 d.addCallback(gotFactory, SingleNodePlaceholder)
420 d.addErrback(sleepingComponent)
421 d.addErrback(handledExceptionErrback)
422 d.addErrback(noMultipleComponents)
423 return d
424 else:
425 return defer.succeed(LabelPlaceholder())
426
431
432 def set_(state, key, value):
433 if key != 'mood':
434 return
435 if value not in [moods.lost.value,
436 moods.sleeping.value,
437 moods.sad.value]:
438 self._setState(COMPONENT_ACTIVE)
439 else:
440 self._setState(COMPONENT_INACTIVE)
441
442 current = self._currentComponentState
443 assert current is not None
444 current.addListener(self, invalidate=invalidate, set_=set_)
445 if current.hasKey('mood'):
446 set_(current, 'mood', current.get('mood'))
447
449
450 def gotWidgetConstructor(placeholder, oldComponentState):
451 if oldComponentState != self._currentComponentState:
452
453
454
455 self.debug('ignoring component %r, state %d, state %r/%r' % (
456 placeholder, self._state,
457 oldComponentState, self._currentComponentState))
458 return
459 self._removePlaceholder(self._planetPlaceholder)
460 self._addPlaceholder(placeholder)
461
462 d = self._getWidgetConstructor(self._currentComponentState)
463 d.addCallback(gotWidgetConstructor, self._currentComponentState)
464
468
470 if self._currentComponentState:
471 self._currentComponentState.removeListener(self)
472 self._currentComponentState = None
473
491
492 gobject.type_register(ComponentView)
493