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 flumotion.configure import configure
31 from flumotion.common import log, planet, pygobject
32 from flumotion.twisted import flavors
33 from flumotion.twisted.compat import implements
34 from flumotion.common.planet import moods
35 from flumotion.common.pygobject import gsignal, gproperty
36 from flumotion.common.pygobject import with_construct_properties
37
38 COL_MOOD = 0
39 COL_NAME = 1
40 COL_WORKER = 2
41 COL_PID = 3
42 COL_STATE = 4
43 COL_MOOD_VALUE = 5
44 COL_CPU = 6
45
47 """
48 I implement the status bar used in the admin UI.
49 """
51 """
52 @param widget: a gtk.Statusbar to wrap.
53 """
54 self._widget = widget
55
56 self._cids = {}
57 self._mids = {}
58 self._contexts = ['main', 'notebook']
59
60 for context in self._contexts:
61 self._cids[context] = widget.get_context_id(context)
62 self._mids[context] = []
63
64 - def clear(self, context=None):
65 """
66 Clear the status bar for the given context, or for all contexts
67 if none specified.
68 """
69 if context:
70 self._clear_context(context)
71 return
72
73 for context in self._contexts:
74 self._clear_context(context)
75
76 - def push(self, context, message):
77 """
78 Push the given message for the given context.
79
80 @returns: message id
81 """
82 mid = self._widget.push(self._cids[context], message)
83 self._mids[context].append(mid)
84 return mid
85
86 - def pop(self, context):
87 """
88 Pop the last message for the given context.
89
90 @returns: message id popped, or None
91 """
92 if len(self._mids[context]):
93 mid = self._mids[context].pop()
94 self._widget.remove(self._cids[context], mid)
95 return mid
96
97 return None
98
99 - def set(self, context, message):
100 """
101 Replace the current top message for this context with this new one.
102
103 @returns: the message id of the message pushed
104 """
105 self.pop(context)
106 return self.push(context, message)
107
108 - def remove(self, context, mid):
109 """
110 Remove the message with the given id from the given context.
111
112 @returns: whether or not the given mid was valid.
113 """
114 if not mid in self._mids[context]:
115 return False
116
117 self._mids[context].remove(mid)
118 self._widget.remove(self._cids[context], mid)
119 return True
120
121 - def _clear_context(self, context):
122 if not context in self._cids.keys():
123 return
124
125 for mid in self._mids[context]:
126 self.remove(context, mid)
127
129 """
130 I present a view on the list of components logged in to the manager.
131 """
132
133 implements(flavors.IStateListener)
134
135 logCategory = 'components'
136
137 gsignal('has-selection', object)
138 gsignal('activated', object, str)
139
140
141 gproperty(bool, 'can-start-any', 'True if any component can be started',
142 False, construct=True)
143 gproperty(bool, 'can-stop-any', 'True if any component can be stopped',
144 False, construct=True)
145 _model = _view = _moodPixbufs = None
146
167 __init__ = with_construct_properties (__init__)
168
170
171 col = gtk.TreeViewColumn(_('Mood'), gtk.CellRendererPixbuf(),
172 pixbuf=COL_MOOD)
173 col.set_sort_column_id(COL_MOOD_VALUE)
174 self._view.append_column(col)
175
176 col = gtk.TreeViewColumn(_('Component'), gtk.CellRendererText(),
177 text=COL_NAME)
178 col.set_sort_column_id(COL_NAME)
179 self._view.append_column(col)
180
181 col = gtk.TreeViewColumn(_('Worker'), gtk.CellRendererText(),
182 markup=COL_WORKER)
183 col.set_sort_column_id(COL_WORKER)
184 self._view.append_column(col)
185
186 def type_pid_datafunc(column, cell, model, iter):
187 state = model.get_value(iter, COL_STATE)
188 pid = state.get('pid')
189 cell.set_property('text', pid and str(pid) or '')
190
191 t = gtk.CellRendererText()
192 col = gtk.TreeViewColumn('PID', t, text=COL_PID)
193 col.set_cell_data_func(t, type_pid_datafunc)
194 col.set_sort_column_id(COL_PID)
195 self._view.append_column(col)
196
197 def type_cpu_datafunc(column, cell, model, iter):
198 state = model.get_value(iter, COL_STATE)
199 cpu = state.get('cpu')
200 if isinstance(cpu, float):
201 cell.set_property('text', '%.2f' % (cpu * 100.0))
202 else:
203 cell.set_property('text', '')
204
205 t = gtk.CellRendererText()
206 col = gtk.TreeViewColumn('CPU %', t, text=COL_CPU)
207 col.set_cell_data_func(t, type_cpu_datafunc)
208 col.set_sort_column_id(COL_CPU)
209 self._view.append_column(col)
210
211
212
213
215 pixbufs = {}
216 for i in range(0, len(moods)):
217 name = moods.get(i).name
218 pixbufs[i] = gtk.gdk.pixbuf_new_from_file(os.path.join(
219 configure.imagedir, 'mood-%s.png' % name))
220
221 return pixbufs
222
224
225 state = self.get_selected_state()
226
227 if not state:
228 self.debug('no component selected, emitting has-selection None')
229 self.emit('has-selection', None)
230 return
231
232 if state == self._last_state:
233 return
234
235 self._last_state = state
236 self.debug('component selected, emitting has-selection')
237 self.emit('has-selection', state)
238
261
265
267 """
268 Get the name of the currently selected component, or None.
269
270 @rtype: string
271 """
272 selection = self._view.get_selection()
273 sel = selection.get_selected()
274 if not sel:
275 return None
276 model, iter = sel
277 if not iter:
278 return
279
280 return model.get(iter, COL_NAME)[0]
281
283 """
284 Get the state of the currently selected component, or None.
285
286 @rtype: L{flumotion.common.component.AdminComponentState}
287 """
288 selection = self._view.get_selection()
289 if not selection:
290 return None
291 sel = selection.get_selected()
292 if not sel:
293 return None
294 model, iter = sel
295 if not iter:
296 return
297
298 return model.get(iter, COL_STATE)[0]
299
301 oldstop = self.get_property('can-stop-any')
302 oldstart = self.get_property('can-start-any')
303 moodnames = [moods.get(x[COL_MOOD_VALUE]).name for x in self._model]
304 can_stop = bool([x for x in moodnames if (x!='lost' and x!='sleeping')])
305 can_start = bool([x for x in moodnames if (x=='sleeping')])
306 if oldstop != can_stop:
307 self.set_property('can-stop-any', can_stop)
308 if oldstart != can_start:
309 self.set_property('can-start-any', can_start)
310
315
316 - def update(self, components):
360
362
363
364
365
366
367 workerName = componentState.get('workerName')
368 workerRequested = componentState.get('workerRequested')
369 if not workerName:
370 workerName = "%s" % workerRequested
371 if not workerRequested:
372 workerName = _("[any worker]")
373
374 mood = componentState.get('mood')
375 markup = workerName
376 if mood == moods.sleeping.value:
377 markup = "<i>%s</i>" % workerName
378 self._model.set(iter, COL_WORKER, markup)
379
381 if not isinstance(state, planet.AdminComponentState):
382 self.warning('Got state change for unknown object %r' % state)
383 return
384
385 iter = self._iters[state]
386 self.log('stateSet: state %r, key %s, value %r' % (state, key, value))
387
388 if key == 'mood':
389 self._set_mood_value(iter, value)
390 self._updateWorker(iter, state)
391 elif key == 'name':
392 if value:
393 self._model.set(iter, COL_NAME, value)
394 elif key == 'workerName':
395 self._updateWorker(iter, state)
396 elif key == 'cpu':
397 self._model.set(iter, COL_CPU, value)
398
409
410 pygobject.type_register(ComponentsView)
411
413
414 gsignal('activated', str)
415
417 """
418 @param state: L{flumotion.common.component.AdminComponentState}
419 """
420 gtk.Menu.__init__(self)
421 self._items = {}
422
423 self.set_title(_('Component'))
424
425 i = gtk.MenuItem(_('_Restart'))
426 self.append(i)
427 self._items['restart'] = i
428
429 i = gtk.MenuItem(_('_Start'))
430 mood = moods.get(state.get('mood'))
431 if mood == moods.happy:
432 i.set_property('sensitive', False)
433 self.append(i)
434 self._items['start'] = i
435
436 i = gtk.MenuItem(_('St_op'))
437 if mood == moods.sleeping:
438 i.set_property('sensitive', False)
439 self.append(i)
440 self._items['stop'] = i
441
442 self.append(gtk.SeparatorMenuItem())
443
444 i = gtk.MenuItem(_('Reload _code'))
445 self.append(i)
446 self._items['reload'] = i
447
448 i = gtk.MenuItem(_('_Modify element property ...'))
449 self.append(i)
450 self._items['modify'] = i
451
452
453 for name in self._items.keys():
454 i = self._items[name]
455 i.connect('activate', self._activated_cb, name)
456
457 self.show_all()
458
461
462 pygobject.type_register(ComponentMenu)
463