Merge lp:~nataliabidart/magicicada-gui/set-initial-state into lp:magicicada-gui

Proposed by Natalia Bidart
Status: Merged
Approved by: Facundo Batista
Approved revision: 26
Merged at revision: 23
Proposed branch: lp:~nataliabidart/magicicada-gui/set-initial-state
Merge into: lp:magicicada-gui
Diff against target: 520 lines (+169/-100)
3 files modified
magicicada/__init__.py (+60/-35)
magicicada/syncdaemon.py (+7/-0)
magicicada/tests/test_magicicada.py (+102/-65)
To merge this branch: bzr merge lp:~nataliabidart/magicicada-gui/set-initial-state
Reviewer Review Type Date Requested Status
chicharreros Pending
Review via email: mp+25834@code.launchpad.net

Description of the change

GUI updates the initial state based on syncdaemon.current_state.
Also fixed some glitches on buttons sensitivity and visibility.

To post a comment you must log in.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'magicicada/__init__.py'
2--- magicicada/__init__.py 2010-05-22 03:19:12 +0000
3+++ magicicada/__init__.py 2010-05-23 10:42:26 +0000
4@@ -29,7 +29,7 @@
5 gtk2reactor.install()
6
7 from magicicada import syncdaemon
8-from magicicada.helpers import get_data_file, get_builder, NO_OP
9+from magicicada.helpers import get_data_file, get_builder, NO_OP, print_debug
10
11 CONTENT_QUEUE = 'content'
12 META_QUEUE = 'meta'
13@@ -39,7 +39,6 @@
14 STATUS = {
15 'started': _('Service started, click Connect to continue.'),
16 'connected': _('Service connected. Doing internal synchronization...'),
17- 'online': _('Service reached Nirvana.'),
18 }
19
20 def __init__(self, launchpad_available=False, on_destroy=NO_OP,
21@@ -96,6 +95,8 @@
22 self.widget_enabled = lambda w: \
23 w.get_property('visible') and w.is_sensitive()
24
25+ self.update()
26+
27 # GTK callbacks
28
29 def on_main_window_destroy(self, widget, data=None):
30@@ -118,10 +119,8 @@
31 def on_start_clicked(self, widget, data=None):
32 """Start syncdaemon."""
33 self.sd.start()
34- self.start.hide()
35- self.stop.set_sensitive(False)
36- self.stop.show()
37- self.start_loading(self.is_started)
38+ self.start.set_sensitive(False)
39+ self._start_loading(self.is_started)
40
41 def on_stop_clicked(self, widget, data=None):
42 """Stop syncdaemon."""
43@@ -129,28 +128,21 @@
44 self.on_disconnect_clicked(self.disconnect)
45 self.connect.set_sensitive(False)
46
47- self.start.show()
48- self.start.set_sensitive(False)
49- self.stop.hide()
50-
51+ self.stop.set_sensitive(False)
52 self.sd.quit()
53
54 def on_connect_clicked(self, widget, data=None):
55 """Connect syncdaemon."""
56 self.sd.connect()
57- self.connect.hide()
58- self.disconnect.set_sensitive(False)
59- self.disconnect.show()
60- self.start_loading(self.is_connected)
61+ self.connect.set_sensitive(False)
62+ self._start_loading(self.is_connected)
63
64 def on_disconnect_clicked(self, widget, data=None):
65 """Disconnect syncdaemon."""
66- self.connect.show()
67- self.connect.set_sensitive(False)
68- self.disconnect.hide()
69-
70+ self.disconnect.set_sensitive(False)
71 self.sd.disconnect()
72
73+ @print_debug
74 def on_status_icon_activate(self, widget, data=None):
75 """Systray icon was clicked."""
76 if self.main_window.get_property('visible'):
77@@ -158,48 +150,60 @@
78 else:
79 self.main_window.show()
80
81- # DBus callbacks
82+ # SyncDaemon callbacks
83
84 def on_started(self, *args, **kwargs):
85 """Callback'ed when syncadaemon is started."""
86+ self.start.hide()
87+ self.stop.show()
88 self.stop.set_sensitive(True)
89- self.activate_indicator(self.is_started)
90+ self._activate_indicator(self.is_started)
91 self.connect.set_sensitive(True)
92
93 def on_stopped(self, *args, **kwargs):
94 """Callback'ed when syncadaemon is stopped."""
95+ self.stop.hide()
96+ self.start.show()
97 self.start.set_sensitive(True)
98+ self.connect.set_sensitive(False)
99
100- self.activate_indicator(self.is_started, sensitive=False)
101- self.activate_indicator(self.is_connected, sensitive=False)
102- self.activate_indicator(self.is_online, sensitive=False)
103+ self._activate_indicator(self.is_started, sensitive=False)
104+ self._activate_indicator(self.is_connected, sensitive=False)
105+ self._activate_indicator(self.is_online, sensitive=False)
106
107 def on_connected(self, *args, **kwargs):
108 """Callback'ed when syncadaemon is connected."""
109+ self.connect.hide()
110+ self.disconnect.show()
111 self.disconnect.set_sensitive(True)
112- self.activate_indicator(self.is_connected)
113- self.start_loading(self.is_online)
114- self.start_loading(self.is_online)
115+ self._activate_indicator(self.is_connected)
116+ self._start_loading(self.is_online)
117+ self._start_loading(self.is_online)
118
119 def on_disconnected(self, *args, **kwargs):
120 """Callback'ed when syncadaemon is disconnected."""
121+ self.disconnect.hide()
122+ self.connect.show()
123 self.connect.set_sensitive(True)
124
125- self.activate_indicator(self.is_connected, sensitive=False)
126- self.activate_indicator(self.is_online, sensitive=False)
127+ self._activate_indicator(self.is_connected, sensitive=False)
128+ self._activate_indicator(self.is_online, sensitive=False)
129
130 def on_online(self, *args, **kwargs):
131 """Callback'ed when syncadaemon is online."""
132 self.is_online.set_sensitive(True)
133- self.activate_indicator(self.is_online)
134+ self._activate_indicator(self.is_online)
135
136 def on_offline(self, *args, **kwargs):
137 """Callback'ed when syncadaemon is offline."""
138- self.activate_indicator(self.is_online, sensitive=False)
139+ self._activate_indicator(self.is_online, sensitive=False)
140
141- def on_status_changed(self, name, description, is_error, is_connected,
142- is_online, queues, connection):
143+ def on_status_changed(self, name=None, description=None,
144+ is_error=False, is_connected=True,
145+ is_online=True, queues=None, connection=None):
146 """Callback'ed when the SD status changed."""
147+ if description is None:
148+ description = ''
149 self.status_label.set_text(description)
150
151 def _on_queue_changed(self, queue_name, items, *args, **kwargs):
152@@ -211,7 +215,7 @@
153 row = (item.operation, item.path, item.node, item.share)
154 queue_store.append(row)
155
156- if not queue_view.is_sensitive():
157+ if not queue_view.is_sensitive() and len(items) > 0:
158 queue_view.set_sensitive(True)
159
160 def on_content_queue_changed(self, items, *args, **kwargs):
161@@ -224,12 +228,33 @@
162
163 # custom
164
165- def start_loading(self, what):
166+ def _start_loading(self, what):
167 """Set a loader animation on 'what'."""
168 what.set_sensitive(True)
169 what.set_from_animation(self.loading_animation)
170
171- def activate_indicator(self, what, sensitive=True):
172+ def _activate_indicator(self, what, sensitive=True):
173 """Set ready pixbuf on 'what' and make it 'sensitive'."""
174 what.set_sensitive(sensitive)
175 what.set_from_pixbuf(self.active_indicator)
176+
177+ def update(self):
178+ """Update UI based on SD current state."""
179+ current_state = self.sd.current_state
180+
181+ self._activate_indicator(self.is_online,
182+ sensitive=current_state.is_online)
183+
184+ if current_state.is_started:
185+ self.on_started()
186+ if current_state.is_connected:
187+ self.on_connected()
188+ else:
189+ self.on_disconnected()
190+ else:
191+ self.on_disconnected()
192+ self.on_stopped()
193+
194+ self.on_meta_queue_changed(self.sd.meta_queue)
195+ self.on_content_queue_changed(self.sd.content_queue)
196+ self.on_status_changed(description=current_state.description)
197
198=== modified file 'magicicada/syncdaemon.py'
199--- magicicada/syncdaemon.py 2010-05-22 20:27:11 +0000
200+++ magicicada/syncdaemon.py 2010-05-23 10:42:26 +0000
201@@ -85,6 +85,13 @@
202 raise AttributeError("Name not in _attrs: %r" % name)
203 self.__dict__[name] = value
204
205+ def __str__(self):
206+ """String representation."""
207+ result = []
208+ for attr in self._attrs:
209+ result.append("%s=%s" % (attr, getattr(self, attr)))
210+ return "<%s>" % ", ".join(result)
211+
212
213 class SyncDaemon(object):
214 """Interface to Ubuntu One's SyncDaemon."""
215
216=== modified file 'magicicada/tests/test_magicicada.py'
217--- magicicada/tests/test_magicicada.py 2010-05-22 03:19:12 +0000
218+++ magicicada/tests/test_magicicada.py 2010-05-23 10:42:26 +0000
219@@ -18,28 +18,10 @@
220
221 """Tests for magicicada."""
222
223-import gobject
224-import gtk
225-import unittest
226-
227-from functools import wraps
228-
229 from twisted.trial.unittest import TestCase
230
231 from magicicada import MagicicadaUI, CONTENT_QUEUE, META_QUEUE, syncdaemon
232-from magicicada.helpers import get_builder, NO_OP
233-
234-DEFAULT_TIMEOUT = 200
235-
236-def close_window_after(a_test):
237- """Decorator to close the main window after executing f."""
238- @wraps(a_test)
239- def inner(*args, **kwargs):
240- """Inner function."""
241- #gobject.timeout_add(DEFAULT_TIMEOUT, a_test)
242- #self.ui.run()
243-
244- return inner
245+from magicicada.helpers import NO_OP
246
247
248 class FakedSyncdaemon(object):
249@@ -61,13 +43,16 @@
250 self.connect = NO_OP
251 self.disconnect = NO_OP
252
253+ self.current_state = syncdaemon.State()
254+ self.meta_queue = []
255+ self.content_queue = []
256+
257
258 class MagicicadaUITestCase(TestCase):
259 """UI test cases for Magicicada UI."""
260
261 def setUp(self):
262 """Init."""
263- self.builder = get_builder('gui.glade')
264 self.ui = MagicicadaUI(syncdaemon_class=FakedSyncdaemon)
265 self._called = False
266 self.set_called = lambda *_: setattr(self, '_called', True)
267@@ -76,7 +61,6 @@
268 """Cleanup."""
269 self.ui.on_main_window_destroy(self.ui.main_window)
270 self._called = False
271- self.builder = None
272
273 def assert_indicator_disabled(self, indicator):
274 """Test that 'indicator' is not sensitive."""
275@@ -136,8 +120,11 @@
276 self.assertFalse(self.ui.is_online.is_sensitive())
277
278 def test_update_is_correct(self):
279- """Update updates."""
280- # XXX: TODO
281+ """Update is called at startup."""
282+ self.patch(MagicicadaUI, 'update', self.set_called)
283+ self.ui = MagicicadaUI(syncdaemon_class=FakedSyncdaemon)
284+ self.assertTrue(self._called,
285+ 'update was called at startup.')
286
287
288 class MagicicadaUIClickedTestCase(MagicicadaUITestCase):
289@@ -147,9 +134,9 @@
290 """Test on_start_clicked."""
291 self.ui.on_start_clicked(self.ui.start)
292
293- self.assertFalse(self.ui.start.get_property('visible'))
294- self.assertTrue(self.ui.stop.get_property('visible'))
295- self.assertFalse(self.ui.stop.is_sensitive())
296+ self.assertTrue(self.ui.start.get_property('visible'))
297+ self.assertFalse(self.ui.start.is_sensitive())
298+ self.assertFalse(self.ui.stop.get_property('visible'))
299
300 self.assert_indicator_loading(self.ui.is_started)
301 self.assert_indicator_disabled(self.ui.is_connected)
302@@ -167,9 +154,9 @@
303 self.ui.on_started()
304 self.ui.on_connect_clicked(self.ui.connect)
305
306- self.assertFalse(self.ui.connect.get_property('visible'))
307- self.assertTrue(self.ui.disconnect.get_property('visible'))
308- self.assertFalse(self.ui.disconnect.is_sensitive())
309+ self.assertTrue(self.ui.connect.get_property('visible'))
310+ self.assertFalse(self.ui.connect.is_sensitive())
311+ self.assertFalse(self.ui.disconnect.get_property('visible'))
312
313 self.assert_indicator_ready(self.ui.is_started)
314 self.assert_indicator_loading(self.ui.is_connected)
315@@ -191,9 +178,9 @@
316
317 self.assertFalse(self._called, 'on_disconnect_clicked was not called.')
318
319- self.assertTrue(self.ui.start.get_property('visible'))
320- self.assertFalse(self.ui.start.is_sensitive())
321- self.assertFalse(self.ui.stop.get_property('visible'))
322+ self.assertFalse(self.ui.start.get_property('visible'))
323+ self.assertTrue(self.ui.stop.get_property('visible'))
324+ self.assertFalse(self.ui.stop.is_sensitive())
325
326 self.assertTrue(self.ui.connect.get_property('visible'))
327 self.assertFalse(self.ui.connect.is_sensitive())
328@@ -224,9 +211,9 @@
329 self.ui.on_connected()
330 self.ui.on_disconnect_clicked(self.ui.disconnect)
331
332- self.assertTrue(self.ui.connect.get_property('visible'))
333- self.assertFalse(self.ui.connect.is_sensitive())
334- self.assertFalse(self.ui.disconnect.get_property('visible'))
335+ self.assertFalse(self.ui.connect.get_property('visible'))
336+ self.assertTrue(self.ui.disconnect.get_property('visible'))
337+ self.assertFalse(self.ui.disconnect.is_sensitive())
338
339 def test_on_disconnect_clicked_disconnects_syncdaemon(self):
340 """Test on_disconnect_clicked."""
341@@ -268,7 +255,7 @@
342 self.queue_view = getattr(self.ui, '%sq_view' % self.queue)
343
344 def build_some_data(self, limit=5):
345- """Build some data to pass to queue changed callback."""
346+ """Build some data to pass to queue changed callback and related."""
347 items = []
348 for i in xrange(limit):
349 cq = syncdaemon.QueueData(operation='operation %i' % i,
350@@ -277,6 +264,25 @@
351 items.append(cq)
352 return items
353
354+ def assert_queue_store_correct(self, queue_store, items):
355+ """Test that 'queue_store' has 'items' as content."""
356+ msg = 'amount of rows for %s must be %s (got %s).'
357+ self.assertEqual(len(queue_store), len(items),
358+ msg % (queue_store, len(items), len(queue_store)))
359+ # assert rows content equal to items content
360+ tree_iter = queue_store.get_iter_root()
361+ tmp = list(reversed(items))
362+ while tree_iter is not None:
363+ expected = tmp.pop()
364+
365+ op, path, node, share = queue_store.get(tree_iter, 0, 1, 2, 3)
366+ self.assertEqual(expected.operation, op)
367+ self.assertEqual(expected.path, path)
368+ self.assertEqual(expected.node, node)
369+ self.assertEqual(expected.share, share)
370+
371+ tree_iter = queue_store.iter_next(tree_iter)
372+
373 def test_callback_is_connected(self):
374 """Queue changed callback is connected."""
375 self.assertEqual(self.sd_changed, self.ui_changed,
376@@ -293,22 +299,7 @@
377 """On queue changed the view is updated."""
378 items = self.build_some_data()
379 self.sd_changed(items)
380-
381- self.assertEqual(len(self.queue_store), len(items))
382-
383- # assert rows content equal to items content
384- tree_iter = self.queue_store.get_iter_root()
385- tmp = list(reversed(items))
386- while tree_iter is not None:
387- expected = tmp.pop()
388-
389- op, path, node, share = self.queue_store.get(tree_iter, 0, 1, 2, 3)
390- self.assertEqual(expected.operation, op)
391- self.assertEqual(expected.path, path)
392- self.assertEqual(expected.node, node)
393- self.assertEqual(expected.share, share)
394-
395- tree_iter = self.queue_store.iter_next(tree_iter)
396+ self.assert_queue_store_correct(self.queue_store, items)
397
398 def test_model_is_cleared_before_updating(self):
399 """The model is cleared before upadting with a new set of data."""
400@@ -329,6 +320,15 @@
401 self.assertTrue(self.queue_view.is_sensitive(),
402 'Tree view must be enabled on changed.')
403
404+ def test_update_is_correct_for_queue(self):
405+ """Correctly updates the queue state."""
406+ data = self.build_some_data()
407+ setattr(self.ui.sd, '%s_queue' % self.queue, data)
408+
409+ self.ui.update()
410+
411+ self.assert_queue_store_correct(self.queue_store, data)
412+
413
414 class MagicicadaUIContentQueueTestCase(_MagicicadaUIQueueTestCase):
415 """UI test cases for content queue view."""
416@@ -345,10 +345,6 @@
417 class MagicicadaUIStatusTestCase(MagicicadaUITestCase):
418 """UI test cases for the status label."""
419
420- def setUp(self):
421- """Init."""
422- super(MagicicadaUIStatusTestCase, self).setUp()
423-
424 def test_callback_is_connected(self):
425 """Status callback is connected."""
426 self.assertEqual(self.ui.sd.status_changed_callback,
427@@ -363,13 +359,53 @@
428 self.ui.on_status_changed(**kwargs)
429 self.assertEqual(self.ui.status_label.get_text(), kwargs['description'])
430
431+ def test_update_is_correct_for_status_label(self):
432+ """Correctly updates the status label."""
433+ expected = 'dummy test'
434+ self.ui.sd.current_state._set(description=expected)
435+
436+ self.ui.update()
437+
438+ self.assertEqual(expected, self.ui.status_label.get_text())
439+
440
441 class MagicicadaUIConnectionTestCase(MagicicadaUITestCase):
442 """UI test cases for."""
443
444- def setUp(self):
445- """Init."""
446- super(MagicicadaUIConnectionTestCase, self).setUp()
447+ def assert_indicator_is_updated_correctly(self, indicator):
448+ """Test that correctly updates the 'indicator'."""
449+ cs = self.ui.sd.current_state
450+ for expected in (True, False):
451+ cs._set(**{indicator: expected})
452+
453+ self.ui.update()
454+
455+ self.assertEqual(self.ui.widget_enabled(self.ui.start),
456+ not cs.is_started,
457+ 'start must be enabled if not started.')
458+ self.assertEqual(self.ui.widget_enabled(self.ui.stop),
459+ cs.is_started,
460+ 'stop must be enabled if started.')
461+
462+ if cs.is_started:
463+ actual = self.ui.widget_enabled(getattr(self.ui, indicator))
464+ self.assertEqual(expected, actual,
465+ '%s must be %s' % (indicator, expected))
466+
467+ self.assertEqual(self.ui.widget_enabled(self.ui.connect),
468+ not cs.is_connected,
469+ 'connect must be enabled if not connected.')
470+ self.assertEqual(self.ui.widget_enabled(self.ui.disconnect),
471+ cs.is_connected,
472+ 'disconnect must be enabled if connected.')
473+ else:
474+ self.assertFalse(self.ui.connect.is_sensitive(),
475+ 'connect must be disabled when %s' % cs)
476+ self.assertTrue(self.ui.connect.get_property('visible'),
477+ 'connect must be visible when %s' % cs)
478+ actual = self.ui.widget_enabled(getattr(self.ui, indicator))
479+ self.assertFalse(actual,
480+ '%s must be disabled' % (indicator,))
481
482 def test_all_disabled_at_startup(self):
483 """Indicators are all disabled at startup."""
484@@ -391,13 +427,11 @@
485 """On SD started, the UI enables connect and indicator."""
486 # must have click start first
487 self.ui.on_start_clicked(self.ui.start)
488- assert not self.ui.stop.is_sensitive()
489- assert not self.ui.connect.is_sensitive()
490
491 self.ui.on_started()
492
493- self.assertTrue(self.ui.stop.is_sensitive())
494- self.assertTrue(self.ui.connect.is_sensitive())
495+ self.assertTrue(self.ui.widget_enabled(self.ui.stop))
496+ self.assertTrue(self.ui.widget_enabled(self.ui.connect))
497 self.assert_indicator_ready(self.ui.is_started)
498 self.assert_indicator_disabled(self.ui.is_connected)
499 self.assert_indicator_disabled(self.ui.is_online)
500@@ -407,11 +441,10 @@
501 self.ui.on_start_clicked(self.ui.start)
502 self.ui.on_started()
503 self.ui.on_connect_clicked(self.ui.start)
504- assert not self.ui.disconnect.is_sensitive()
505
506 self.ui.on_connected()
507
508- self.assertTrue(self.ui.disconnect.is_sensitive())
509+ self.assertTrue(self.ui.widget_enabled(self.ui.disconnect))
510 self.assert_indicator_ready(self.ui.is_started)
511 self.assert_indicator_ready(self.ui.is_connected)
512 self.assert_indicator_loading(self.ui.is_online)
513@@ -471,3 +504,7 @@
514 self.assert_indicator_ready(self.ui.is_connected)
515 self.assert_indicator_disabled(self.ui.is_online)
516
517+ def test_update_is_correct_for_indicators_and_buttons(self):
518+ """Correctly updates the indicators and buttons state."""
519+ for i in ('is_started', 'is_connected', 'is_online'):
520+ self.assert_indicator_is_updated_correctly(i)

Subscribers

People subscribed via source and target branches

to all changes: