Merge lp:~dobey/ubuntuone-client/update-4-0 into lp:ubuntuone-client/stable-4-0

Proposed by dobey
Status: Merged
Merged at revision: 1265
Proposed branch: lp:~dobey/ubuntuone-client/update-4-0
Merge into: lp:ubuntuone-client/stable-4-0
Diff against target: 783 lines (+243/-113)
14 files modified
tests/platform/messaging/test_linux.py (+9/-1)
tests/platform/sync_menu/test_common.py (+49/-0)
tests/platform/sync_menu/test_linux.py (+63/-18)
tests/status/test_aggregator.py (+18/-2)
tests/syncdaemon/test_main.py (+0/-14)
tests/syncdaemon/test_status_listener.py (+2/-2)
ubuntuone/platform/__init__.py (+4/-3)
ubuntuone/platform/filesystem_notifications/monitor/__init__.py (+2/-2)
ubuntuone/platform/messaging/linux.py (+7/-2)
ubuntuone/platform/sync_menu/common.py (+6/-11)
ubuntuone/platform/sync_menu/linux.py (+50/-28)
ubuntuone/status/aggregator.py (+28/-15)
ubuntuone/syncdaemon/main.py (+3/-13)
ubuntuone/syncdaemon/status_listener.py (+2/-2)
To merge this branch: bzr merge lp:~dobey/ubuntuone-client/update-4-0
Reviewer Review Type Date Requested Status
Roberto Alsina (community) Approve
Review via email: mp+127586@code.launchpad.net

Commit message

[Rodney Dawes]

    Start the control panel, not the old installer which no longer exists.
    Disable the session inhibitor to prevent bug #737620 from happening.

[Mike McCracken]

    - Fix dummy sync menu implementation for windows and darwin. (LP: #1055840)
    - Make fsevents root daemon the default fs monitor for darwin, leave other platforms alone.
    - Send 'darwin' to server as platform name in auth. (LP: #1037435)

[Diego Sarmentero]

    - Sort items based on the written value, to prioritize the files being transferred (LP: #1052956).
    - Using a timer event that doesn't fire continuously if another update timer is in progress (LP: #1052922).

To post a comment you must log in.
Revision history for this message
Roberto Alsina (ralsina) :
review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'tests/platform/messaging/test_linux.py'
2--- tests/platform/messaging/test_linux.py 2012-05-02 20:14:50 +0000
3+++ tests/platform/messaging/test_linux.py 2012-10-02 20:28:28 +0000
4@@ -39,7 +39,7 @@
5 from twisted.internet import defer
6 from twisted.trial.unittest import TestCase
7 from ubuntuone.devtools.testcases import skipIf
8-
9+from ubuntuone.platform.messaging import linux
10 from ubuntuone.platform.messaging.linux import (
11 Messaging,
12 _server_callback,
13@@ -160,3 +160,11 @@
14 actual_callback = messaging.create_callback()
15 actual_callback(messaging.indicators[-1])
16 self.assertEquals(0, len(messaging.indicators))
17+
18+ def test_open_u1(self):
19+ """Check that the proper action is executed."""
20+ data = []
21+
22+ self.patch(linux.glib, "spawn_command_line_async", data.append)
23+ _server_callback(None)
24+ self.assertEqual(data, ['ubuntuone-control-panel-qt'])
25
26=== added file 'tests/platform/sync_menu/test_common.py'
27--- tests/platform/sync_menu/test_common.py 1970-01-01 00:00:00 +0000
28+++ tests/platform/sync_menu/test_common.py 2012-10-02 20:28:28 +0000
29@@ -0,0 +1,49 @@
30+# -*- coding: utf-8 *-*
31+#
32+# Copyright 2012 Canonical Ltd.
33+#
34+# This program is free software: you can redistribute it and/or modify it
35+# under the terms of the GNU General Public License version 3, as published
36+# by the Free Software Foundation.
37+#
38+# This program is distributed in the hope that it will be useful, but
39+# WITHOUT ANY WARRANTY; without even the implied warranties of
40+# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
41+# PURPOSE. See the GNU General Public License for more details.
42+#
43+# You should have received a copy of the GNU General Public License along
44+# with this program. If not, see <http://www.gnu.org/licenses/>.
45+#
46+# In addition, as a special exception, the copyright holders give
47+# permission to link the code of portions of this program with the
48+# OpenSSL library under certain conditions as described in each
49+# individual source file, and distribute linked combinations
50+# including the two.
51+# You must obey the GNU General Public License in all respects
52+# for all of the code used other than OpenSSL. If you modify
53+# file(s) with this exception, you may extend this exception to your
54+# version of the file(s), but you are not obligated to do so. If you
55+# do not wish to do so, delete this exception statement from your
56+# version. If you delete this exception statement from all source
57+# files in the program, then also delete it here.
58+"""Test the common dummy Sync Menu implementation for win32/darwin."""
59+
60+from collections import Callable
61+
62+from twisted.trial.unittest import TestCase
63+
64+from ubuntuone.platform.sync_menu import common
65+
66+
67+class SyncMenuDummyTestCase(TestCase):
68+ """Test the SyncMenu."""
69+
70+ def test_dummy_support(self):
71+ """Can we create a Dummy with the same #args as the real obj."""
72+ dummy = common.UbuntuOneSyncMenu(1, 2)
73+ self.assertIsInstance(dummy, common.UbuntuOneSyncMenu)
74+
75+ def test_dummy_has_update_transfers(self):
76+ """Check that the dummy has the proper methods required by the API."""
77+ dummy = common.UbuntuOneSyncMenu(1, 2)
78+ self.assertIsInstance(dummy.update_transfers, Callable)
79
80=== modified file 'tests/platform/sync_menu/test_linux.py'
81--- tests/platform/sync_menu/test_linux.py 2012-09-21 14:09:05 +0000
82+++ tests/platform/sync_menu/test_linux.py 2012-10-02 20:28:28 +0000
83@@ -28,6 +28,7 @@
84 # files in the program, then also delete it here.
85 """Test the Sync Menu."""
86
87+import time
88 from collections import Callable
89
90 from twisted.internet import defer
91@@ -57,18 +58,20 @@
92 return self.uploading_data
93
94
95-class FakeStatusListener(object):
96- """Fake StatusListener."""
97-
98- def __init__(self):
99- self.status_frontend = FakeStatusFrontend()
100-
101-
102-class FakeMain(object):
103- """Fake Main."""
104-
105- def __init__(self):
106- self.status_listener = FakeStatusListener()
107+class FakeTimer(object):
108+ """Fake Timer."""
109+
110+ def __init__(self, delay):
111+ self.delay = delay
112+ self.callback = None
113+
114+ def addCallback(self, callback):
115+ """Add callback."""
116+ self.callback = callback
117+
118+
119+class FakeSyncdaemonService(object):
120+ """Fake SyncdaemonService."""
121
122
123 class FakeSyncMenuApp(object):
124@@ -101,10 +104,10 @@
125 dummy = linux.DummySyncMenu('random', 'args')
126 self.assertIsInstance(dummy, linux.DummySyncMenu)
127
128- def test_dummy_has_start_timer(self):
129+ def test_dummy_has_update_transfers(self):
130 """Check that the dummy has the proper methods required by the API."""
131 dummy = linux.DummySyncMenu('random', 'args')
132- self.assertIsInstance(dummy.start_timer, Callable)
133+ self.assertIsInstance(dummy.update_transfers, Callable)
134
135
136 class SyncMenuTestCase(TestCase):
137@@ -117,12 +120,13 @@
138 yield super(SyncMenuTestCase, self).setUp()
139 self.patch(linux.SyncMenu, "App", FakeSyncMenuApp)
140 FakeSyncMenuApp.clean()
141- self.main = FakeMain()
142- self.status_frontend = self.main.status_listener.status_frontend
143+ self.syncdaemon_service = FakeSyncdaemonService()
144+ self.status_frontend = FakeStatusFrontend()
145 self._paused = False
146 self.patch(sync_menu.UbuntuOneSyncMenu, "change_sync_status",
147 self._change_sync_status)
148- self.sync_menu = sync_menu.UbuntuOneSyncMenu(self.main)
149+ self.sync_menu = sync_menu.UbuntuOneSyncMenu(self.status_frontend,
150+ self.syncdaemon_service)
151
152 def _change_sync_status(self, *args):
153 """Fake change_sync_status."""
154@@ -170,7 +174,7 @@
155
156 self.patch(linux.glib, "spawn_command_line_async", data.append)
157 self.sync_menu.open_control_panel()
158- self.assertEqual(data, ['ubuntuone-installer'])
159+ self.assertEqual(data, ['ubuntuone-control-panel-qt'])
160
161 def test_go_to_web(self):
162 """Check that the proper action is executed."""
163@@ -330,3 +334,44 @@
164 self.assertEqual(item.property_get_int(
165 linux.SyncMenu.PROGRESS_MENUITEM_PROP_PERCENT_DONE),
166 percentage)
167+
168+ def test_transfers_order(self):
169+ """Check that the proper transfers are shown first."""
170+ data_current = [
171+ ('file0', 1200, 610),
172+ ('file1', 3000, 400),
173+ ('file2', 2000, 100),
174+ ('file3', 2500, 150),
175+ ('file4', 2500, 950),
176+ ('file5', 3500, 550),
177+ ('file6', 1000, 600),
178+ ('file7', 5000, 4600)]
179+ expected = [
180+ ('file7', 5000, 4600),
181+ ('file4', 2500, 950),
182+ ('file0', 1200, 610),
183+ ('file6', 1000, 600),
184+ ('file5', 3500, 550)]
185+ self.status_frontend.uploading_data = data_current
186+ self.sync_menu.transfers.update_progress()
187+ children = self.sync_menu.transfers.get_children()
188+ # The menu should only show 5 current transfers.
189+ self.assertEqual(len(children), 5)
190+ for i, item in enumerate(children):
191+ text = item.property_get(linux.Dbusmenu.MENUITEM_PROP_LABEL)
192+ percentage = item.property_get_int(
193+ linux.SyncMenu.PROGRESS_MENUITEM_PROP_PERCENT_DONE)
194+ name, size, written = expected[i]
195+ percentage_expected = written * 100 / size
196+ self.assertEqual(text, name)
197+ self.assertEqual(percentage, percentage_expected)
198+
199+ def test_update_transfers_delay(self):
200+ """Check that the timer is being handle properly."""
201+ self.patch(linux.status.aggregator, "Timer", FakeTimer)
202+ self.sync_menu.next_update = time.time()
203+ self.sync_menu.update_transfers()
204+ self.sync_menu.timer = None
205+ self.sync_menu.next_update = time.time() * 2
206+ self.sync_menu.update_transfers()
207+ self.assertEqual(self.sync_menu.timer.delay, 3)
208
209=== modified file 'tests/status/test_aggregator.py'
210--- tests/status/test_aggregator.py 2012-08-20 13:18:43 +0000
211+++ tests/status/test_aggregator.py 2012-10-02 20:28:28 +0000
212@@ -39,6 +39,7 @@
213
214 from contrib.testing.testcase import BaseTwistedTestCase
215 from ubuntuone.devtools.handlers import MementoHandler
216+from ubuntuone.devtools.testcases import skipTest
217 from ubuntuone.status import aggregator
218 from ubuntuone.status.notification import AbstractNotification
219 from ubuntuone.status.messaging import AbstractMessaging
220@@ -576,7 +577,6 @@
221 """Initialize this test instance."""
222 yield super(ProgressBarTestCase, self).setUp()
223 self.patch(aggregator, "UbuntuOneLauncher", FakeLauncher)
224- self.patch(aggregator.session, "Inhibitor", FakeInhibitor)
225 self.clock = PatchedClock()
226 self.bar = aggregator.ProgressBar(clock=self.clock)
227 self.addCleanup(self.bar.cleanup)
228@@ -662,6 +662,7 @@
229 self.assertFalse(self.bar.visible)
230 self.assertFalse(self.bar.launcher.progress_visible)
231
232+ @skipTest('Inhibitor is disabled to prevent bug #737620')
233 @defer.inlineCallbacks
234 def test_progress_made_inhibits_logout_suspend(self):
235 """Suspend and logout are inhibited when the progressbar is shown."""
236@@ -670,6 +671,7 @@
237 inhibitor = yield self.bar.inhibitor_defer
238 self.assertEqual(inhibitor.flags, expected)
239
240+ @skipTest('Inhibitor is disabled to prevent bug #737620')
241 @defer.inlineCallbacks
242 def test_completed_uninhibits_logout_suspend(self):
243 """Suspend and logout are uninhibited when all has completed."""
244@@ -1291,7 +1293,6 @@
245 self.patch(aggregator, "ToggleableNotification",
246 FakeNotificationSingleton())
247 self.patch(aggregator, "UbuntuOneLauncher", FakeLauncher)
248- self.patch(aggregator.session, "Inhibitor", FakeInhibitor)
249 clock = PatchedClock()
250 self.status_frontend = aggregator.StatusFrontend(clock=clock)
251 self.aggregator = self.status_frontend.aggregator
252@@ -1314,6 +1315,21 @@
253 self.assertEqual({}, self.aggregator.to_do)
254 self.assertIdentical(None, self.aggregator.queue_done_timer)
255
256+ def test_register_progress_listener(self):
257+ """Check that register listener handles properly additions."""
258+
259+ def fake_callback():
260+ """Do nothing."""
261+
262+ self.aggregator.register_progress_listener(fake_callback)
263+ self.assertEqual(len(self.aggregator.progress_listeners), 1)
264+
265+ def test_register_progress_listener_fail(self):
266+ """Check that register listener fails with not Callable objects."""
267+ self.assertRaises(TypeError,
268+ self.aggregator.register_progress_listener, [])
269+ self.assertEqual(len(self.aggregator.progress_listeners), 0)
270+
271 def assertMiscCommandQueued(self, fc):
272 """Assert that some command was queued."""
273 self.assertEqual(len(self.aggregator.to_do), 1)
274
275=== modified file 'tests/syncdaemon/test_main.py'
276--- tests/syncdaemon/test_main.py 2012-09-19 17:23:02 +0000
277+++ tests/syncdaemon/test_main.py 2012-10-02 20:28:28 +0000
278@@ -70,19 +70,6 @@
279 return defer.succeed(None)
280
281
282-class FakedSyncMenu(object):
283- """Do nothing."""
284-
285- def __init__(self, *args, **kwargs):
286- self.arguments = (args, kwargs)
287-
288- def update_progress(self):
289- """Do nothing."""
290-
291- def start_timer(self):
292- """Do nothing."""
293-
294-
295 class MainTests(BaseTwistedTestCase):
296 """ Basic tests to check main.Main """
297
298@@ -100,7 +87,6 @@
299 self.patch(main_mod.event_logging, "get_listener", lambda *a: None)
300 # no status listener by default
301 self.patch(main_mod.status_listener, "get_listener", lambda *a: None)
302- self.patch(main_mod.sync_menu, "UbuntuOneSyncMenu", FakedSyncMenu)
303
304 self.handler = MementoHandler()
305 self.handler.setLevel(logging.DEBUG)
306
307=== modified file 'tests/syncdaemon/test_status_listener.py'
308--- tests/syncdaemon/test_status_listener.py 2012-04-09 20:07:05 +0000
309+++ tests/syncdaemon/test_status_listener.py 2012-10-02 20:28:28 +0000
310@@ -84,7 +84,7 @@
311 callback(args)
312
313 listener = Listener()
314- setattr(listener, 'handle_'+event, listener._handle_event)
315+ setattr(listener, 'handle_' + event, listener._handle_event)
316 event_q.subscribe(listener)
317 return listener
318
319@@ -92,7 +92,7 @@
320 class FakeStatusFrontend(object):
321 """A fake status frontend."""
322
323- def __init__(self):
324+ def __init__(self, *args, **kwargs):
325 """Initialize this instance."""
326 self.call_log = []
327
328
329=== modified file 'ubuntuone/platform/__init__.py'
330--- ubuntuone/platform/__init__.py 2012-08-06 19:18:57 +0000
331+++ ubuntuone/platform/__init__.py 2012-10-02 20:28:28 +0000
332@@ -33,11 +33,12 @@
333
334 from dirspec.utils import user_home
335
336-# very hackish way to avoid "import *" to satisfy pyflakes
337-# and to avoid import ubuntuone.platform.X as source (it wont work)
338-
339+# define a platform string separate from sys.platform to be sent to
340+# the server for metrics in ActionQueue.authenticate().
341 if sys.platform == "win32":
342 platform = "win32"
343+elif sys.platform == "darwin":
344+ platform = "darwin"
345 else:
346 platform = "linux"
347
348
349=== modified file 'ubuntuone/platform/filesystem_notifications/monitor/__init__.py'
350--- ubuntuone/platform/filesystem_notifications/monitor/__init__.py 2012-08-28 07:58:50 +0000
351+++ ubuntuone/platform/filesystem_notifications/monitor/__init__.py 2012-10-02 20:28:28 +0000
352@@ -60,8 +60,8 @@
353 )
354
355 FILEMONITOR_IDS = {
356- DEFAULT_MONITOR: common.FilesystemMonitor,
357- 'daemon': darwin.fsevents_daemon.FilesystemMonitor,
358+ DEFAULT_MONITOR: darwin.fsevents_daemon.FilesystemMonitor,
359+ 'macfsevents': common.FilesystemMonitor,
360 }
361 ACTIONS = darwin.fsevents_client.ACTIONS
362 else:
363
364=== modified file 'ubuntuone/platform/messaging/linux.py'
365--- ubuntuone/platform/messaging/linux.py 2012-04-30 17:33:18 +0000
366+++ ubuntuone/platform/messaging/linux.py 2012-10-02 20:28:28 +0000
367@@ -34,6 +34,7 @@
368 # of them are available, we should fall back to silently discarding
369 # messages.
370
371+import logging
372 import sys
373
374 indicate = None
375@@ -61,6 +62,8 @@
376
377 from ubuntuone.status.messaging import AbstractMessaging
378
379+logger = logging.getLogger("ubuntuone.platform.Messaging")
380+
381
382 def open_volumes():
383 """Open the control panel to the shares tab."""
384@@ -69,8 +72,10 @@
385
386 def _server_callback(the_indicator, message_time=None):
387 """Open the control panel to the shares tab."""
388- glib.spawn_command_line_async('ubuntuone-installer')
389-# pylint: enable=W0613
390+ try:
391+ glib.spawn_command_line_async('ubuntuone-control-panel-qt')
392+ except glib.GError as e:
393+ logger.warning('Failed to open the control panel: %s' % e)
394
395
396 class Messaging(AbstractMessaging):
397
398=== modified file 'ubuntuone/platform/sync_menu/common.py'
399--- ubuntuone/platform/sync_menu/common.py 2012-09-18 16:29:22 +0000
400+++ ubuntuone/platform/sync_menu/common.py 2012-10-02 20:28:28 +0000
401@@ -26,18 +26,13 @@
402 # do not wish to do so, delete this exception statement from your
403 # version. If you delete this exception statement from all source
404 # files in the program, then also delete it here.
405-"""Use SyncMenu lib to integrate U1 with the Systray Sync Icon."""
406+"""Dummy implementation of sync_menu lib for win32 and darwin."""
407
408
409 class UbuntuOneSyncMenu(object):
410 """Integrate U1 with the Ubuntu Sync Menu."""
411-
412- def __init__(self, *args):
413- self.transfers = DummyTransfersMenu()
414-
415-
416-class DummyTransfersMenu(object):
417- """Dummy Transfers Menu."""
418-
419- def start_timer(self):
420- """Empty start timer, this is not needed on windows."""
421+ def __init__(self, status, syncdaemon_service):
422+ """Match #args of linux syncmenu and do nothing."""
423+
424+ def update_transfers(self):
425+ """Do nothing."""
426
427=== modified file 'ubuntuone/platform/sync_menu/linux.py'
428--- ubuntuone/platform/sync_menu/linux.py 2012-09-21 12:39:52 +0000
429+++ ubuntuone/platform/sync_menu/linux.py 2012-10-02 20:28:28 +0000
430@@ -29,8 +29,12 @@
431 """Use SyncMenu lib to integrate U1 with the Systray Sync Icon."""
432
433 import gettext
434+import logging
435+import time
436 import sys
437 import webbrowser
438+from collections import OrderedDict
439+from operator import itemgetter
440
441 glib = None
442 try:
443@@ -50,10 +54,12 @@
444 use_syncmenu = True
445 except:
446 use_syncmenu = False
447-from twisted.internet import reactor
448
449 from ubuntuone.clientdefs import GETTEXT_PACKAGE
450-
451+from ubuntuone import status
452+
453+
454+logger = logging.getLogger("ubuntuone.platform.SyncMenu")
455
456 Q_ = lambda string: gettext.dgettext(GETTEXT_PACKAGE, string)
457
458@@ -63,6 +69,7 @@
459 MORE_STORAGE = Q_("Get More Space")
460 GET_HELP = Q_("Get Help on the Web")
461
462+DELAY_BETWEEN_UPDATES = 3
463 UBUNTUONE_LINK = u'https://one.ubuntu.com/'
464 DASHBOARD = UBUNTUONE_LINK + u'dashboard/'
465 HELP_LINK = UBUNTUONE_LINK + u'support/'
466@@ -72,11 +79,12 @@
467 class UbuntuOneSyncMenuLinux(object):
468 """Integrate U1 with the Ubuntu Sync Menu."""
469
470- def __init__(self, main):
471+ def __init__(self, status, syncdaemon_service):
472 """Initialize menu."""
473- self._main = main
474- self.status_listener = main.status_listener
475+ self._syncdaemon_service = syncdaemon_service
476 self._paused = False
477+ self.timer = None
478+ self.next_update = time.time()
479 self.root_menu = Dbusmenu.Menuitem()
480
481 self.open_u1 = Dbusmenu.Menuitem()
482@@ -86,7 +94,7 @@
483 self.go_to_web.property_set(Dbusmenu.MENUITEM_PROP_LABEL,
484 GO_TO_WEB)
485
486- self.transfers = TransfersMenu(self.status_listener)
487+ self.transfers = TransfersMenu(status)
488 self.transfers.property_set(Dbusmenu.MENUITEM_PROP_LABEL,
489 TRANSFERS)
490
491@@ -121,22 +129,21 @@
492 self.app.set_menu(self.server)
493 self.app.connect("notify::paused", self.change_sync_status)
494
495- def start_timer(self):
496- """Start the transfers timer."""
497- self.transfers.start_timer()
498-
499 def change_sync_status(self, *args):
500 """Triggered when the sync status is changed fromm the menu."""
501 if self._paused:
502- self._main.external.connect()
503+ self._syncdaemon_service.connect()
504 self._paused = False
505 else:
506- self._main.external.disconnect()
507+ self._syncdaemon_service.disconnect()
508 self._paused = True
509
510 def open_control_panel(self, *args):
511 """Open the Ubuntu One Control Panel."""
512- glib.spawn_command_line_async('ubuntuone-installer')
513+ try:
514+ glib.spawn_command_line_async('ubuntuone-control-panel-qt')
515+ except glib.GError as e:
516+ logger.warning('Failed to open the control panel: %s.' % e)
517
518 def open_go_to_web(self, *args):
519 """Open the Ubunto One Help Page"""
520@@ -150,36 +157,49 @@
521 """Open the Ubunto One Help Page"""
522 webbrowser.open(GET_STORAGE_LINK)
523
524+ def _timeout(self, result):
525+ """The aggregating timer has expired, so update the UI."""
526+ self.next_update = int(time.time()) + DELAY_BETWEEN_UPDATES
527+ self.transfers.update_progress()
528+ self.timer = None
529+
530+ def update_transfers(self):
531+ """Set up a timer if there isn't one ticking and update the ui."""
532+ if not self.timer:
533+ logger.debug("Updating Transfers.")
534+ delay = int(max(0, min(DELAY_BETWEEN_UPDATES,
535+ self.next_update - time.time())))
536+ self.timer = status.aggregator.Timer(delay)
537+ self.timer.addCallback(self._timeout)
538+
539
540 class TransfersMenu(Dbusmenu.Menuitem):
541 """Menu that handles the recent and current transfers."""
542
543- def __init__(self, listener):
544+ def __init__(self, status_frontend):
545 super(TransfersMenu, self).__init__()
546- self.listener = listener
547+ self.status_frontend = status_frontend
548 self.uploading = {}
549 self.previous_transfers = []
550 self._transfers_items = {}
551 self._uploading_items = {}
552
553- def start_timer(self):
554- """Trigger an update in one second."""
555- self.update_progress()
556- reactor.callLater(3, self.start_timer)
557-
558 def update_progress(self):
559 """Update the list of recent transfers and current transfers."""
560- current_transfers = self.listener.status_frontend.recent_transfers()
561- uploading_data = {}
562- for filename, size, written in \
563- self.listener.status_frontend.files_uploading():
564+ recent_transfers = self.status_frontend.recent_transfers()
565+ current_transfers = self.status_frontend.files_uploading()
566+ current_transfers.sort(key=itemgetter(2))
567+ current_transfers.reverse()
568+ uploading_data = OrderedDict()
569+ for filename, size, written in current_transfers:
570 uploading_data[filename] = (size, written)
571
572 temp_transfers = {}
573- if current_transfers != self.previous_transfers:
574+ if recent_transfers != self.previous_transfers:
575+ logger.debug("Update recent transfers with: %r", recent_transfers)
576 for item_transfer in self._transfers_items:
577 self.child_delete(self._transfers_items[item_transfer])
578- for item in current_transfers:
579+ for item in recent_transfers:
580 recent_file = Dbusmenu.Menuitem()
581 recent_file.property_set(Dbusmenu.MENUITEM_PROP_LABEL,
582 item)
583@@ -197,6 +217,8 @@
584 upload_item.property_set_int(
585 SyncMenu.PROGRESS_MENUITEM_PROP_PERCENT_DONE,
586 percentage)
587+ logger.debug("Current transfer %s progress update: %r",
588+ item, percentage)
589 items_added += 1
590 else:
591 self.child_delete(self._uploading_items[item])
592@@ -216,6 +238,7 @@
593 uploading_file.property_set_int(
594 SyncMenu.PROGRESS_MENUITEM_PROP_PERCENT_DONE,
595 percentage)
596+ logger.debug("Current transfer %s created", item)
597 self.child_append(uploading_file)
598 self._uploading_items[item] = uploading_file
599 items_added += 1
600@@ -227,8 +250,7 @@
601 def __init__(self, *args, **kwargs):
602 """Initialize menu."""
603
604- def start_timer(self):
605+ def update_transfers(self):
606 """Do nothing."""
607
608-
609 UbuntuOneSyncMenu = UbuntuOneSyncMenuLinux if use_syncmenu else DummySyncMenu
610
611=== modified file 'ubuntuone/status/aggregator.py'
612--- ubuntuone/status/aggregator.py 2012-08-16 12:00:12 +0000
613+++ ubuntuone/status/aggregator.py 2012-10-02 20:28:28 +0000
614@@ -33,7 +33,7 @@
615 import itertools
616 import operator
617 import os
618-from collections import deque
619+from collections import deque, Callable
620
621 import gettext
622
623@@ -41,7 +41,10 @@
624
625 from ubuntuone.clientdefs import GETTEXT_PACKAGE
626 from ubuntuone.status.logger import logger
627-from ubuntuone.platform import session, notification
628+from ubuntuone.platform import (
629+ notification,
630+ sync_menu
631+)
632 from ubuntuone.platform.messaging import Messaging
633 from ubuntuone.platform.launcher import UbuntuOneLauncher, DummyLauncher
634
635@@ -529,7 +532,6 @@
636 progress = 0.0
637 updates_delay = 0.1
638 timer = None
639- inhibitor_defer = None
640
641 def __init__(self, clock=reactor):
642 """Initialize this instance."""
643@@ -559,9 +561,6 @@
644 self.visible = True
645 self.launcher.show_progressbar()
646 logger.debug("progressbar shown")
647- if self.inhibitor_defer is None:
648- self.inhibitor_defer = session.inhibit_logout_suspend(
649- FILE_SYNC_IN_PROGRESS)
650 if not self.timer:
651 self.timer = Timer(self.updates_delay, clock=self.clock)
652 self.timer.addCallback(self._timeout)
653@@ -572,14 +571,6 @@
654 self.visible = False
655 self.launcher.hide_progressbar()
656 logger.debug("progressbar hidden")
657- if self.inhibitor_defer is not None:
658-
659- def inhibitor_callback(inhibitor):
660- """The inhibitor was found, so cancel it."""
661- self.inhibitor_defer = None
662- return inhibitor.cancel()
663-
664- self.inhibitor_defer.addCallback(inhibitor_callback)
665
666
667 class FinalStatusBubble(object):
668@@ -625,6 +616,7 @@
669 self.progress = {}
670 self.to_do = {}
671 self.recent_transfers = deque(maxlen=5)
672+ self.progress_listeners = []
673
674 def get_notification(self):
675 """Create a new toggleable notification object."""
676@@ -655,6 +647,13 @@
677 self.to_do = {}
678 # pylint: enable=W0201
679
680+ def register_progress_listener(self, listener):
681+ """Register a callable object to be notified."""
682+ if isinstance(listener, Callable):
683+ self.progress_listeners.append(listener)
684+ else:
685+ raise TypeError("Callable object expected.")
686+
687 def get_discovery_message(self):
688 """Get the text for the discovery bubble."""
689 lines = []
690@@ -716,6 +715,8 @@
691 progress = float(
692 sum(self.progress.values())) / sum(self.to_do.values())
693 self.progress_bar.set_progress(progress)
694+ for listener in self.progress_listeners:
695+ listener()
696
697 def download_started(self, command):
698 """A download just started."""
699@@ -801,13 +802,25 @@
700 class StatusFrontend(object):
701 """Frontend for the status aggregator, used by the StatusListener."""
702
703- def __init__(self, clock=reactor):
704+ def __init__(self, clock=reactor, service=None):
705 """Initialize this instance."""
706 self.aggregator = StatusAggregator(clock=clock)
707 self.notification = self.aggregator.get_notification()
708 self.messaging = Messaging()
709 self.quota_timer = None
710
711+ self.syncdaemon_service = service
712+ self.sync_menu = None
713+ self.start_sync_menu()
714+
715+ def start_sync_menu(self):
716+ """Create the sync menu and register the progress listener."""
717+ if self.syncdaemon_service is not None:
718+ self.sync_menu = sync_menu.UbuntuOneSyncMenu(self,
719+ self.syncdaemon_service)
720+ self.aggregator.register_progress_listener(
721+ self.sync_menu.update_transfers)
722+
723 def recent_transfers(self):
724 """Return a tuple with the recent transfers paths."""
725 return list(self.aggregator.recent_transfers)
726
727=== modified file 'ubuntuone/syncdaemon/main.py'
728--- ubuntuone/syncdaemon/main.py 2012-09-19 17:23:02 +0000
729+++ ubuntuone/syncdaemon/main.py 2012-10-02 20:28:28 +0000
730@@ -48,10 +48,7 @@
731 volume_manager,
732 )
733 from ubuntuone import syncdaemon, clientdefs
734-from ubuntuone.platform import (
735- event_logging,
736- sync_menu,
737-)
738+from ubuntuone.platform import event_logging
739 from ubuntuone.syncdaemon import status_listener
740 from ubuntuone.syncdaemon.interaction_interfaces import SyncdaemonService
741 from ubuntuone.syncdaemon.states import StateManager, QueueManager
742@@ -159,14 +156,6 @@
743 self.mark = task.LoopingCall(self.log_mark)
744 self.mark.start(mark_interval)
745
746- self.sync_menu = None
747- self.start_sync_menu()
748-
749- def start_sync_menu(self):
750- """Create the sync menu and run the loop."""
751- self.sync_menu = sync_menu.UbuntuOneSyncMenu(self)
752- self.sync_menu.start_timer()
753-
754 def start_event_logger(self):
755 """Start the event logger if it's available for this platform."""
756 self.eventlog_listener = event_logging.get_listener(self.fs, self.vm)
757@@ -176,7 +165,8 @@
758
759 def start_status_listener(self):
760 """Start the status listener if it is configured to start."""
761- self.status_listener = status_listener.get_listener(self.fs, self.vm)
762+ self.status_listener = status_listener.get_listener(self.fs, self.vm,
763+ self.external)
764 # subscribe to EQ, to be unsubscribed in shutdown
765 if self.status_listener:
766 self.event_q.subscribe(self.status_listener)
767
768=== modified file 'ubuntuone/syncdaemon/status_listener.py'
769--- ubuntuone/syncdaemon/status_listener.py 2012-08-10 12:49:46 +0000
770+++ ubuntuone/syncdaemon/status_listener.py 2012-10-02 20:28:28 +0000
771@@ -48,10 +48,10 @@
772 return True
773
774
775-def get_listener(fsm, vm):
776+def get_listener(fsm, vm, syncdaemon_service=None):
777 """Return an instance of the status listener, or None if turned off."""
778 if should_start_listener():
779- status_frontend = StatusFrontend()
780+ status_frontend = StatusFrontend(service=syncdaemon_service)
781 return StatusListener(fsm, vm, status_frontend)
782 else:
783 return None

Subscribers

People subscribed via source and target branches

to all changes: