From 82faa4aa08459f93356d2130f6e06a5793f96ae4 Mon Sep 17 00:00:00 2001 From: Vandal <86826719+VandalByte@users.noreply.github.com> Date: Tue, 24 Jun 2025 19:31:55 +0530 Subject: [PATCH 1/9] Do button testing --- src/vorta/assets/UI/exclude_dialog.ui | 80 +++++++++++++-------------- 1 file changed, 40 insertions(+), 40 deletions(-) diff --git a/src/vorta/assets/UI/exclude_dialog.ui b/src/vorta/assets/UI/exclude_dialog.ui index 793ad3fdc..ade897230 100644 --- a/src/vorta/assets/UI/exclude_dialog.ui +++ b/src/vorta/assets/UI/exclude_dialog.ui @@ -97,46 +97,46 @@ - - Exclude If Present - - - - - - true - - - - - - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - - - - - - - - + + Exclude If Present + + + + + + true + + + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + + + + Preview From 156a4c725e2e62ec8db97ee17993bf67ac273a57 Mon Sep 17 00:00:00 2001 From: Vandal <86826719+VandalByte@users.noreply.github.com> Date: Fri, 11 Jul 2025 20:08:55 +0530 Subject: [PATCH 2/9] Update layout design --- src/vorta/assets/UI/exclude_dialog.ui | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/vorta/assets/UI/exclude_dialog.ui b/src/vorta/assets/UI/exclude_dialog.ui index ade897230..370f2d973 100644 --- a/src/vorta/assets/UI/exclude_dialog.ui +++ b/src/vorta/assets/UI/exclude_dialog.ui @@ -52,6 +52,13 @@ + + + + Exclude Files/Folders + + + From 7c2d6a6443ef849ce57d0b941a549381195e07f8 Mon Sep 17 00:00:00 2001 From: Vandal <86826719+VandalByte@users.noreply.github.com> Date: Sun, 20 Jul 2025 18:52:57 +0530 Subject: [PATCH 3/9] Connect file dialog to button --- src/vorta/views/exclude_dialog.py | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/src/vorta/views/exclude_dialog.py b/src/vorta/views/exclude_dialog.py index 261d2667f..34dd6b1c9 100644 --- a/src/vorta/views/exclude_dialog.py +++ b/src/vorta/views/exclude_dialog.py @@ -1,14 +1,9 @@ from PyQt6 import uic from PyQt6.QtCore import QModelIndex, QObject, Qt from PyQt6.QtGui import QCursor, QStandardItem, QStandardItemModel -from PyQt6.QtWidgets import ( - QAbstractItemView, - QApplication, - QMenu, - QMessageBox, - QStyledItemDelegate, -) +from PyQt6.QtWidgets import QAbstractItemView, QApplication, QMenu, QMessageBox, QStyledItemDelegate +from vorta.filedialog import VortaFileSelector from vorta.i18n import translate from vorta.store.models import ExclusionModel from vorta.utils import get_asset @@ -87,6 +82,7 @@ def __init__(self, profile, parent=None): self.bPreviewCopy.setIcon(get_colored_icon('copy')) self.bAddPattern.clicked.connect(self.add_pattern_custom_exclusion) self.bAddPattern.setIcon(get_colored_icon('plus')) + self.bOpenExcludeFD.clicked.connect(self.open_exclude_filedialog) self.bAddPatternExcludeIfPresent.setIcon(get_colored_icon('plus')) self.bAddPatternExcludeIfPresent.clicked.connect(self.add_pattern_exclude_if_present) self.bRemovePatternExcludeIfPresent.setIcon(get_colored_icon('minus')) @@ -447,3 +443,13 @@ def eventFilter(self, source, event): self.remove_pattern() return True return QObject.eventFilter(self, source, event) + + def open_exclude_filedialog(self): + file_dialog = VortaFileSelector( + self, window_title='Exclude Files and Folders', title='Select files and folders to exclude:' + ) + paths = file_dialog.get_paths() # Selected paths from file dialog + if paths: + for path in paths: + # Add items to the list + print(path) From e20fe6b188b011f728dd876fc52bc174b49fb9bc Mon Sep 17 00:00:00 2001 From: Vandal <86826719+VandalByte@users.noreply.github.com> Date: Sun, 20 Jul 2025 19:36:08 +0530 Subject: [PATCH 4/9] Add the pattern to list --- src/vorta/views/exclude_dialog.py | 35 ++++++++++++++++++++++++++++--- 1 file changed, 32 insertions(+), 3 deletions(-) diff --git a/src/vorta/views/exclude_dialog.py b/src/vorta/views/exclude_dialog.py index 34dd6b1c9..57775b334 100644 --- a/src/vorta/views/exclude_dialog.py +++ b/src/vorta/views/exclude_dialog.py @@ -1,3 +1,6 @@ +from pathlib import Path +from typing import List + from PyQt6 import uic from PyQt6.QtCore import QModelIndex, QObject, Qt from PyQt6.QtGui import QCursor, QStandardItem, QStandardItemModel @@ -444,12 +447,38 @@ def eventFilter(self, source, event): return True return QObject.eventFilter(self, source, event) + def make_exclude_pattern_from_path(self, paths: List[str]): + ''' + Create an exclusion pattern from a list of given paths. + ''' + patterns = [] + for path in paths: + if Path(path).is_file(): + pattern = "fm:*" + path + patterns.append(pattern) + else: # folder + pattern = "fm:*" + path + "/*" + patterns.append(pattern) + return patterns + def open_exclude_filedialog(self): file_dialog = VortaFileSelector( self, window_title='Exclude Files and Folders', title='Select files and folders to exclude:' ) paths = file_dialog.get_paths() # Selected paths from file dialog if paths: - for path in paths: - # Add items to the list - print(path) + patterns = self.make_exclude_pattern_from_path(paths) + for pattern in patterns: + # Check if the path already exists in the model + if not ExclusionModel.get_or_none(name=pattern, profile=self.profile): + # Create a new item in the list + item = QStandardItem(pattern) + item.setCheckable(True) + item.setCheckState(Qt.CheckState.Checked) + self.customExclusionsModel.appendRow(item) + + # Add the item to database + ExclusionModel.create( + name=pattern, source=ExclusionModel.SourceFieldOptions.CUSTOM.value, profile=self.profile + ) + self.populate_preview_tab() From 45ca9a50c2d5d01150e965603af5da3008f16d7e Mon Sep 17 00:00:00 2001 From: Vandal <86826719+VandalByte@users.noreply.github.com> Date: Wed, 23 Jul 2025 23:20:46 +0530 Subject: [PATCH 5/9] Add the proper pattern format --- src/vorta/views/exclude_dialog.py | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/src/vorta/views/exclude_dialog.py b/src/vorta/views/exclude_dialog.py index 57775b334..3d28030c2 100644 --- a/src/vorta/views/exclude_dialog.py +++ b/src/vorta/views/exclude_dialog.py @@ -447,18 +447,15 @@ def eventFilter(self, source, event): return True return QObject.eventFilter(self, source, event) - def make_exclude_pattern_from_path(self, paths: List[str]): + def make_exclude_pattern_from_path(self, paths: List[str]) -> List[str]: ''' - Create an exclusion pattern from a list of given paths. + Create exclusion patterns from a list of given paths. ''' patterns = [] + # Both files and folders use the same pattern format (fm:*/name), + # confirmed through testing to correctly exclude them during backup creation. for path in paths: - if Path(path).is_file(): - pattern = "fm:*" + path - patterns.append(pattern) - else: # folder - pattern = "fm:*" + path + "/*" - patterns.append(pattern) + patterns.append(f"fm:*/{Path(path).name}") return patterns def open_exclude_filedialog(self): From 7fe6633731ec58335c1b78c831a991b61c4fd43c Mon Sep 17 00:00:00 2001 From: Vandal <86826719+VandalByte@users.noreply.github.com> Date: Sun, 3 Aug 2025 20:56:21 +0530 Subject: [PATCH 6/9] Fix issue #2260 --- src/vorta/views/exclude_dialog.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vorta/views/exclude_dialog.py b/src/vorta/views/exclude_dialog.py index 3d28030c2..af179dc96 100644 --- a/src/vorta/views/exclude_dialog.py +++ b/src/vorta/views/exclude_dialog.py @@ -301,7 +301,7 @@ def text_editing_finished(self, model): ''' for row in range(model.rowCount()): item = model.item(row) - if item.text() == '': + if item is not None and item.text() == '': model.removeRow(row) def custom_pattern_editing_finished(self, editor): From 687a9bdaacf966ae0c385bc5c051161084e7d053 Mon Sep 17 00:00:00 2001 From: Vandal <86826719+VandalByte@users.noreply.github.com> Date: Mon, 4 Aug 2025 21:22:21 +0530 Subject: [PATCH 7/9] Fix the incorrect model used --- src/vorta/views/exclude_dialog.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/vorta/views/exclude_dialog.py b/src/vorta/views/exclude_dialog.py index af179dc96..4ee10f3b1 100644 --- a/src/vorta/views/exclude_dialog.py +++ b/src/vorta/views/exclude_dialog.py @@ -301,7 +301,7 @@ def text_editing_finished(self, model): ''' for row in range(model.rowCount()): item = model.item(row) - if item is not None and item.text() == '': + if item is not None and item.text().strip() == '': model.removeRow(row) def custom_pattern_editing_finished(self, editor): @@ -371,7 +371,7 @@ def add_pattern_exclude_if_present(self): self.save_exclude_if_present_patterns() def exclude_if_present_pattern_editing_finished(self, editor): - self.text_editing_finished(self.customExclusionsModel) + self.text_editing_finished(self.excludeIfPresentModel) self.save_exclude_if_present_patterns() def save_exclude_if_present_patterns(self): From 978f31d2a5c01c4d1887bd64c8261656a06effbc Mon Sep 17 00:00:00 2001 From: Vandal <86826719+VandalByte@users.noreply.github.com> Date: Sat, 23 Aug 2025 18:40:24 +0530 Subject: [PATCH 8/9] fix linting --- src/vorta/borg/create.py | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/src/vorta/borg/create.py b/src/vorta/borg/create.py index 6f1f8c5b9..1fcf0671e 100644 --- a/src/vorta/borg/create.py +++ b/src/vorta/borg/create.py @@ -4,18 +4,13 @@ import tempfile from datetime import datetime as dt +from PyQt6.QtCore import QCoreApplication + from vorta import config from vorta.i18n import trans_late, translate -from vorta.store.models import ( - ArchiveModel, - RepoModel, - SourceFileModel, - WifiSettingModel, -) +from vorta.store.models import ArchiveModel, RepoModel, SourceFileModel, WifiSettingModel from vorta.utils import borg_compat, format_archive_name, get_network_status_monitor -from PyQt6.QtCore import QCoreApplication - from .borg_job import BorgJob From 4627fa7602e8af80c20847b67b9165a9eb65d67e Mon Sep 17 00:00:00 2001 From: Vandal <86826719+VandalByte@users.noreply.github.com> Date: Fri, 29 Aug 2025 23:38:21 +0530 Subject: [PATCH 9/9] Change pattern format to 'pf' --- src/vorta/views/exclude_dialog.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vorta/views/exclude_dialog.py b/src/vorta/views/exclude_dialog.py index 0eb68e36b..6cd7d1233 100644 --- a/src/vorta/views/exclude_dialog.py +++ b/src/vorta/views/exclude_dialog.py @@ -456,7 +456,7 @@ def make_exclude_pattern_from_path(self, paths: List[str]) -> List[str]: # Both files and folders use the same pattern format (fm:*/name), # confirmed through testing to correctly exclude them during backup creation. for path in paths: - patterns.append(f"fm:*/{Path(path).name}") + patterns.append(f"pf:{path}") return patterns def open_exclude_filedialog(self):