From 157ac373a9bdb0396479d01eb1c983ccf046844d Mon Sep 17 00:00:00 2001 From: Divyansh Singh Date: Wed, 5 Jul 2023 15:58:09 +0530 Subject: [PATCH] Run actions on multiple archives. By @diivi (#1723) --- src/vorta/assets/UI/archivetab.ui | 4 +- src/vorta/views/archive_tab.py | 69 ++++++++++++++++++++----------- src/vorta/views/main_window.py | 4 +- 3 files changed, 49 insertions(+), 28 deletions(-) diff --git a/src/vorta/assets/UI/archivetab.ui b/src/vorta/assets/UI/archivetab.ui index 6fc6d586..dfaa5d51 100644 --- a/src/vorta/assets/UI/archivetab.ui +++ b/src/vorta/assets/UI/archivetab.ui @@ -209,10 +209,10 @@ - Refresh selected archive + Recalculate selected archive's size(s) - Refresh + Recalculate Qt::ToolButtonTextBesideIcon diff --git a/src/vorta/views/archive_tab.py b/src/vorta/views/archive_tab.py index 95427511..54ae7aa1 100644 --- a/src/vorta/views/archive_tab.py +++ b/src/vorta/views/archive_tab.py @@ -79,11 +79,15 @@ class ArchiveTab(ArchiveTabBase, ArchiveTabUI, BackupProfileMixin): self.app = app self.toolBox.setCurrentIndex(0) self.repoactions_enabled = True + self.remaining_refresh_archives = ( + 0 # number of archives that are left to refresh before action buttons are enabled again + ) #: Tooltip dict to save the tooltips set in the designer self.tooltip_dict: Dict[QWidget, str] = {} self.tooltip_dict[self.bDiff] = self.bDiff.toolTip() self.tooltip_dict[self.bDelete] = self.bDelete.toolTip() + self.tooltip_dict[self.bRefreshArchive] = self.bRefreshArchive.toolTip() self.tooltip_dict[self.compactButton] = self.compactButton.toolTip() header = self.archiveTable.horizontalHeader() @@ -320,7 +324,8 @@ class ArchiveTab(ArchiveTabBase, ArchiveTabUI, BackupProfileMixin): self.archiveTable.scrollToItem(item) self.archiveTable.selectionModel().clearSelection() - self._toggle_all_buttons(enabled=True) + if self.remaining_refresh_archives == 0: + self._toggle_all_buttons(enabled=True) else: self.mount_points = {} self.archiveTable.setRowCount(0) @@ -355,6 +360,10 @@ class ArchiveTab(ArchiveTabBase, ArchiveTabUI, BackupProfileMixin): # handle selection of more than 2 rows selectionModel: QItemSelectionModel = self.archiveTable.selectionModel() indexes = selectionModel.selectedRows() + # actions that are enabled only when a single archive is selected + single_archive_action_buttons = [self.bMountArchive, self.bExtract, self.bRename] + # actions that are enabled when at least one archive is selected + multi_archive_action_buttons = [self.bDelete, self.bRefreshArchive] # Toggle archive actions frame layout: QLayout = self.fArchiveActions.layout() @@ -364,14 +373,15 @@ class ArchiveTab(ArchiveTabBase, ArchiveTabUI, BackupProfileMixin): if not self.repoactions_enabled: reason = self.tr("(borg already running)") - # toggle delete button + # Disable the delete and refresh buttons if no archive is selected if self.repoactions_enabled and len(indexes) > 0: - self.bDelete.setEnabled(True) - self.bDelete.setToolTip(self.tooltip_dict.get(self.bDelete, "")) + for button in multi_archive_action_buttons: + button.setEnabled(True) + button.setToolTip(self.tooltip_dict.get(button, "")) else: - self.bDelete.setEnabled(False) - tooltip = self.tooltip_dict[self.bDelete] - self.bDelete.setToolTip(tooltip + " " + reason or self.tr("(Select minimum one archive)")) + for button in multi_archive_action_buttons: + button.setEnabled(False) + button.setToolTip(self.tooltip_dict.get(button, "") + " " + self.tr("(Select minimum one archive)")) # Toggle diff button if self.repoactions_enabled and len(indexes) == 2: @@ -387,7 +397,8 @@ class ArchiveTab(ArchiveTabBase, ArchiveTabUI, BackupProfileMixin): if self.repoactions_enabled and len(indexes) == 1: # Enable archive actions - self.fArchiveActions.setEnabled(True) + for widget in single_archive_action_buttons: + widget.setEnabled(True) for index in range(layout.count()): widget = layout.itemAt(index).widget() @@ -399,14 +410,11 @@ class ArchiveTab(ArchiveTabBase, ArchiveTabUI, BackupProfileMixin): reason = reason or self.tr("(Select exactly one archive)") # too few or too many selected. - self.fArchiveActions.setEnabled(False) - - for index in range(layout.count()): - widget = layout.itemAt(index).widget() + for widget in single_archive_action_buttons: tooltip = widget.toolTip() - tooltip = self.tooltip_dict.setdefault(widget, tooltip) widget.setToolTip(tooltip + " " + reason) + widget.setEnabled(False) # special treatment for dynamic mount/unmount button. self.bmountarchive_refresh() @@ -522,20 +530,31 @@ class ArchiveTab(ArchiveTabBase, ArchiveTabUI, BackupProfileMixin): self.populate_from_profile() def refresh_archive_info(self): - archive_name = self.selected_archive_name() - if archive_name is not None: - params = BorgInfoArchiveJob.prepare(self.profile(), archive_name) - if params['ok']: - job = BorgInfoArchiveJob(params['cmd'], params, self.profile().repo.id) - job.updated.connect(self._set_status) - job.result.connect(self.info_result) - self._toggle_all_buttons(False) - self.app.jobs_manager.add_job(job) + selected_archives = self.archiveTable.selectionModel().selectedRows() + + archive_names = [] + for index in selected_archives: + archive_names.append(self.archiveTable.item(index.row(), 4).text()) + + self.remaining_refresh_archives = len(archive_names) # number of archives to refresh + self._toggle_all_buttons(False) + for archive_name in archive_names: + if archive_name is not None: + params = BorgInfoArchiveJob.prepare(self.profile(), archive_name) + if params['ok']: + job = BorgInfoArchiveJob(params['cmd'], params, self.profile().repo.id) + job.updated.connect(self._set_status) + job.result.connect(self.info_result) + self.app.jobs_manager.add_job(job) + else: + self._set_status(params['message']) + return def info_result(self, result): - self._toggle_all_buttons(True) - if result['returncode'] == 0: - self._set_status(self.tr('Refreshed archive.')) + self.remaining_refresh_archives -= 1 + if result['returncode'] == 0 and self.remaining_refresh_archives == 0: + self._toggle_all_buttons(True) + self._set_status(self.tr('Refreshed archives.')) self.populate_from_profile() def selected_archive_name(self): diff --git a/src/vorta/views/main_window.py b/src/vorta/views/main_window.py index fab20dfe..3da134f4 100644 --- a/src/vorta/views/main_window.py +++ b/src/vorta/views/main_window.py @@ -275,7 +275,9 @@ class MainWindow(MainWindowBase, MainWindowUI): self.repoTab.init_repo_stats() self.scheduleTab.populate_logs() - if not self.app.jobs_manager.is_worker_running(): + if not self.app.jobs_manager.is_worker_running() and ( + self.archiveTab.remaining_refresh_archives == 0 or self.archiveTab.remaining_refresh_archives == 1 + ): # Either the refresh is done or this is the last archive to refresh. self._toggle_buttons(create_enabled=True) self.archiveTab._toggle_all_buttons(enabled=True)