Skip to content
87 changes: 47 additions & 40 deletions src/vorta/assets/UI/exclude_dialog.ui
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,13 @@
</property>
</spacer>
</item>
<item>
<widget class="QToolButton" name="bOpenExcludeFD">
<property name="text">
<string>Exclude Files/Folders</string>
</property>
</widget>
</item>
<item>
<widget class="QToolButton" name="bAddPattern"/>
</item>
Expand Down Expand Up @@ -97,46 +104,46 @@
</layout>
</widget>
<widget class="QWidget" name="tab_5">
<attribute name="title">
<string>Exclude If Present</string>
</attribute>
<layout class="QVBoxLayout" name="verticalLayout_5">
<item>
<widget class="QLabel" name="excludeIfPresentHelpText">
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QListView" name="excludeIfPresentList"/>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_5">
<item>
<spacer name="horizontalSpacer_5">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QToolButton" name="bAddPatternExcludeIfPresent"/>
</item>
<item>
<widget class="QToolButton" name="bRemovePatternExcludeIfPresent"/>
</item>
</layout>
</item>
</layout>
</widget>
<widget class="QWidget" name="tab_3">
<attribute name="title">
<string>Exclude If Present</string>
</attribute>
<layout class="QVBoxLayout" name="verticalLayout_5">
<item>
<widget class="QLabel" name="excludeIfPresentHelpText">
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QListView" name="excludeIfPresentList"/>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_5">
<item>
<spacer name="horizontalSpacer_5">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QToolButton" name="bAddPatternExcludeIfPresent"/>
</item>
<item>
<widget class="QToolButton" name="bRemovePatternExcludeIfPresent"/>
</item>
</layout>
</item>
</layout>
</widget>
<widget class="QWidget" name="tab_3">
<attribute name="title">
<string>Preview</string>
</attribute>
Expand Down
11 changes: 3 additions & 8 deletions src/vorta/borg/create.py
Original file line number Diff line number Diff line change
Expand Up @@ -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


Expand Down
50 changes: 41 additions & 9 deletions src/vorta/views/exclude_dialog.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,12 @@
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
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
Expand Down Expand Up @@ -87,6 +85,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'))
Expand Down Expand Up @@ -302,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().strip() == '':
model.removeRow(row)

def custom_pattern_editing_finished(self, editor):
Expand Down Expand Up @@ -373,7 +372,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):
Expand Down Expand Up @@ -448,3 +447,36 @@ def eventFilter(self, source, event):
self.remove_pattern()
return True
return QObject.eventFilter(self, source, event)

def make_exclude_pattern_from_path(self, paths: List[str]) -> List[str]:
'''
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.
Comment thread
VandalByte marked this conversation as resolved.
for path in paths:
patterns.append(f"pf:{path}")
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:
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):
Comment thread
VandalByte marked this conversation as resolved.
# 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()
Loading