173
175
"""A message if this is the only event of this type."""
174
176
return self.MESSAGE_ONE
176
def many(self, events):
177
"""A message if there are many events of this type."""
178
format_args = {"event_count": len(events)}
179
return self.MESSAGE_MANY % format_args
182
179
class FilePublishingStatus(StatusEvent):
183
180
"""Files that are made public with a url."""
185
182
MESSAGE_ONE = Q_("A file was just made public at %(new_public_url)s")
186
MESSAGE_MANY = Q_("%(event_count)d files were just made public")
190
187
"""Show the url if only one event of this type."""
191
188
return self.MESSAGE_ONE % self.kwargs
190
def many(self, events):
191
"""Show the number of files if many event of this type."""
192
no_of_files = len(events)
195
"%(event_count)d file was just made public.",
196
"%(event_count)d files were just made public.",
197
no_of_files) % {'event_count': no_of_files}
194
200
class FileUnpublishingStatus(StatusEvent):
195
201
"""Files that have stopped being published."""
197
203
MESSAGE_ONE = Q_("A file is no longer published")
198
MESSAGE_MANY = Q_("%(event_count)d files are no longer published")
206
def many(self, events):
207
"""Show the number of files if many event of this type."""
208
no_of_files = len(events)
211
"%(event_count)d file is no longer published.",
212
"%(event_count)d files are no longer published.",
213
no_of_files) % {'event_count': no_of_files}
202
216
class FolderAvailableStatus(StatusEvent):
203
217
"""Folders available for subscription."""
205
MESSAGE_MANY = Q_("Found %(event_count)d new cloud folders.")
221
def many(self, events):
222
"""Show the number of files if many event of this type."""
223
no_of_files = len(events)
226
"Found %(event_count)d new cloud folder.",
227
"Found %(event_count)d new cloud folders.",
228
no_of_files) % {'event_count': no_of_files}
209
231
class ShareAvailableStatus(FolderAvailableStatus):
210
232
"""A Share is available for subscription."""
444
467
def _popup(self):
445
468
"""Display the notification."""
469
if not self.connected:
446
471
text = self.status_aggregator.get_discovery_message()
447
self.notification.send_notification(UBUNTUONE_TITLE, text)
448
self.status_aggregator.restart_progress_bubble()
449
logger.debug("notification shown: %s", text)
473
self.notification.send_notification(UBUNTUONE_TITLE, text)
474
logger.debug("notification shown: %s", text)
450
475
self._change_state(FileDiscoveryUpdateState)
452
477
def _update(self):
453
478
"""Update the notification."""
479
if not self.connected:
454
481
text = self.status_aggregator.get_discovery_message()
455
logger.debug("notification updated: %s", text)
456
self.status_aggregator.restart_progress_bubble()
457
self.notification.send_notification(UBUNTUONE_TITLE, text)
483
logger.debug("notification updated: %s", text)
484
self.notification.send_notification(UBUNTUONE_TITLE, text)
459
486
def start_sleeping(self):
460
487
"""Wait for 10 minutes before annoying again."""
464
491
"""Cleanup this instance."""
465
492
self.state.cleanup()
494
def connection_made(self):
495
"""Connection made."""
496
self.connected = True
500
def connection_lost(self):
501
"""Connection lost."""
502
self.connected = False
467
504
def new_file_found(self):
468
505
"""New files found."""
506
self.files_found = True
469
507
self.state.new_file_found()
472
class ProgressBubble(object):
473
"""Show a notification for transfer progress."""
479
def __init__(self, status_aggregator, clock=reactor):
480
"""Initialize this instance."""
481
self.status_aggregator = status_aggregator
485
"""Start running the timer."""
487
self.timer = Timer(self.sleep_delay, clock=self.clock)
488
self.timer.addCallback(self._timeout)
490
def _timeout(self, _):
491
"""Show the bubble."""
492
self.notification = self.status_aggregator.get_notification()
493
text = self.status_aggregator.get_progress_message()
494
self.notification.send_notification(UBUNTUONE_TITLE, text)
498
"""Cleanup this instance."""
505
510
class ProgressBar(object):
506
511
"""Update a progressbar no more than 10 times a second."""
603
608
"""The status aggregator backend."""
605
610
file_discovery_bubble = None
606
progress_bubble = None
607
611
final_status_bubble = None
609
613
def __init__(self, clock=reactor):
610
614
"""Initialize this instance."""
611
615
self.clock = clock
612
616
self.notification_switch = NotificationSwitch()
617
self.queue_done_timer = None
614
619
self.progress_bar = ProgressBar(clock=self.clock)
620
self.finished_delay = 10
616
622
def get_notification(self):
617
623
"""Create a new toggleable notification object."""
630
636
self.uploading_filename = ''
631
637
self.files_downloading = []
632
638
self.downloading_filename = ''
639
if self.queue_done_timer is not None:
640
self.queue_done_timer.cleanup()
634
642
if self.file_discovery_bubble:
635
643
self.file_discovery_bubble.cleanup()
636
644
self.file_discovery_bubble = FileDiscoveryBubble(self,
637
645
clock=self.clock)
639
if self.progress_bubble:
640
self.progress_bubble.cleanup()
641
self.progress_bubble = ProgressBubble(self, clock=self.clock)
643
647
if self.final_status_bubble:
644
648
self.final_status_bubble.cleanup()
645
649
self.final_status_bubble = FinalStatusBubble(self)
660
664
self.downloading_filename, files_downloading))
661
665
return "\n".join(lines)
663
def get_progress_message(self):
664
"""Get some lines describing the progress."""
665
assert self.total_counter > 0
667
upload_total = self.upload_total
669
parts.append(files_being_uploaded(
670
self.uploading_filename, upload_total))
671
download_total = self.download_total
673
parts.append(files_being_downloaded(
674
self.downloading_filename, download_total))
675
progress_percentage = 100.0 * self.done_counter / self.total_counter
676
format_args = {"percentage_completed": int(progress_percentage)}
677
parts.append(PROGRESS_COMPLETED % format_args)
678
return "\n".join(parts)
680
667
def get_final_status_message(self):
681
668
"""Get some lines describing all we did."""
692
679
self.downloading_filename, download_done))
693
680
return "\n".join(parts)
695
def restart_progress_bubble(self):
696
"""Restart the progress bubble."""
697
self.progress_bubble.restart()
699
def queue_done(self):
682
def _queue_done(self, _):
700
683
"""Show final bubble and reset counters."""
684
self.queue_done_timer.cleanup()
685
self.queue_done_timer = None
686
logger.debug("queue done callback fired")
701
687
if self.upload_done + self.download_done > 0:
702
688
self.final_status_bubble.show()
703
689
self.progress_bar.completed()
706
def misc_command_queued(self, command):
707
"""A miscellaneous command was queued."""
708
self.total_counter += 1
709
logger.debug("queueing command (%d/%d): %s", self.done_counter,
710
self.total_counter, command.__class__.__name__)
711
self.update_progressbar()
692
def queue_done(self):
693
"""Queue is finished."""
694
if not self.total_counter:
696
if self.queue_done_timer is None:
697
logger.debug("queue done callback added")
698
self.queue_done_timer = Timer(
699
self.finished_delay, clock=self.clock)
700
self.queue_done_timer.addCallback(self._queue_done)
702
logger.debug("queue done callback reset")
703
self.queue_done_timer.reset()
713
705
def update_progressbar(self):
714
706
"""Update the counters of the progressbar."""
715
707
self.progress_bar.progress_made(self.done_counter, self.total_counter)
717
def misc_command_unqueued(self, command):
718
"""A miscellaneous command was unqueued."""
719
self.done_counter += 1
720
logger.debug("unqueueing command (%d/%d): %s", self.done_counter,
721
self.total_counter, command.__class__.__name__)
722
self.update_progressbar()
724
709
def download_started(self, command):
725
710
"""A download just started."""
711
if self.queue_done_timer is not None:
712
self.queue_done_timer.reset()
726
713
self.files_downloading.append(command)
727
714
self.download_total += 1
715
self.total_counter += 1
728
716
# pylint: disable=W0201
729
717
if not self.downloading_filename:
730
718
self.downloading_filename = self.files_downloading[0].path.split(
732
720
# pylint: enable=W0201
733
self.misc_command_queued(command)
721
self.update_progressbar()
722
logger.debug("queueing command (%d/%d): %s", self.done_counter,
723
self.total_counter, command.__class__.__name__)
734
724
self.file_discovery_bubble.new_file_found()
736
726
def download_finished(self, command):
738
728
if command in self.files_downloading:
739
729
self.files_downloading.remove(command)
740
730
self.download_done += 1
741
self.misc_command_unqueued(command)
731
self.done_counter += 1
732
logger.debug("unqueueing command (%d/%d): %s", self.done_counter,
733
self.total_counter, command.__class__.__name__)
734
self.update_progressbar()
743
736
def upload_started(self, command):
744
737
"""An upload just started."""
738
if self.queue_done_timer is not None:
739
self.queue_done_timer.reset()
745
740
self.files_uploading.append(command)
746
741
self.upload_total += 1
742
self.total_counter += 1
747
743
# pylint: disable=W0201
748
744
if not self.uploading_filename:
749
745
self.uploading_filename = self.files_uploading[0].path.split(
751
747
# pylint: enable=W0201
752
self.misc_command_queued(command)
748
self.update_progressbar()
749
logger.debug("queueing command (%d/%d): %s", self.done_counter,
750
self.total_counter, command.__class__.__name__)
753
751
self.file_discovery_bubble.new_file_found()
755
753
def upload_finished(self, command):
757
755
if command in self.files_uploading:
758
756
self.files_uploading.remove(command)
759
757
self.upload_done += 1
760
self.misc_command_unqueued(command)
758
self.done_counter += 1
759
logger.debug("unqueueing command (%d/%d): %s", self.done_counter,
760
self.total_counter, command.__class__.__name__)
761
self.update_progressbar()
762
763
def connection_lost(self):
763
764
"""The connection to the server was lost."""
765
self.file_discovery_bubble.connection_lost()
764
766
self.progress_bar.show_warning_emblem()
766
768
def connection_made(self):
767
769
"""The connection to the server was made."""
770
self.file_discovery_bubble.connection_made()
768
771
self.progress_bar.hide_emblem()
805
808
"""A file upload was unqueued."""
806
809
self.aggregator.upload_finished(command)
808
def queue_added(self, command):
809
"""A command was added to the queue."""
810
self.aggregator.misc_command_queued(command)
812
def queue_removed(self, command):
813
"""A command was removed from the queue."""
814
self.aggregator.misc_command_unqueued(command)
816
811
def queue_done(self):
817
812
"""The queue is empty."""
818
813
self.aggregator.queue_done()