From 803901e15ee771f923210ebeaea9d389af2b8543 Mon Sep 17 00:00:00 2001 From: Sam Date: Fri, 1 Sep 2023 23:13:17 +0530 Subject: [PATCH 1/8] added peewee to requirements.d/dev.txt --- requirements.d/dev.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/requirements.d/dev.txt b/requirements.d/dev.txt index 5391c54a0..9cc3cc9c8 100644 --- a/requirements.d/dev.txt +++ b/requirements.d/dev.txt @@ -3,6 +3,7 @@ coverage flake8 macholib nox +peewee pkgconfig pre-commit pyinstaller From 1650c99ed0d0135b79c31aba9b85c62c4b8324b9 Mon Sep 17 00:00:00 2001 From: Sam Date: Wed, 6 Sep 2023 11:57:06 +0530 Subject: [PATCH 2/8] removed peewee from requirements: not necessary --- requirements.d/dev.txt | 1 - 1 file changed, 1 deletion(-) diff --git a/requirements.d/dev.txt b/requirements.d/dev.txt index 9cc3cc9c8..5391c54a0 100644 --- a/requirements.d/dev.txt +++ b/requirements.d/dev.txt @@ -3,7 +3,6 @@ coverage flake8 macholib nox -peewee pkgconfig pre-commit pyinstaller From 0cecc56c8d4096ed126401a2279e24d2ad1d1551 Mon Sep 17 00:00:00 2001 From: Sam Date: Wed, 13 Dec 2023 14:45:27 +0530 Subject: [PATCH 3/8] add peewee --- requirements.d/dev.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/requirements.d/dev.txt b/requirements.d/dev.txt index 5391c54a0..9cc3cc9c8 100644 --- a/requirements.d/dev.txt +++ b/requirements.d/dev.txt @@ -3,6 +3,7 @@ coverage flake8 macholib nox +peewee pkgconfig pre-commit pyinstaller From 13dc613255e12bbb55361d27caf0199fc909aafb Mon Sep 17 00:00:00 2001 From: Sam Date: Fri, 15 Dec 2023 01:04:51 +0530 Subject: [PATCH 4/8] multiselection of folders in sources --- src/vorta/utils.py | 31 +++++++++++++++++++++++++++++-- src/vorta/views/source_tab.py | 7 +++++-- 2 files changed, 34 insertions(+), 4 deletions(-) diff --git a/src/vorta/utils.py b/src/vorta/utils.py index 033b486a5..bacf469e1 100644 --- a/src/vorta/utils.py +++ b/src/vorta/utils.py @@ -15,7 +15,13 @@ import psutil from PyQt6 import QtCore from PyQt6.QtCore import QFileInfo, QThread, pyqtSignal -from PyQt6.QtWidgets import QApplication, QFileDialog, QSystemTrayIcon +from PyQt6.QtWidgets import ( + QAbstractItemView, + QApplication, + QFileDialog, + QSystemTrayIcon, + QTreeView, +) from vorta.borg._compatibility import BorgCompatibility from vorta.log import logger @@ -50,6 +56,22 @@ def run(self): self.signal.emit(self.path, str(self.size), str(self.files_count)) +class MultiSelectionFileDialog(QFileDialog): + def __init__(self, parent, title, initial_dir=os.path.expanduser('~')): + super().__init__(parent, title, initial_dir) + + def selectedFiles(self, tree_view=None): + selected_files = super().selectedFiles() + + if self.fileMode() == QFileDialog.FileMode.Directory: + if tree_view: + selected_indexes = tree_view.selectionModel().selectedIndexes() + selected_dirs = [tree_view.model().filePath(index) for index in selected_indexes] + selected_files += selected_dirs + + return selected_files + + def normalize_path(path): """normalize paths for MacOS (but do nothing on other platforms)""" # HFS+ converts paths to a canonical form, so users shouldn't be required to enter an exact match. @@ -167,11 +189,16 @@ def get_dict_from_list(dataDict, mapList): def choose_file_dialog(parent, title, want_folder=True): - dialog = QFileDialog(parent, title, os.path.expanduser('~')) + dialog = MultiSelectionFileDialog(parent, title, os.path.expanduser('~')) dialog.setFileMode(QFileDialog.FileMode.Directory if want_folder else QFileDialog.FileMode.ExistingFiles) dialog.setParent(parent, QtCore.Qt.WindowType.Sheet) if want_folder: dialog.setOption(QFileDialog.Option.ShowDirsOnly) + dialog.setOption(QFileDialog.Option.DontUseNativeDialog) + dir_dialog = dialog.findChild(QTreeView) + dir_dialog.setSelectionMode(QAbstractItemView.SelectionMode.MultiSelection) + return dialog, dir_dialog + return dialog diff --git a/src/vorta/views/source_tab.py b/src/vorta/views/source_tab.py index ed63be2a7..09461c80e 100644 --- a/src/vorta/views/source_tab.py +++ b/src/vorta/views/source_tab.py @@ -287,7 +287,7 @@ def sources_update(self): def source_add(self, want_folder): def receive(): - dirs = dialog.selectedFiles() + dirs = dialog.selectedFiles(dir_dialog) if want_folder else dialog.selectedFiles() for dir in dirs: if not os.access(dir, os.R_OK): msg = QMessageBox() @@ -301,7 +301,10 @@ def receive(): new_source.save() msg = self.tr("Choose directory to back up") if want_folder else self.tr("Choose file(s) to back up") - dialog = choose_file_dialog(self, msg, want_folder=want_folder) + if want_folder: + dialog, dir_dialog = choose_file_dialog(self, msg, want_folder=want_folder) + else: + dialog = choose_file_dialog(self, msg, want_folder=want_folder) dialog.open(receive) def source_copy(self, index=None): From f858d18570d9947f80b87d1a07607865b1c8083a Mon Sep 17 00:00:00 2001 From: Sam Date: Sun, 17 Dec 2023 00:55:42 +0530 Subject: [PATCH 5/8] Selection of multiple directories working now --- src/vorta/utils.py | 29 +++++------------------------ src/vorta/views/source_tab.py | 11 ++++------- 2 files changed, 9 insertions(+), 31 deletions(-) diff --git a/src/vorta/utils.py b/src/vorta/utils.py index bacf469e1..46b392c3a 100644 --- a/src/vorta/utils.py +++ b/src/vorta/utils.py @@ -56,22 +56,6 @@ def run(self): self.signal.emit(self.path, str(self.size), str(self.files_count)) -class MultiSelectionFileDialog(QFileDialog): - def __init__(self, parent, title, initial_dir=os.path.expanduser('~')): - super().__init__(parent, title, initial_dir) - - def selectedFiles(self, tree_view=None): - selected_files = super().selectedFiles() - - if self.fileMode() == QFileDialog.FileMode.Directory: - if tree_view: - selected_indexes = tree_view.selectionModel().selectedIndexes() - selected_dirs = [tree_view.model().filePath(index) for index in selected_indexes] - selected_files += selected_dirs - - return selected_files - - def normalize_path(path): """normalize paths for MacOS (but do nothing on other platforms)""" # HFS+ converts paths to a canonical form, so users shouldn't be required to enter an exact match. @@ -189,17 +173,14 @@ def get_dict_from_list(dataDict, mapList): def choose_file_dialog(parent, title, want_folder=True): - dialog = MultiSelectionFileDialog(parent, title, os.path.expanduser('~')) + dialog = QFileDialog(parent, title, os.path.expanduser('~')) dialog.setFileMode(QFileDialog.FileMode.Directory if want_folder else QFileDialog.FileMode.ExistingFiles) dialog.setParent(parent, QtCore.Qt.WindowType.Sheet) if want_folder: - dialog.setOption(QFileDialog.Option.ShowDirsOnly) - dialog.setOption(QFileDialog.Option.DontUseNativeDialog) - dir_dialog = dialog.findChild(QTreeView) - dir_dialog.setSelectionMode(QAbstractItemView.SelectionMode.MultiSelection) - return dialog, dir_dialog - - return dialog + list_view = dialog.findChild(QTreeView) + list_view.setSelectionMode(QAbstractItemView.SelectionMode.MultiSelection) + dialog.exec() + return dialog.selectedFiles() def is_ssh_private_key_file(filepath: str) -> bool: diff --git a/src/vorta/views/source_tab.py b/src/vorta/views/source_tab.py index 09461c80e..f97834740 100644 --- a/src/vorta/views/source_tab.py +++ b/src/vorta/views/source_tab.py @@ -286,8 +286,7 @@ def sources_update(self): self.update_path_info(row) # Update data for each entry def source_add(self, want_folder): - def receive(): - dirs = dialog.selectedFiles(dir_dialog) if want_folder else dialog.selectedFiles() + def receive(dirs): for dir in dirs: if not os.access(dir, os.R_OK): msg = QMessageBox() @@ -301,11 +300,9 @@ def receive(): new_source.save() msg = self.tr("Choose directory to back up") if want_folder else self.tr("Choose file(s) to back up") - if want_folder: - dialog, dir_dialog = choose_file_dialog(self, msg, want_folder=want_folder) - else: - dialog = choose_file_dialog(self, msg, want_folder=want_folder) - dialog.open(receive) + + paths = choose_file_dialog(self, msg, want_folder=want_folder) + receive(paths) def source_copy(self, index=None): """ From fbe527e0a7fdc00143912f275d0ddc9ba031f66a Mon Sep 17 00:00:00 2001 From: Sam Date: Sun, 17 Dec 2023 00:55:42 +0530 Subject: [PATCH 6/8] Selection of multiple directories working now. Co-authored-by: real-yfprojects --- requirements.d/dev.txt | 1 - 1 file changed, 1 deletion(-) diff --git a/requirements.d/dev.txt b/requirements.d/dev.txt index 9cc3cc9c8..5391c54a0 100644 --- a/requirements.d/dev.txt +++ b/requirements.d/dev.txt @@ -3,7 +3,6 @@ coverage flake8 macholib nox -peewee pkgconfig pre-commit pyinstaller From 5ae4527ae2f347f89a53cea085693f3fdd5abb4d Mon Sep 17 00:00:00 2001 From: Sam Date: Tue, 20 Feb 2024 16:38:44 +0530 Subject: [PATCH 7/8] feat: directories multiselections --- src/vorta/utils.py | 5 +++-- src/vorta/views/archive_tab.py | 3 ++- src/vorta/views/repo_add_dialog.py | 3 ++- src/vorta/views/source_tab.py | 8 +++++--- tests/integration/conftest.py | 3 +++ tests/unit/conftest.py | 3 +++ tests/unit/test_archives.py | 3 +++ 7 files changed, 21 insertions(+), 7 deletions(-) diff --git a/src/vorta/utils.py b/src/vorta/utils.py index 46b392c3a..de20e797c 100644 --- a/src/vorta/utils.py +++ b/src/vorta/utils.py @@ -177,10 +177,11 @@ def choose_file_dialog(parent, title, want_folder=True): dialog.setFileMode(QFileDialog.FileMode.Directory if want_folder else QFileDialog.FileMode.ExistingFiles) dialog.setParent(parent, QtCore.Qt.WindowType.Sheet) if want_folder: + dialog.setOption(QFileDialog.Option.ShowDirsOnly) list_view = dialog.findChild(QTreeView) list_view.setSelectionMode(QAbstractItemView.SelectionMode.MultiSelection) - dialog.exec() - return dialog.selectedFiles() + + return dialog def is_ssh_private_key_file(filepath: str) -> bool: diff --git a/src/vorta/views/archive_tab.py b/src/vorta/views/archive_tab.py index d2af5757b..7ef851d36 100644 --- a/src/vorta/views/archive_tab.py +++ b/src/vorta/views/archive_tab.py @@ -642,7 +642,8 @@ def receive(): self.app.jobs_manager.add_job(job) dialog = choose_file_dialog(self, self.tr("Choose Mount Point"), want_folder=True) - dialog.open(receive) + dialog.exec() + receive() def mount_result(self, result): if result['returncode'] == 0: diff --git a/src/vorta/views/repo_add_dialog.py b/src/vorta/views/repo_add_dialog.py index cd265a333..d0d22c29d 100644 --- a/src/vorta/views/repo_add_dialog.py +++ b/src/vorta/views/repo_add_dialog.py @@ -72,7 +72,8 @@ def receive(): self.is_remote_repo = False dialog = choose_file_dialog(self, self.tr("Choose Location of Borg Repository")) - dialog.open(receive) + dialog.exec() + receive() def use_remote_repo_action(self): self.repoURL.setText('') diff --git a/src/vorta/views/source_tab.py b/src/vorta/views/source_tab.py index f97834740..158d932b2 100644 --- a/src/vorta/views/source_tab.py +++ b/src/vorta/views/source_tab.py @@ -286,7 +286,8 @@ def sources_update(self): self.update_path_info(row) # Update data for each entry def source_add(self, want_folder): - def receive(dirs): + def receive(): + dirs = dialog.selectedFiles() for dir in dirs: if not os.access(dir, os.R_OK): msg = QMessageBox() @@ -301,8 +302,9 @@ def receive(dirs): msg = self.tr("Choose directory to back up") if want_folder else self.tr("Choose file(s) to back up") - paths = choose_file_dialog(self, msg, want_folder=want_folder) - receive(paths) + dialog = choose_file_dialog(self, msg, want_folder) + dialog.exec() + receive() def source_copy(self, index=None): """ diff --git a/tests/integration/conftest.py b/tests/integration/conftest.py index 683271f54..8dffd8d7a 100644 --- a/tests/integration/conftest.py +++ b/tests/integration/conftest.py @@ -190,6 +190,9 @@ def __init__(self, *args, **kwargs): def open(self, func): func() + def exec(self): + return 1 + def selectedFiles(self): if self.subdirectory: return [str(tmpdir.join(self.subdirectory))] diff --git a/tests/unit/conftest.py b/tests/unit/conftest.py index e622a2118..2d689d40e 100644 --- a/tests/unit/conftest.py +++ b/tests/unit/conftest.py @@ -86,6 +86,9 @@ def __init__(self, *args, **kwargs): def open(self, func): func() + def exec(self): + return 1 + def selectedFiles(self): return ['/tmp'] diff --git a/tests/unit/test_archives.py b/tests/unit/test_archives.py index e0a7fb1aa..3a04f1470 100644 --- a/tests/unit/test_archives.py +++ b/tests/unit/test_archives.py @@ -14,6 +14,9 @@ class MockFileDialog: def open(self, func): func() + def exec(self): + return 1 + def selectedFiles(self): return ['/tmp'] From 28d60348008e88fcb336a519d410d80128c8fc70 Mon Sep 17 00:00:00 2001 From: Sam Date: Mon, 8 Apr 2024 18:40:10 +0530 Subject: [PATCH 8/8] minor change --- src/vorta/utils.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/vorta/utils.py b/src/vorta/utils.py index de20e797c..7ace88bed 100644 --- a/src/vorta/utils.py +++ b/src/vorta/utils.py @@ -19,8 +19,8 @@ QAbstractItemView, QApplication, QFileDialog, + QListView, QSystemTrayIcon, - QTreeView, ) from vorta.borg._compatibility import BorgCompatibility @@ -178,8 +178,9 @@ def choose_file_dialog(parent, title, want_folder=True): dialog.setParent(parent, QtCore.Qt.WindowType.Sheet) if want_folder: dialog.setOption(QFileDialog.Option.ShowDirsOnly) - list_view = dialog.findChild(QTreeView) - list_view.setSelectionMode(QAbstractItemView.SelectionMode.MultiSelection) + list_view = dialog.findChild(QListView) + if list_view: + list_view.setSelectionMode(QAbstractItemView.SelectionMode.MultiSelection) return dialog