1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 import os
23
24 from gettext import gettext as _
25
26 import gobject
27 import gtk
28 import gtk.glade
29
30 from zope.interface import implements
31
32 from flumotion.configure import configure
33 from flumotion.common import log, planet, pygobject
34 from flumotion.twisted import flavors
35 from flumotion.common.planet import moods
36 from flumotion.common.pygobject import gsignal, gproperty
37 from flumotion.common.pygobject import with_construct_properties
38
39 (COL_MOOD,
40 COL_NAME,
41 COL_WORKER,
42 COL_PID,
43 COL_STATE,
44 COL_MOOD_VALUE,
45 COL_CPU) = range(7)
46
50
52 """
53 I implement the status bar used in the admin UI.
54 """
56 """
57 @param widget: a gtk.Statusbar to wrap.
58 """
59 self._widget = widget
60
61 self._cids = {}
62 self._mids = {}
63 self._contexts = ['main', 'notebook']
64
65 for context in self._contexts:
66 self._cids[context] = widget.get_context_id(context)
67 self._mids[context] = []
68
69 - def clear(self, context=None):
70 """
71 Clear the status bar for the given context, or for all contexts
72 if none specified.
73 """
74 if context:
75 self._clear_context(context)
76 return
77
78 for context in self._contexts:
79 self._clear_context(context)
80
81 - def push(self, context, message):
82 """
83 Push the given message for the given context.
84
85 @returns: message id
86 """
87 mid = self._widget.push(self._cids[context], message)
88 self._mids[context].append(mid)
89 return mid
90
91 - def pop(self, context):
92 """
93 Pop the last message for the given context.
94
95 @returns: message id popped, or None
96 """
97 if len(self._mids[context]):
98 mid = self._mids[context].pop()
99 self._widget.remove(self._cids[context], mid)
100 return mid
101
102 return None
103
104 - def set(self, context, message):
105 """
106 Replace the current top message for this context with this new one.
107
108 @returns: the message id of the message pushed
109 """
110 self.pop(context)
111 return self.push(context, message)
112
113 - def remove(self, context, mid):
114 """
115 Remove the message with the given id from the given context.
116
117 @returns: whether or not the given mid was valid.
118 """
119 if not mid in self._mids[context]:
120 return False
121
122 self._mids[context].remove(mid)
123 self._widget.remove(self._cids[context], mid)
124 return True
125
126 - def _clear_context(self, context):
127 if not context in self._cids.keys():
128 return
129
130 for mid in self._mids[context]:
131 self.remove(context, mid)
132
134 """
135 I present a view on the list of components logged in to the manager.
136 """
137
138 implements(flavors.IStateListener)
139
140 logCategory = 'components'
141
142 gsignal('selection-changed', object)
143 gsignal('activated', object, str)
144
145
146 gproperty(bool, 'can-start-any', 'True if any component can be started',
147 False, construct=True)
148 gproperty(bool, 'can-stop-any', 'True if any component can be stopped',
149 False, construct=True)
150 _model = _view = _moodPixbufs = None
151
172 __init__ = with_construct_properties (__init__)
173
175
176 col = gtk.TreeViewColumn(_('Mood'), gtk.CellRendererPixbuf(),
177 pixbuf=COL_MOOD)
178 col.set_sort_column_id(COL_MOOD_VALUE)
179 self._view.append_column(col)
180
181 col = gtk.TreeViewColumn(_('Component'), gtk.CellRendererText(),
182 text=COL_NAME)
183 col.set_sort_column_id(COL_NAME)
184 self._view.append_column(col)
185
186 col = gtk.TreeViewColumn(_('Worker'), gtk.CellRendererText(),
187 markup=COL_WORKER)
188 col.set_sort_column_id(COL_WORKER)
189 self._view.append_column(col)
190
191 def type_pid_datafunc(column, cell, model, iter):
192 state = model.get_value(iter, COL_STATE)
193 pid = state.get('pid')
194 cell.set_property('text', pid and str(pid) or '')
195
196 t = gtk.CellRendererText()
197 col = gtk.TreeViewColumn('PID', t, text=COL_PID)
198 col.set_cell_data_func(t, type_pid_datafunc)
199 col.set_sort_column_id(COL_PID)
200 self._view.append_column(col)
201
202
203
204
206 pixbufs = {}
207 for i in range(0, len(moods)):
208 name = moods.get(i).name
209 pixbufs[i] = gtk.gdk.pixbuf_new_from_file(os.path.join(
210 configure.imagedir, 'mood-%s.png' % name))
211
212 return pixbufs
213
215
216 state = self.get_selected_state()
217
218 if not state:
219 self.debug('no component selected, emitting selection-changed None')
220 self.emit('selection-changed', None)
221 return
222
223 if state == self._last_state:
224 return
225
226 self._last_state = state
227 self.debug('component selected, emitting selection-changed')
228 self.emit('selection-changed', state)
229
252
256
258 """
259 Get the name of the currently selected component, or None.
260
261 @rtype: string
262 """
263 selection = self._view.get_selection()
264 sel = selection.get_selected()
265 if not sel:
266 return None
267 model, iter = sel
268 if not iter:
269 return
270
271 return model.get(iter, COL_NAME)[0]
272
274 """
275 Get the state of the currently selected component, or None.
276
277 @rtype: L{flumotion.common.component.AdminComponentState}
278 """
279 selection = self._view.get_selection()
280 if not selection:
281 return None
282 sel = selection.get_selected()
283 if not sel:
284 return None
285 model, iter = sel
286 if not iter:
287 return
288
289 return model.get(iter, COL_STATE)[0]
290
292 oldstop = self.get_property('can-stop-any')
293 oldstart = self.get_property('can-start-any')
294 moodnames = [moods.get(x[COL_MOOD_VALUE]).name for x in self._model]
295 can_stop = bool([x for x in moodnames if (x!='sleeping')])
296 can_start = bool([x for x in moodnames if (x=='sleeping')])
297 if oldstop != can_stop:
298 self.set_property('can-stop-any', can_stop)
299 if oldstart != can_start:
300 self.set_property('can-start-any', can_start)
301
306
307 - def update(self, components):
351
353
354
355
356
357
358 workerName = componentState.get('workerName')
359 workerRequested = componentState.get('workerRequested')
360 if not workerName:
361 workerName = "%s" % workerRequested
362 if not workerRequested:
363 workerName = _("[any worker]")
364
365 mood = componentState.get('mood')
366 markup = workerName
367 if mood == moods.sleeping.value:
368 markup = "<i>%s</i>" % workerName
369 self._model.set(iter, COL_WORKER, markup)
370
372 if not isinstance(state, planet.AdminComponentState):
373 self.warning('Got state change for unknown object %r' % state)
374 return
375
376 iter = self._iters[state]
377 self.log('stateSet: state %r, key %s, value %r' % (state, key, value))
378
379 if key == 'mood':
380 self._set_mood_value(iter, value)
381 self._updateWorker(iter, state)
382 elif key == 'name':
383 if value:
384 self._model.set(iter, COL_NAME, value)
385 elif key == 'workerName':
386 self._updateWorker(iter, state)
387
398
399 pygobject.type_register(ComponentsView)
400
402
403 gsignal('activated', str)
404
406 """
407 @param state: L{flumotion.common.component.AdminComponentState}
408 """
409 gtk.Menu.__init__(self)
410 self._items = {}
411
412 self.set_title(_('Component'))
413
414 i = gtk.MenuItem(_('_Restart'))
415 self.append(i)
416 self._items['restart'] = i
417
418 i = gtk.MenuItem(_('_Start'))
419 mood = moods.get(state.get('mood'))
420 if mood == moods.happy:
421 i.set_property('sensitive', False)
422 self.append(i)
423 self._items['start'] = i
424
425 i = gtk.MenuItem(_('St_op'))
426 if mood == moods.sleeping:
427 i.set_property('sensitive', False)
428 self.append(i)
429 self._items['stop'] = i
430
431 i = gtk.MenuItem(_('_Delete'))
432 if not (mood == moods.sleeping):
433 i.set_property('sensitive', False)
434 self.append(i)
435 self._items['delete'] = i
436
437 self.append(gtk.SeparatorMenuItem())
438
439 i = gtk.MenuItem(_('Reload _code'))
440 self.append(i)
441 self._items['reload'] = i
442
443 i = gtk.MenuItem(_('_Modify element property ...'))
444 self.append(i)
445 self._items['modify'] = i
446
447
448 for name in self._items.keys():
449 i = self._items[name]
450 i.connect('activate', self._activated_cb, name)
451
452 self.show_all()
453
456
457 pygobject.type_register(ComponentMenu)
458