ui.py

changeset 10
76dbfb06eba0
parent 9
aa121291eb0e
child 11
0bff53095f28
equal deleted inserted replaced
9:aa121291eb0e 10:76dbfb06eba0
1 # 1 #
2 # MacOS UI 2 # MacOS UI
3 # 3 #
4 4
5 import rumps 5 import rumps
6 import time
7 import datetime
8 import logging
9 from threading import Lock
10
11 def make_title(status):
12 if status['type']=='scheduled':
13 # Operation scheduled
14 when=status['when']
15 now=time.time()
16 if when<now:
17 whenstr='overdue'
18 else:
19 diff=datetime.timedelta(seconds=when-now)
20 if diff.days>0:
21 whenday=datetime.date.fromtimestamp(when)
22 whenstr='on %s' % whenday.isoformat()
23 else:
24 twhen=time.localtime(when)
25 if twhen.tm_sec>30:
26 # Round up minute display to avoid user confusion
27 twhen=time.localtime(when+30)
28 whenstr='at %02d:%02d' % (twhen.tm_hour, twhen.tm_min)
29 detail=''
30 if 'detail' in status and status['detail']:
31 detail=status['detail']+' '
32 return "%s (%s%s %s)" % (status['name'], detail, status['operation'], whenstr)
33 elif status['type']=='current':
34 # Operation running
35 return "%s (running: %s)" % (status['name'], status['operation'])
36 else: # status['type']=='nothing':
37 # Should be unscheduled, nothing running
38 return status['name']
39
6 40
7 class BorgendTray(rumps.App): 41 class BorgendTray(rumps.App):
8 def __init__(self, name, backups): 42 def __init__(self, name, backups):
9 menu=[rumps.MenuItem(b.name, callback=self.silly) for b in backups] 43 self.lock=Lock()
10 menu = menu + [rumps.MenuItem("Quit...", callback=self.my_quit_button)] 44 self.backups=backups
11 super().__init__(name, menu=menu, quit_button=None) 45 self.statuses=[None]*len(backups)
12 46
13 def my_quit_button(self, _): 47 with self.lock:
48 # Initialise reporting callbacks and local status copy
49 # (since rumps doesn't seem to be able to update menu items
50 # without rebuilding the whole menu, and we don't want to lock
51 # when calling Backup.status(), especially as we will be called
52 # from Backup reporting its status, we keep a copy to allow
53 # rebuilding the entire menu
54 for index in range(len(backups)):
55 b=backups[index]
56 # Python closures suck dog's balls; hence the _index=index hack
57 # See also http://math.andrej.com/2009/04/09/pythons-lambda-is-broken/
58 cb=(lambda obj, status, _index=index:
59 self.__status_callback(obj, _index, status))
60 b.set_status_update_callback(cb)
61 self.statuses[index]=b.status()
62
63 menu=self.__rebuild_menu()
64
65 super().__init__(name, menu=menu, quit_button=None)
66
67 def __rebuild_menu(self):
68 menu=[]
69 for index in range(len(self.backups)):
70 b=self.backups[index]
71 title=make_title(self.statuses[index])
72 logging.info('TITLE: %s' % title)
73 # Python closures suck dog's balls...
74 # first and the last program I write in Python until somebody
75 # fixes this brain damage
76 cbm=lambda sender, _b=b: self.__menu_select_backup(sender, _b)
77 item=rumps.MenuItem(title, callback=cbm)
78 menu.append(item)
79
80 menu_quit=rumps.MenuItem("Quit...", callback=self.my_quit)
81 menu.append(menu_quit)
82
83 return menu
84
85
86 def my_quit(self, _):
14 rumps.quit_application() 87 rumps.quit_application()
15 88
16 def silly(self, sender): 89 def __menu_select_backup(self, sender, b):
17 sender.state=not sender.state 90 #sender.state=not sender.state
91 logging.debug("Manually backup '%s'", b.name)
92 b.create(None)
18 93
94 def __status_callback(self, obj, index, status):
95 logging.debug('Status callbackup %s' % str(status))
96 with self.lock:
97 self.statuses[index]=status
98 logging.debug('Rebuilding menu')
99 self.menu.clear()
100 self.menu.update(self.__rebuild_menu())
101
102
103

mercurial