1
1
import logging
2
2
import sys
3
3
from typing import Dict , Optional
4
+ from datetime import timedelta
4
5
5
6
from PyQt6 import QtCore , uic
6
7
from PyQt6 .QtCore import QItemSelectionModel , QMimeData , QPoint , Qt , pyqtSlot
36
37
borg_compat ,
37
38
choose_file_dialog ,
38
39
format_archive_name ,
39
- get_asset
40
+ get_asset ,
41
+ pretty_bytes ,
42
+ find_best_unit_for_sizes
40
43
)
41
44
from vorta .views import diff_result , extract_dialog
42
45
from vorta .views .diff_result import DiffResultDialog , DiffTree
43
46
from vorta .views .extract_dialog import ExtractDialog , ExtractTree
44
- from vorta .views .utils import get_colored_icon
45
- from vorta .views .workers .archive_table_worker import PopulateArchiveTableAsync
47
+ from vorta .views .utils import get_colored_icon , SizeItem
48
+ from vorta .views .workers .mount_points_worker import MountPointsWorker
46
49
47
50
uifile = get_asset ('UI/archivetab.ui' )
48
51
ArchiveTabUI , ArchiveTabBase = uic .loadUiType (uifile )
@@ -234,23 +237,85 @@ def _toggle_all_buttons(self, enabled=True):
234
237
# Restore states
235
238
self .on_selection_change ()
236
239
240
+ def set_mount_points (self , mount_points , repo_mounts ):
241
+ if len (repo_mounts ) == 0 :
242
+ return
243
+
244
+ archives = [s for s in self .profile ().repo .archives .select ().order_by (ArchiveModel .time .desc ())]
245
+
246
+ # if no archive's name can be found in self.mount_points, then hide the mount point column
247
+ if not any (a .name in mount_points for a in archives ):
248
+ return
249
+ else :
250
+ self .archiveTable .showColumn (3 )
251
+ self .repo_mount_point = repo_mounts [0 ]
252
+
253
+ for row , archive in enumerate (archives ):
254
+ mount_point = self .mount_points .get (archive .name )
255
+ if mount_point is not None :
256
+ item = QTableWidgetItem (mount_point )
257
+ self .archiveTable .setItem (row , 3 , item )
258
+
237
259
def populate_from_profile (self ):
238
260
"""Populate archive list and prune settings from profile."""
261
+ self .archiveTable .blockSignals (True )
239
262
profile = self .profile ()
240
263
if profile .repo is not None :
241
-
242
264
if profile .repo .name :
243
265
repo_name = f"{ profile .repo .name } ({ profile .repo .url } )"
244
266
else :
245
267
repo_name = profile .repo .url
246
268
self .toolBox .setItemText (0 , self .tr ('Archives for {}' ).format (repo_name ))
247
269
248
- populateArchiveTableWorker = PopulateArchiveTableAsync (profile , self . mount_points , self . archiveTable )
270
+ populateArchiveTableWorker = MountPointsWorker (profile . repo . url )
249
271
self .workers .append (populateArchiveTableWorker ) # preserve worker reference
272
+ populateArchiveTableWorker .signal .connect (self .set_mount_points )
250
273
populateArchiveTableWorker .start ()
274
+ self .archiveTable .hideColumn (3 )
275
+
276
+ archives = [s for s in profile .repo .archives .select ().order_by (ArchiveModel .time .desc ())]
277
+
278
+ sorting = self .archiveTable .isSortingEnabled ()
279
+ self .archiveTable .setSortingEnabled (False )
280
+ best_unit = find_best_unit_for_sizes ((a .size for a in archives ), precision = SIZE_DECIMAL_DIGITS )
281
+ for row , archive in enumerate (archives ):
282
+ self .archiveTable .insertRow (row )
283
+
284
+ formatted_time = archive .time .strftime ('%Y-%m-%d %H:%M' )
285
+ self .archiveTable .setItem (row , 0 , QTableWidgetItem (formatted_time ))
251
286
252
- if self .remaining_refresh_archives == 0 :
253
- self ._toggle_all_buttons (enabled = True )
287
+ # format units based on user settings for 'dynamic' or 'fixed' units
288
+ fixed_unit = best_unit if SettingsModel .get (key = 'enable_fixed_units' ).value else None
289
+ size = pretty_bytes (archive .size , fixed_unit = fixed_unit , precision = SIZE_DECIMAL_DIGITS )
290
+ self .archiveTable .setItem (row , 1 , SizeItem (size ))
291
+
292
+ if archive .duration is not None :
293
+ formatted_duration = str (timedelta (seconds = round (archive .duration )))
294
+ else :
295
+ formatted_duration = ''
296
+
297
+ self .archiveTable .setItem (row , 2 , QTableWidgetItem (formatted_duration ))
298
+ self .archiveTable .setItem (row , 4 , QTableWidgetItem (archive .name ))
299
+
300
+ if archive .trigger == 'scheduled' :
301
+ item = QTableWidgetItem (get_colored_icon ('clock-o' ), '' )
302
+ item .setToolTip (self .tr ('Scheduled' ))
303
+ self .archiveTable .setItem (row , 5 , item )
304
+ elif archive .trigger == 'user' :
305
+ item = QTableWidgetItem (get_colored_icon ('user' ), '' )
306
+ item .setToolTip (self .tr ('User initiated' ))
307
+ item .setTextAlignment (Qt .AlignmentFlag .AlignRight )
308
+ self .archiveTable .setItem (row , 5 , item )
309
+
310
+ self .archiveTable .setRowCount (len (archives ))
311
+ self .archiveTable .setSortingEnabled (sorting )
312
+ item = self .archiveTable .item (0 , 0 )
313
+ self .archiveTable .scrollToItem (item )
314
+
315
+ self .archiveTable .selectionModel ().clearSelection ()
316
+
317
+ if self .remaining_refresh_archives == 0 :
318
+ self ._toggle_all_buttons (enabled = True )
254
319
else :
255
320
self .mount_points = {}
256
321
self .archiveTable .setRowCount (0 )
@@ -261,13 +326,14 @@ def populate_from_profile(self):
261
326
self .prunePrefixTemplate .setText (profile .prune_prefix )
262
327
263
328
# Populate pruning options from database
264
- profile = self .profile ()
265
329
for i in self .prune_intervals :
266
330
getattr (self , f'prune_{ i } ' ).setValue (getattr (profile , f'prune_{ i } ' ))
267
331
getattr (self , f'prune_{ i } ' ).valueChanged .connect (self .save_prune_setting )
268
332
self .prune_keep_within .setText (profile .prune_keep_within )
269
333
self .prune_keep_within .editingFinished .connect (self .save_prune_setting )
270
334
335
+ self .archiveTable .blockSignals (False )
336
+
271
337
def on_selection_change (self , selected = None , deselected = None ):
272
338
"""
273
339
React to a change of the selection of the archiveTableView.
0 commit comments