borgend/ui.py

changeset 105
55043f86c0b5
parent 101
3068b0de12ee
child 106
a7bdc239ef62
equal deleted inserted replaced
104:d33e2d7dbeb1 105:55043f86c0b5
110 return "%s; %s" % (info, new) 110 return "%s; %s" % (info, new)
111 else: 111 else:
112 return new 112 return new
113 113
114 info=None 114 info=None
115 this_need_reconstruct=None 115 this_refresh_time=None
116 116
117 if not status.errors.ok(): 117 if not status.errors.ok():
118 info=add_info(info, str(status.errors)) 118 info=add_info(info, str(status.errors))
119 119
120 if status.state==backup.State.PAUSED: 120 if status.state==backup.State.PAUSED:
133 tendtoday=twhen.replace(hour=23,minute=59,second=59) 133 tendtoday=twhen.replace(hour=23,minute=59,second=59)
134 tendtomorrow=tendtoday+datetime.timedelta(days=1) 134 tendtomorrow=tendtoday+datetime.timedelta(days=1)
135 diff=datetime.timedelta(seconds=when-now) 135 diff=datetime.timedelta(seconds=when-now)
136 136
137 if twhen>tendtomorrow: 137 if twhen>tendtomorrow:
138 # Display date if scheduled event is after tomorrow
138 whenday=datetime.date.fromtimestamp(when) 139 whenday=datetime.date.fromtimestamp(when)
139 whenstr='on %s' % twhen.date().isoformat() 140 whenstr='on %s' % twhen.date().isoformat()
140 this_need_reconstruct=tendtoday+datetime.timedelta(seconds=1) 141 this_refresh_time=tendtoday+datetime.timedelta(seconds=1)
141 elif diff.seconds>=12*60*60: # 12 hours 142 elif twhen>tendtoday and diff.seconds>=12*60*60: # 12 hours
143 # Display 'tomorrow' if the scheduled event is tomorrow and
144 # not earlier than after 12 hours
142 whenstr='tomorrow' 145 whenstr='tomorrow'
143 this_need_reconstruct=twhen-datetime.timedelta(hours=12) 146 this_refresh_time=twhen-datetime.timedelta(hours=12)
144 else: 147 else:
148 # Otherwise, display time
145 twhen=time.localtime(when) 149 twhen=time.localtime(when)
146 if twhen.tm_sec>30: 150 if twhen.tm_sec>30:
147 # Round up minute display to avoid user confusion 151 # Round up minute display to avoid user confusion
148 twhen=time.localtime(when+30) 152 twhen=time.localtime(when+30)
149 whenstr='at %02d:%02d' % (twhen.tm_hour, twhen.tm_min) 153 whenstr='at %02d:%02d' % (twhen.tm_hour, twhen.tm_min)
182 if info: 186 if info:
183 title=status.name + ' (' + info + ')' 187 title=status.name + ' (' + info + ')'
184 else: 188 else:
185 title=status.name 189 title=status.name
186 190
187 return title, (status.state, status.errors), this_need_reconstruct 191 return title, (status.state, status.errors), this_refresh_time
188 192
189 class BorgendTray(rumps.App): 193 class BorgendTray(rumps.App):
190 def __init__(self, backups): 194 def __init__(self, backups):
191 self.lock=Lock() 195 self.lock=Lock()
192 self.backups=backups 196 self.backups=backups
211 dreamtime.add_callback(self, self.__sleepwake_callback) 215 dreamtime.add_callback(self, self.__sleepwake_callback)
212 216
213 def __rebuild_menu(self): 217 def __rebuild_menu(self):
214 menu=[] 218 menu=[]
215 state=(backup.State.INACTIVE, backup.Errors.OK) 219 state=(backup.State.INACTIVE, backup.Errors.OK)
216 need_reconstruct=None 220 refresh_time=None
217 all_paused=True 221 all_paused=True
218 222
219 for index in range(len(self.backups)): 223 for index in range(len(self.backups)):
220 b=self.backups[index] 224 b=self.backups[index]
221 title, this_state, this_need_reconstruct=make_title(self.statuses[index]) 225 title, this_state, this_refresh_time=make_title(self.statuses[index])
222 # Python closures suck dog's balls... 226 # Python closures suck dog's balls...
223 # first and the last program I write in Python until somebody 227 # first and the last program I write in Python until somebody
224 # fixes this brain damage 228 # fixes this brain damage
225 cbm=lambda sender, _b=b: self.__menu_select_backup(sender, _b) 229 cbm=lambda sender, _b=b: self.__menu_select_backup(sender, _b)
226 item=rumps.MenuItem(title, callback=cbm) 230 item=rumps.MenuItem(title, callback=cbm)
232 state=combine_state(state, this_state) 236 state=combine_state(state, this_state)
233 237
234 all_paused=(all_paused and this_state[0]==backup.State.PAUSED) 238 all_paused=(all_paused and this_state[0]==backup.State.PAUSED)
235 239
236 # Do we have to automatically update menu display? 240 # Do we have to automatically update menu display?
237 if not need_reconstruct: 241 if not refresh_time:
238 need_reconstruct=this_need_reconstruct 242 refresh_time=this_refresh_time
239 elif this_need_reconstruct: 243 elif this_refresh_time:
240 need_reconstruct=min(need_reconstruct, this_need_reconstruct) 244 refresh_time=min(refresh_time, this_refresh_time)
241 245
242 menu_log=rumps.MenuItem("Show log", callback=lambda _: showlog()) 246 menu_log=rumps.MenuItem("Show log", callback=lambda _: showlog())
243 menu.append(menu_log) 247 menu.append(menu_log)
244 248
245 if all_paused: 249 if all_paused:
251 255
252 if not settings['no_quit_menu_entry']: 256 if not settings['no_quit_menu_entry']:
253 menu_quit=rumps.MenuItem("Quit...", callback=lambda _: self.quit()) 257 menu_quit=rumps.MenuItem("Quit...", callback=lambda _: self.quit())
254 menu.append(menu_quit) 258 menu.append(menu_quit)
255 259
256 return menu, state, need_reconstruct 260 return menu, state, refresh_time
257 261
258 def build_menu_and_timer(self): 262 def build_menu_and_timer(self):
259 if self.refresh_timer: 263 if self.refresh_timer:
260 self.refresh_timer.cancel() 264 self.refresh_timer.cancel()
261 self.refresh_timer=None 265 self.refresh_timer=None
262 self.refresh_timer_time=None 266 self.refresh_timer_time=None
267
263 logger.debug('Rebuilding menu') 268 logger.debug('Rebuilding menu')
264 menu, state, need_reconstruct=self.__rebuild_menu() 269 menu, state, refresh_time=self.__rebuild_menu()
265 title=trayname(state) 270 title=trayname(state)
266 271
267 if need_reconstruct: 272 if refresh_time:
268 when=time.mktime(need_reconstruct.timetuple()) 273 # Need to time a refresh due to content display changing,
274 # e.g., 'tomorrow' changing to a more specific hour.
275 when=time.mktime(refresh_time.timetuple())
269 delay=when-time.time() 276 delay=when-time.time()
270 self.refresh_timer=Timer(delay, self.refresh_ui) 277 if delay>0:
271 self.refresh_timer_time=need_reconstruct 278 logger.debug('Timing menu refresh in %s seconds' % delay)
272 self.refresh_timer.start() 279 self.refresh_timer=Timer(delay, self.refresh_ui)
280 self.refresh_timer_time=refresh_time
281 self.refresh_timer.start()
273 282
274 return menu, title 283 return menu, title
275 284
276 def refresh_ui(self): 285 def refresh_ui(self):
277 with self.lock: 286 with self.lock:
285 with self.lock: 294 with self.lock:
286 self.statuses[index]=status 295 self.statuses[index]=status
287 # Time the refresh if it has not been timed, or if the timer 296 # Time the refresh if it has not been timed, or if the timer
288 # is timing for the "long-term" (refresh_timer_time set) 297 # is timing for the "long-term" (refresh_timer_time set)
289 if not self.refresh_timer or self.refresh_timer_time: 298 if not self.refresh_timer or self.refresh_timer_time:
290 logger.debug("Timing refresh") 299 # logger.debug("Timing refresh")
291 self.refresh_timer=Timer(refresh_interval, self.refresh_ui) 300 self.refresh_timer=Timer(refresh_interval, self.refresh_ui)
292 # refresh_timer_time is only set for "long-term timers" 301 # refresh_timer_time is only set for "long-term timers"
293 self.refresh_timer_time=None 302 self.refresh_timer_time=None
294 self.refresh_timer.start() 303 self.refresh_timer.start()
295 304

mercurial