ui.py

changeset 10
76dbfb06eba0
parent 9
aa121291eb0e
child 11
0bff53095f28
--- a/ui.py	Sat Jan 20 15:55:09 2018 +0000
+++ b/ui.py	Sat Jan 20 19:57:05 2018 +0000
@@ -3,16 +3,101 @@
 #
 
 import rumps
+import time
+import datetime
+import logging
+from threading import Lock
+
+def make_title(status):
+    if status['type']=='scheduled':
+        # Operation scheduled
+        when=status['when']
+        now=time.time()
+        if when<now:
+            whenstr='overdue'
+        else:
+            diff=datetime.timedelta(seconds=when-now)
+            if diff.days>0:
+                whenday=datetime.date.fromtimestamp(when)
+                whenstr='on %s' % whenday.isoformat()
+            else:
+                twhen=time.localtime(when)
+                if twhen.tm_sec>30:
+                    # Round up minute display to avoid user confusion
+                    twhen=time.localtime(when+30)
+                whenstr='at %02d:%02d' % (twhen.tm_hour, twhen.tm_min)
+        detail=''
+        if 'detail' in status and status['detail']:
+            detail=status['detail']+' '
+        return "%s (%s%s %s)" % (status['name'], detail, status['operation'], whenstr)
+    elif status['type']=='current':
+        # Operation running
+       return "%s (running: %s)" % (status['name'], status['operation'])
+    else: # status['type']=='nothing':
+        # Should be unscheduled, nothing running
+        return status['name']
+
 
 class BorgendTray(rumps.App):
     def __init__(self, name, backups):
-        menu=[rumps.MenuItem(b.name, callback=self.silly) for b in backups]
-        menu = menu + [rumps.MenuItem("Quit...", callback=self.my_quit_button)]
-        super().__init__(name, menu=menu, quit_button=None)
+        self.lock=Lock()
+        self.backups=backups
+        self.statuses=[None]*len(backups)
+
+        with self.lock:
+            # Initialise reporting callbacks and local status copy
+            # (since rumps doesn't seem to be able to update menu items
+            # without rebuilding the whole menu, and we don't want to lock
+            # when calling Backup.status(), especially as we will be called
+            # from Backup reporting its status, we keep a copy to allow
+            # rebuilding the entire menu
+            for index in range(len(backups)):
+                b=backups[index]
+                # Python closures suck dog's balls; hence the _index=index hack
+                # See also http://math.andrej.com/2009/04/09/pythons-lambda-is-broken/
+                cb=(lambda obj, status, _index=index:
+                    self.__status_callback(obj, _index, status))
+                b.set_status_update_callback(cb)
+                self.statuses[index]=b.status()
+
+            menu=self.__rebuild_menu()
 
-    def my_quit_button(self, _):
+            super().__init__(name, menu=menu, quit_button=None)
+
+    def __rebuild_menu(self):
+        menu=[]
+        for index in range(len(self.backups)):
+            b=self.backups[index]
+            title=make_title(self.statuses[index])
+            logging.info('TITLE: %s' % title)
+            # Python closures suck dog's balls...
+            # first and the last program I write in Python until somebody
+            # fixes this brain damage
+            cbm=lambda sender, _b=b: self.__menu_select_backup(sender, _b)
+            item=rumps.MenuItem(title, callback=cbm)
+            menu.append(item)
+
+        menu_quit=rumps.MenuItem("Quit...", callback=self.my_quit)
+        menu.append(menu_quit)
+
+        return menu
+
+
+    def my_quit(self, _):
         rumps.quit_application()
 
-    def silly(self, sender):
-        sender.state=not sender.state
+    def __menu_select_backup(self, sender, b):
+        #sender.state=not sender.state
+        logging.debug("Manually backup '%s'", b.name)
+        b.create(None)
 
+    def __status_callback(self, obj, index, status):
+        logging.debug('Status callbackup %s' % str(status))
+        with self.lock:
+            self.statuses[index]=status
+            logging.debug('Rebuilding menu')
+            self.menu.clear()
+            self.menu.update(self.__rebuild_menu())
+
+
+

mercurial