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