Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
81 changes: 81 additions & 0 deletions src/vorta/views/archive/archive_diff.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
from PyQt6.QtCore import Qt

from vorta.borg.diff import BorgDiffJob
from vorta.store.models import ArchiveModel
from vorta.views.dialogs.archive import diff_result
from vorta.views.dialogs.archive.diff_result import DiffResultDialog, DiffTree


class ArchiveDiff:
def __init__(self, tab):
self.tab = tab

def diff_action(self):
"""
Handle the diff button being clicked.

Exactly two archives must be selected in `archiveTable`. This is
usually enforced by `on_selection_change`.
"""
archives = self.tab.selected_archives()
profile = self.tab.profile()

name1 = archives[0].name
name2 = archives[1].name

archive1, archive2 = (
profile.repo.archives.select()
.where((ArchiveModel.name == name1) | (ArchiveModel.name == name2))
.order_by(ArchiveModel.time.desc())
)

archive_name_newer = archive1.name
archive_name_older = archive2.name

# Start diff job
params = BorgDiffJob.prepare(profile, archive_name_older, archive_name_newer)

if params['ok']:
self.tab._toggle_all_buttons(False)
job = BorgDiffJob(params['cmd'], params, self.tab.profile().repo.id)
job.updated.connect(self.tab.mountErrors.setText)
job.result.connect(self.list_diff_result)
self.tab.app.jobs_manager.add_job(job)
else:
self.tab._set_status(params['message'])

def list_diff_result(self, result):
"""
Process the result of the `BorgDiffJob`.

The `BorgDiffJob` was initiated by `diff_action`.

Parameters
----------
result : dict
The BorgJob result.
"""
self.tab._set_status('')
if result['returncode'] == 0:
archive_newer = ArchiveModel.get(name=result['params']['archive_name_newer'])
archive_older = ArchiveModel.get(name=result['params']['archive_name_older'])
self.tab._set_status(self.tab.tr("Processing diff results."))

model = DiffTree()

self.tab._t = diff_result.ParseThread(result['data'], result['params']['json_lines'], model)
self.tab._t.finished.connect(lambda: self.show_diff_result(archive_newer, archive_older, model))
self.tab._t.start()

def show_diff_result(self, archive_newer, archive_older, model):
self.tab._t = None

# show dialog
self.tab._toggle_all_buttons(True)
self.tab._set_status('')
window = DiffResultDialog(archive_newer, archive_older, model)
window.setParent(self.tab)
window.setWindowFlags(Qt.WindowType.Window)
window.setWindowModality(Qt.WindowModality.NonModal)
self.tab._resultwindow = window # for testing
window.show()
92 changes: 92 additions & 0 deletions src/vorta/views/archive/archive_rename.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
from PyQt6 import QtCore
from PyQt6.QtCore import Qt
from PyQt6.QtGui import QDesktopServices

from vorta.borg.rename import BorgRenameJob
from vorta.store.models import ArchiveModel
from vorta.views.partials.archive_table_model import ArchiveTableModel


class ArchiveRename:
def __init__(self, tab):
self.tab = tab

def cell_double_clicked(self, index=None):
"""Open a mounted archive's folder, or start an in-place rename."""
if isinstance(index, QtCore.QModelIndex) and index.isValid():
column = index.column()
else:
index = self.tab.archiveTable.currentIndex()
column = ArchiveTableModel.COL_NAME

if not index.isValid():
return

if column == ArchiveTableModel.COL_MOUNT:
archive = index.data(ArchiveTableModel.ArchiveRole)
mount_point = self.tab.mount_points.get(archive.name) if archive else None
if mount_point is not None:
QDesktopServices.openUrl(QtCore.QUrl(f'file:///{mount_point}'))
return

if column == ArchiveTableModel.COL_NAME:
if not self.tab.bRename.isEnabled():
return
archive = index.data(ArchiveTableModel.ArchiveRole)
if archive is None:
return
self.tab.renamed_archive_original_name = archive.name
self.tab.is_editing = True
self.tab.archiveTable.edit(index.siblingAtColumn(ArchiveTableModel.COL_NAME))

def on_name_edited(self, top_left, bottom_right, roles=None):
"""Handle a committed in-place name edit (model `dataChanged` from the Name column)."""
if not self.tab.is_editing or top_left.column() != ArchiveTableModel.COL_NAME:
return
self.tab.is_editing = False

archive = top_left.data(ArchiveTableModel.ArchiveRole)
original = self.tab.renamed_archive_original_name
new_name = archive.name if archive else ''
profile = self.tab.profile()

if new_name == original:
return

if not new_name:
self._revert_name(top_left, original)
self.tab._set_status(self.tab.tr('Archive name cannot be blank.'))
return

if ArchiveModel.get_or_none(name=new_name, repo=profile.repo) is not None:
self.tab._set_status(self.tab.tr('An archive with this name already exists.'))
self._revert_name(top_left, original)
return

params = BorgRenameJob.prepare(profile, original, new_name)
if not params['ok']:
self.tab._set_status(params['message'])
self._revert_name(top_left, original)
return

self.tab._set_status(self.tab.tr('Renaming archive...'))
job = BorgRenameJob(params['cmd'], params, profile.repo.id)
job.updated.connect(self.tab._set_status)
job.result.connect(self.rename_result)
self.tab._toggle_all_buttons(False)
self.tab.app.jobs_manager.add_job(job)

def _revert_name(self, index, original):
"""Restore the model's name after a rejected edit."""
self.tab.archive_model.setData(index, original, Qt.ItemDataRole.EditRole)

def rename_result(self, result):
if result['returncode'] == 0:
self.tab.refresh_archive_info()
self.tab._set_status(self.tab.tr('Archive renamed.'))
self.tab.renamed_archive_original_name = None
self.tab.populate_from_profile()
else:
# rename failed: refresh from the DB to drop the optimistically-applied name
self.tab.renamed_archive_original_name = None
self.tab.populate_from_profile(preserve_view=True)
Loading
Loading