11import logging
22import sys
33from typing import Dict , Optional
4+ from datetime import timedelta
45
56from PyQt6 import QtCore , uic
67from PyQt6 .QtCore import QItemSelectionModel , QMimeData , QPoint , Qt , pyqtSlot
3637 borg_compat ,
3738 choose_file_dialog ,
3839 format_archive_name ,
39- get_asset
40+ get_asset ,
41+ pretty_bytes ,
42+ find_best_unit_for_sizes
4043)
4144from vorta .views import diff_result , extract_dialog
4245from vorta .views .diff_result import DiffResultDialog , DiffTree
4346from 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
4649
4750uifile = get_asset ('UI/archivetab.ui' )
4851ArchiveTabUI , ArchiveTabBase = uic .loadUiType (uifile )
@@ -234,23 +237,85 @@ def _toggle_all_buttons(self, enabled=True):
234237 # Restore states
235238 self .on_selection_change ()
236239
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+
237259 def populate_from_profile (self ):
238260 """Populate archive list and prune settings from profile."""
261+ self .archiveTable .blockSignals (True )
239262 profile = self .profile ()
240263 if profile .repo is not None :
241-
242264 if profile .repo .name :
243265 repo_name = f"{ profile .repo .name } ({ profile .repo .url } )"
244266 else :
245267 repo_name = profile .repo .url
246268 self .toolBox .setItemText (0 , self .tr ('Archives for {}' ).format (repo_name ))
247269
248- populateArchiveTableWorker = PopulateArchiveTableAsync (profile , self . mount_points , self . archiveTable )
270+ populateArchiveTableWorker = MountPointsWorker (profile . repo . url )
249271 self .workers .append (populateArchiveTableWorker ) # preserve worker reference
272+ populateArchiveTableWorker .signal .connect (self .set_mount_points )
250273 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 ))
251286
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 )
254319 else :
255320 self .mount_points = {}
256321 self .archiveTable .setRowCount (0 )
@@ -261,13 +326,14 @@ def populate_from_profile(self):
261326 self .prunePrefixTemplate .setText (profile .prune_prefix )
262327
263328 # Populate pruning options from database
264- profile = self .profile ()
265329 for i in self .prune_intervals :
266330 getattr (self , f'prune_{ i } ' ).setValue (getattr (profile , f'prune_{ i } ' ))
267331 getattr (self , f'prune_{ i } ' ).valueChanged .connect (self .save_prune_setting )
268332 self .prune_keep_within .setText (profile .prune_keep_within )
269333 self .prune_keep_within .editingFinished .connect (self .save_prune_setting )
270334
335+ self .archiveTable .blockSignals (False )
336+
271337 def on_selection_change (self , selected = None , deselected = None ):
272338 """
273339 React to a change of the selection of the archiveTableView.
0 commit comments