2019-01-21 10:44:01 +00:00
|
|
|
import os.path
|
2018-11-22 01:05:54 +00:00
|
|
|
import sys
|
2018-11-01 16:53:41 +00:00
|
|
|
from datetime import timedelta
|
2019-07-04 19:17:09 +00:00
|
|
|
|
|
|
|
from PyQt5 import QtCore, uic
|
2019-02-02 02:01:09 +00:00
|
|
|
from PyQt5.QtGui import QDesktopServices
|
2019-07-04 19:17:09 +00:00
|
|
|
from PyQt5.QtWidgets import (QHeaderView, QMessageBox, QTableView,
|
|
|
|
QTableWidgetItem)
|
2018-10-27 17:24:34 +00:00
|
|
|
|
2018-11-04 15:37:46 +00:00
|
|
|
from vorta.borg.check import BorgCheckThread
|
2019-07-04 19:17:09 +00:00
|
|
|
from vorta.borg.delete import BorgDeleteThread
|
|
|
|
from vorta.borg.diff import BorgDiffThread
|
2018-11-27 11:33:16 +00:00
|
|
|
from vorta.borg.extract import BorgExtractThread
|
2019-07-04 19:17:09 +00:00
|
|
|
from vorta.borg.list_archive import BorgListArchiveThread
|
|
|
|
from vorta.borg.list_repo import BorgListRepoThread
|
|
|
|
from vorta.borg.mount import BorgMountThread
|
|
|
|
from vorta.borg.prune import BorgPruneThread
|
2018-11-22 04:06:10 +00:00
|
|
|
from vorta.borg.umount import BorgUmountThread
|
2019-02-19 13:42:19 +00:00
|
|
|
from vorta.i18n import trans_late
|
2019-07-04 19:17:09 +00:00
|
|
|
from vorta.models import ArchiveModel, BackupProfileMixin
|
|
|
|
from vorta.utils import (choose_file_dialog, format_archive_name, get_asset,
|
|
|
|
get_mount_points, pretty_bytes)
|
2020-11-29 00:51:24 +00:00
|
|
|
from vorta.views.source_tab import SizeItem
|
2019-07-04 19:17:09 +00:00
|
|
|
from vorta.views.diff_dialog import DiffDialog
|
|
|
|
from vorta.views.diff_result import DiffResult
|
|
|
|
from vorta.views.extract_dialog import ExtractDialog
|
2020-05-31 11:29:26 +00:00
|
|
|
from vorta.views.utils import get_colored_icon
|
2018-10-27 17:24:34 +00:00
|
|
|
|
2018-11-22 01:18:12 +00:00
|
|
|
uifile = get_asset('UI/archivetab.ui')
|
2020-05-31 11:29:26 +00:00
|
|
|
ArchiveTabUI, ArchiveTabBase = uic.loadUiType(uifile)
|
2018-10-27 17:24:34 +00:00
|
|
|
|
|
|
|
|
2018-11-22 01:18:12 +00:00
|
|
|
class ArchiveTab(ArchiveTabBase, ArchiveTabUI, BackupProfileMixin):
|
2018-11-04 08:23:17 +00:00
|
|
|
prune_intervals = ['hour', 'day', 'week', 'month', 'year']
|
|
|
|
|
2020-10-30 05:17:24 +00:00
|
|
|
def __init__(self, parent=None, app=None):
|
2018-10-27 17:24:34 +00:00
|
|
|
super().__init__(parent)
|
|
|
|
self.setupUi(parent)
|
2019-01-21 10:44:01 +00:00
|
|
|
self.mount_points = {}
|
|
|
|
self.menu = None
|
2020-10-30 05:17:24 +00:00
|
|
|
self.app = app
|
2018-12-14 08:03:26 +00:00
|
|
|
self.toolBox.setCurrentIndex(0)
|
2018-10-27 17:24:34 +00:00
|
|
|
|
2018-11-22 01:18:12 +00:00
|
|
|
header = self.archiveTable.horizontalHeader()
|
2018-10-27 17:24:34 +00:00
|
|
|
header.setVisible(True)
|
2018-11-02 06:06:25 +00:00
|
|
|
header.setSectionResizeMode(0, QHeaderView.ResizeToContents)
|
2018-10-27 17:24:34 +00:00
|
|
|
header.setSectionResizeMode(1, QHeaderView.ResizeToContents)
|
2018-11-01 16:53:41 +00:00
|
|
|
header.setSectionResizeMode(2, QHeaderView.ResizeToContents)
|
2019-01-28 00:41:42 +00:00
|
|
|
header.setSectionResizeMode(3, QHeaderView.Interactive)
|
2019-01-21 10:44:01 +00:00
|
|
|
header.setSectionResizeMode(4, QHeaderView.Stretch)
|
2018-11-22 05:48:16 +00:00
|
|
|
header.setStretchLastSection(True)
|
2018-10-27 17:24:34 +00:00
|
|
|
|
2018-11-22 01:05:54 +00:00
|
|
|
if sys.platform != 'darwin':
|
|
|
|
self._set_status('') # Set platform-specific hints.
|
|
|
|
|
2018-11-22 01:18:12 +00:00
|
|
|
self.archiveTable.setSelectionBehavior(QTableView.SelectRows)
|
2019-01-21 10:44:01 +00:00
|
|
|
self.archiveTable.setSelectionMode(QTableView.SingleSelection)
|
2018-11-22 01:18:12 +00:00
|
|
|
self.archiveTable.setEditTriggers(QTableView.NoEditTriggers)
|
2019-01-28 00:41:42 +00:00
|
|
|
self.archiveTable.setWordWrap(False)
|
|
|
|
self.archiveTable.setTextElideMode(QtCore.Qt.ElideLeft)
|
2018-11-22 07:03:19 +00:00
|
|
|
self.archiveTable.setAlternatingRowColors(True)
|
2019-01-21 10:44:01 +00:00
|
|
|
self.archiveTable.cellDoubleClicked.connect(self.cell_double_clicked)
|
|
|
|
self.archiveTable.itemSelectionChanged.connect(self.update_mount_button_text)
|
2019-10-02 04:05:40 +00:00
|
|
|
self.archiveTable.setSortingEnabled(True)
|
2018-10-27 17:24:34 +00:00
|
|
|
|
2018-11-04 15:37:46 +00:00
|
|
|
self.mountButton.clicked.connect(self.mount_action)
|
2018-11-04 08:23:17 +00:00
|
|
|
self.listButton.clicked.connect(self.list_action)
|
|
|
|
self.pruneButton.clicked.connect(self.prune_action)
|
2018-11-04 15:37:46 +00:00
|
|
|
self.checkButton.clicked.connect(self.check_action)
|
2018-11-27 11:33:16 +00:00
|
|
|
self.extractButton.clicked.connect(self.list_archive_action)
|
2019-07-04 19:17:09 +00:00
|
|
|
self.diffButton.clicked.connect(self.diff_action)
|
2019-01-24 00:36:44 +00:00
|
|
|
self.deleteButton.clicked.connect(self.delete_action)
|
2018-10-27 17:24:34 +00:00
|
|
|
|
2018-12-14 08:03:26 +00:00
|
|
|
self.archiveNameTemplate.textChanged.connect(
|
|
|
|
lambda tpl, key='new_archive_name': self.save_archive_template(tpl, key))
|
|
|
|
self.prunePrefixTemplate.textChanged.connect(
|
|
|
|
lambda tpl, key='prune_prefix': self.save_archive_template(tpl, key))
|
|
|
|
|
2018-11-17 08:51:53 +00:00
|
|
|
self.populate_from_profile()
|
2020-05-31 11:29:26 +00:00
|
|
|
self.set_icons()
|
2018-10-27 17:24:34 +00:00
|
|
|
|
2020-03-23 06:20:09 +00:00
|
|
|
self.selected_archives = None
|
|
|
|
|
2020-05-31 11:29:26 +00:00
|
|
|
def set_icons(self):
|
|
|
|
self.extractButton.setIcon(get_colored_icon('cloud-download'))
|
|
|
|
self.mountButton.setIcon(get_colored_icon('folder-open'))
|
|
|
|
self.checkButton.setIcon(get_colored_icon('check-circle'))
|
|
|
|
self.deleteButton.setIcon(get_colored_icon('trash'))
|
|
|
|
self.diffButton.setIcon(get_colored_icon('stream-solid'))
|
|
|
|
self.pruneButton.setIcon(get_colored_icon('cut'))
|
|
|
|
self.listButton.setIcon(get_colored_icon('refresh'))
|
|
|
|
self.toolBox.setItemIcon(0, get_colored_icon('tasks'))
|
|
|
|
self.toolBox.setItemIcon(1, get_colored_icon('cut'))
|
|
|
|
|
2021-01-20 05:07:32 +00:00
|
|
|
def cancel_action(self):
|
|
|
|
self._set_status(self.tr("Action cancelled."))
|
|
|
|
self._toggle_all_buttons(True)
|
|
|
|
|
2018-11-04 15:37:46 +00:00
|
|
|
def _set_status(self, text):
|
2018-10-28 15:40:38 +00:00
|
|
|
self.mountErrors.setText(text)
|
|
|
|
self.mountErrors.repaint()
|
|
|
|
|
2018-11-04 15:37:46 +00:00
|
|
|
def _toggle_all_buttons(self, enabled=True):
|
2019-01-24 00:36:44 +00:00
|
|
|
for button in [self.checkButton, self.listButton, self.pruneButton,
|
2019-07-04 19:17:09 +00:00
|
|
|
self.mountButton, self.extractButton, self.deleteButton,
|
|
|
|
self.diffButton]:
|
2018-11-27 11:33:16 +00:00
|
|
|
button.setEnabled(enabled)
|
|
|
|
button.repaint()
|
2018-11-04 15:37:46 +00:00
|
|
|
|
2018-11-17 08:51:53 +00:00
|
|
|
def populate_from_profile(self):
|
2018-11-27 11:33:16 +00:00
|
|
|
"""Populate archive list and prune settings from profile."""
|
2018-11-17 08:51:53 +00:00
|
|
|
profile = self.profile()
|
2018-11-20 04:06:09 +00:00
|
|
|
if profile.repo is not None:
|
2019-01-21 10:44:01 +00:00
|
|
|
self.mount_points = get_mount_points(profile.repo.url)
|
2019-01-20 03:50:10 +00:00
|
|
|
self.toolBox.setItemText(0, self.tr('Archives for %s') % profile.repo.url)
|
2018-11-22 05:48:16 +00:00
|
|
|
archives = [s for s in profile.repo.archives.select().order_by(ArchiveModel.time.desc())]
|
2018-10-27 17:24:34 +00:00
|
|
|
|
2018-11-22 05:48:16 +00:00
|
|
|
for row, archive in enumerate(archives):
|
2018-11-22 01:18:12 +00:00
|
|
|
self.archiveTable.insertRow(row)
|
2018-11-22 05:48:16 +00:00
|
|
|
|
|
|
|
formatted_time = archive.time.strftime('%Y-%m-%d %H:%M')
|
2018-11-22 01:18:12 +00:00
|
|
|
self.archiveTable.setItem(row, 0, QTableWidgetItem(formatted_time))
|
2020-11-29 00:51:24 +00:00
|
|
|
self.archiveTable.setItem(row, 1, SizeItem(pretty_bytes(archive.size)))
|
2018-11-22 05:48:16 +00:00
|
|
|
if archive.duration is not None:
|
|
|
|
formatted_duration = str(timedelta(seconds=round(archive.duration)))
|
2018-11-01 16:53:41 +00:00
|
|
|
else:
|
2018-11-22 05:48:16 +00:00
|
|
|
formatted_duration = ''
|
2019-01-21 10:44:01 +00:00
|
|
|
|
2018-11-22 01:18:12 +00:00
|
|
|
self.archiveTable.setItem(row, 2, QTableWidgetItem(formatted_duration))
|
2019-01-21 10:44:01 +00:00
|
|
|
|
|
|
|
mount_point = self.mount_points.get(archive.name)
|
|
|
|
if mount_point is not None:
|
2019-01-28 00:41:42 +00:00
|
|
|
item = QTableWidgetItem(mount_point)
|
2019-01-21 10:44:01 +00:00
|
|
|
self.archiveTable.setItem(row, 3, item)
|
|
|
|
|
|
|
|
self.archiveTable.setItem(row, 4, QTableWidgetItem(archive.name))
|
|
|
|
|
2018-11-22 05:48:16 +00:00
|
|
|
self.archiveTable.setRowCount(len(archives))
|
2018-11-27 11:33:16 +00:00
|
|
|
item = self.archiveTable.item(0, 0)
|
|
|
|
self.archiveTable.scrollToItem(item)
|
2018-11-17 08:51:53 +00:00
|
|
|
self._toggle_all_buttons(enabled=True)
|
2018-11-02 11:14:54 +00:00
|
|
|
else:
|
2019-01-21 10:44:01 +00:00
|
|
|
self.mount_points = {}
|
2018-11-22 01:18:12 +00:00
|
|
|
self.archiveTable.setRowCount(0)
|
2019-01-20 03:50:10 +00:00
|
|
|
self.toolBox.setItemText(0, self.tr('Archives'))
|
2018-11-17 08:51:53 +00:00
|
|
|
self._toggle_all_buttons(enabled=False)
|
2018-11-04 15:37:46 +00:00
|
|
|
|
2018-12-14 08:03:26 +00:00
|
|
|
self.archiveNameTemplate.setText(profile.new_archive_name)
|
|
|
|
self.prunePrefixTemplate.setText(profile.prune_prefix)
|
|
|
|
|
2019-08-21 12:54:00 +00:00
|
|
|
# Populate pruning options from database
|
|
|
|
profile = self.profile()
|
|
|
|
for i in self.prune_intervals:
|
|
|
|
getattr(self, f'prune_{i}').setValue(getattr(profile, f'prune_{i}'))
|
|
|
|
getattr(self, f'prune_{i}').valueChanged.connect(self.save_prune_setting)
|
|
|
|
self.prune_keep_within.setText(profile.prune_keep_within)
|
|
|
|
self.prune_keep_within.editingFinished.connect(self.save_prune_setting)
|
|
|
|
|
2018-12-14 08:03:26 +00:00
|
|
|
def save_archive_template(self, tpl, key):
|
|
|
|
profile = self.profile()
|
|
|
|
try:
|
2019-01-20 03:50:10 +00:00
|
|
|
preview = self.tr('Preview: %s') % format_archive_name(profile, tpl)
|
2018-12-14 08:03:26 +00:00
|
|
|
setattr(profile, key, tpl)
|
|
|
|
profile.save()
|
|
|
|
except Exception:
|
2019-01-20 03:50:10 +00:00
|
|
|
preview = self.tr('Error in archive name template.')
|
2018-12-14 08:03:26 +00:00
|
|
|
|
|
|
|
if key == 'new_archive_name':
|
|
|
|
self.archiveNamePreview.setText(preview)
|
|
|
|
else:
|
|
|
|
self.prunePrefixPreview.setText(preview)
|
|
|
|
|
2018-11-04 15:37:46 +00:00
|
|
|
def check_action(self):
|
|
|
|
params = BorgCheckThread.prepare(self.profile())
|
2018-11-23 13:33:31 +00:00
|
|
|
if not params['ok']:
|
2019-02-19 13:42:19 +00:00
|
|
|
self._set_status(params['message'])
|
2018-11-23 13:33:31 +00:00
|
|
|
return
|
|
|
|
|
|
|
|
# Conditions are met (borg binary available, etc)
|
|
|
|
row_selected = self.archiveTable.selectionModel().selectedRows()
|
|
|
|
if row_selected:
|
2019-01-21 10:44:01 +00:00
|
|
|
archive_cell = self.archiveTable.item(row_selected[0].row(), 4)
|
2019-01-20 03:50:10 +00:00
|
|
|
if archive_cell:
|
|
|
|
archive_name = archive_cell.text()
|
|
|
|
params['cmd'][-1] += f'::{archive_name}'
|
2018-11-23 13:33:31 +00:00
|
|
|
|
2020-10-30 05:17:24 +00:00
|
|
|
thread = BorgCheckThread(params['cmd'], params, parent=self.app)
|
2018-11-23 13:33:31 +00:00
|
|
|
thread.updated.connect(self._set_status)
|
|
|
|
thread.result.connect(self.check_result)
|
|
|
|
self._toggle_all_buttons(False)
|
|
|
|
thread.start()
|
2018-11-04 15:37:46 +00:00
|
|
|
|
|
|
|
def check_result(self, result):
|
|
|
|
if result['returncode'] == 0:
|
|
|
|
self._toggle_all_buttons(True)
|
|
|
|
|
2018-11-04 08:23:17 +00:00
|
|
|
def prune_action(self):
|
2018-11-04 15:37:46 +00:00
|
|
|
params = BorgPruneThread.prepare(self.profile())
|
2018-11-04 08:23:17 +00:00
|
|
|
if params['ok']:
|
2020-10-30 05:17:24 +00:00
|
|
|
thread = BorgPruneThread(params['cmd'], params, parent=self.app)
|
2018-11-04 15:37:46 +00:00
|
|
|
thread.updated.connect(self._set_status)
|
2018-11-04 08:23:17 +00:00
|
|
|
thread.result.connect(self.prune_result)
|
2018-11-04 15:37:46 +00:00
|
|
|
self._toggle_all_buttons(False)
|
2018-11-04 08:23:17 +00:00
|
|
|
thread.start()
|
|
|
|
|
|
|
|
def prune_result(self, result):
|
|
|
|
if result['returncode'] == 0:
|
2019-01-20 03:50:10 +00:00
|
|
|
self._set_status(self.tr('Pruning finished.'))
|
2018-11-04 08:23:17 +00:00
|
|
|
self.list_action()
|
|
|
|
else:
|
2018-11-04 15:37:46 +00:00
|
|
|
self._toggle_all_buttons(True)
|
2018-11-04 08:23:17 +00:00
|
|
|
|
|
|
|
def list_action(self):
|
2018-11-27 11:33:16 +00:00
|
|
|
params = BorgListRepoThread.prepare(self.profile())
|
2018-11-04 08:23:17 +00:00
|
|
|
if params['ok']:
|
2020-10-30 05:17:24 +00:00
|
|
|
thread = BorgListRepoThread(params['cmd'], params, parent=self.app)
|
2018-11-04 15:37:46 +00:00
|
|
|
thread.updated.connect(self._set_status)
|
2018-11-04 08:23:17 +00:00
|
|
|
thread.result.connect(self.list_result)
|
2018-11-04 15:37:46 +00:00
|
|
|
self._toggle_all_buttons(False)
|
2018-11-04 08:23:17 +00:00
|
|
|
thread.start()
|
|
|
|
|
|
|
|
def list_result(self, result):
|
2018-11-04 15:37:46 +00:00
|
|
|
self._toggle_all_buttons(True)
|
2018-11-04 08:23:17 +00:00
|
|
|
if result['returncode'] == 0:
|
2019-01-20 03:50:10 +00:00
|
|
|
self._set_status(self.tr('Refreshed archives.'))
|
2018-11-17 08:51:53 +00:00
|
|
|
self.populate_from_profile()
|
2018-11-04 08:23:17 +00:00
|
|
|
|
2019-01-21 10:44:01 +00:00
|
|
|
def selected_archive_name(self):
|
|
|
|
row_selected = self.archiveTable.selectionModel().selectedRows()
|
|
|
|
if row_selected:
|
|
|
|
archive_cell = self.archiveTable.item(row_selected[0].row(), 4)
|
|
|
|
if archive_cell:
|
|
|
|
return archive_cell.text()
|
|
|
|
return None
|
|
|
|
|
|
|
|
def set_mount_button_mode(self, mode):
|
|
|
|
self.mountButton.clicked.disconnect()
|
|
|
|
mount = (mode == 'Mount')
|
2019-04-07 07:28:02 +00:00
|
|
|
self.mountButton.setText(self.tr('Mount') if mount else self.tr('Unmount'))
|
2019-01-21 10:44:01 +00:00
|
|
|
self.mountButton.clicked.connect(self.mount_action if mount else self.umount_action)
|
|
|
|
|
2018-11-04 15:37:46 +00:00
|
|
|
def mount_action(self):
|
2018-11-04 08:23:17 +00:00
|
|
|
profile = self.profile()
|
2018-11-04 15:37:46 +00:00
|
|
|
params = BorgMountThread.prepare(profile)
|
2018-11-13 00:12:17 +00:00
|
|
|
if not params['ok']:
|
2019-02-19 13:42:19 +00:00
|
|
|
self._set_status(params['message'])
|
2018-11-13 00:12:17 +00:00
|
|
|
return
|
|
|
|
|
|
|
|
# Conditions are met (borg binary available, etc)
|
2019-01-21 10:44:01 +00:00
|
|
|
archive_name = self.selected_archive_name()
|
|
|
|
if archive_name:
|
|
|
|
params['cmd'][-1] += f'::{archive_name}'
|
|
|
|
params['current_archive'] = archive_name
|
2018-10-27 17:24:34 +00:00
|
|
|
|
2018-11-20 00:50:52 +00:00
|
|
|
def receive():
|
2018-11-22 04:06:10 +00:00
|
|
|
mount_point = dialog.selectedFiles()
|
|
|
|
if mount_point:
|
|
|
|
params['cmd'].append(mount_point[0])
|
2019-04-07 07:28:02 +00:00
|
|
|
if params.get('current_archive', False):
|
|
|
|
self.mount_points[params['current_archive']] = mount_point[0]
|
2018-11-20 00:50:52 +00:00
|
|
|
if params['ok']:
|
|
|
|
self._toggle_all_buttons(False)
|
2020-10-30 05:17:24 +00:00
|
|
|
thread = BorgMountThread(params['cmd'], params, parent=self.app)
|
2018-11-20 00:50:52 +00:00
|
|
|
thread.updated.connect(self.mountErrors.setText)
|
|
|
|
thread.result.connect(self.mount_result)
|
|
|
|
thread.start()
|
|
|
|
|
2019-01-21 10:44:01 +00:00
|
|
|
dialog = choose_file_dialog(self, self.tr("Choose Mount Point"), want_folder=True)
|
2018-11-20 00:50:52 +00:00
|
|
|
dialog.open(receive)
|
|
|
|
|
2018-11-04 15:37:46 +00:00
|
|
|
def mount_result(self, result):
|
|
|
|
self._toggle_all_buttons(True)
|
2018-10-27 17:24:34 +00:00
|
|
|
if result['returncode'] == 0:
|
2019-01-20 03:50:10 +00:00
|
|
|
self._set_status(self.tr('Mounted successfully.'))
|
2019-01-21 10:44:01 +00:00
|
|
|
self.update_mount_button_text()
|
2019-04-07 07:28:02 +00:00
|
|
|
if result['params'].get('current_archive'):
|
|
|
|
archive_name = result['params']['current_archive']
|
|
|
|
row = self.row_of_archive(archive_name)
|
|
|
|
item = QTableWidgetItem(result['cmd'][-1])
|
|
|
|
self.archiveTable.setItem(row, 3, item)
|
2018-11-22 04:06:10 +00:00
|
|
|
|
|
|
|
def umount_action(self):
|
2019-01-21 10:44:01 +00:00
|
|
|
archive_name = self.selected_archive_name()
|
|
|
|
|
|
|
|
mount_point = self.mount_points.get(archive_name)
|
|
|
|
|
|
|
|
if mount_point is not None:
|
2018-11-22 04:06:10 +00:00
|
|
|
profile = self.profile()
|
|
|
|
params = BorgUmountThread.prepare(profile)
|
|
|
|
if not params['ok']:
|
2019-02-19 13:42:19 +00:00
|
|
|
self._set_status(params['message'])
|
2018-11-22 04:06:10 +00:00
|
|
|
return
|
|
|
|
|
2019-01-21 10:44:01 +00:00
|
|
|
params['current_archive'] = archive_name
|
|
|
|
|
|
|
|
if os.path.normpath(mount_point) in params['active_mount_points']:
|
|
|
|
params['cmd'].append(mount_point)
|
2020-10-30 05:17:24 +00:00
|
|
|
thread = BorgUmountThread(params['cmd'], params, parent=self.app)
|
2018-11-22 04:06:10 +00:00
|
|
|
thread.updated.connect(self.mountErrors.setText)
|
|
|
|
thread.result.connect(self.umount_result)
|
|
|
|
thread.start()
|
|
|
|
else:
|
2019-01-21 10:44:01 +00:00
|
|
|
self._set_status(self.tr('Mount point not active.'))
|
2018-11-22 04:06:10 +00:00
|
|
|
return
|
|
|
|
|
|
|
|
def umount_result(self, result):
|
|
|
|
self._toggle_all_buttons(True)
|
2020-12-16 03:10:38 +00:00
|
|
|
archive_name = result['params']['current_archive']
|
2018-11-22 04:06:10 +00:00
|
|
|
if result['returncode'] == 0:
|
2019-01-20 03:50:10 +00:00
|
|
|
self._set_status(self.tr('Un-mounted successfully.'))
|
2019-01-21 10:44:01 +00:00
|
|
|
del self.mount_points[archive_name]
|
|
|
|
self.update_mount_button_text()
|
|
|
|
row = self.row_of_archive(archive_name)
|
|
|
|
item = QTableWidgetItem('')
|
|
|
|
self.archiveTable.setItem(row, 3, item)
|
2020-12-16 03:10:38 +00:00
|
|
|
else:
|
|
|
|
self._set_status(self.tr('Unmounting failed. Make sure no programs are using {}').format(
|
|
|
|
self.mount_points.get(archive_name)))
|
2018-11-01 16:53:41 +00:00
|
|
|
|
2018-11-24 02:01:50 +00:00
|
|
|
def save_prune_setting(self, new_value=None):
|
2018-11-04 08:23:17 +00:00
|
|
|
profile = self.profile()
|
|
|
|
for i in self.prune_intervals:
|
|
|
|
setattr(profile, f'prune_{i}', getattr(self, f'prune_{i}').value())
|
2018-11-24 02:01:50 +00:00
|
|
|
profile.prune_keep_within = self.prune_keep_within.text()
|
2018-11-04 08:23:17 +00:00
|
|
|
profile.save()
|
2018-11-22 10:25:22 +00:00
|
|
|
|
2018-11-27 11:33:16 +00:00
|
|
|
def list_archive_action(self):
|
|
|
|
profile = self.profile()
|
|
|
|
|
|
|
|
row_selected = self.archiveTable.selectionModel().selectedRows()
|
|
|
|
if row_selected:
|
2019-01-21 10:44:01 +00:00
|
|
|
archive_cell = self.archiveTable.item(row_selected[0].row(), 4)
|
2018-11-27 11:33:16 +00:00
|
|
|
if archive_cell:
|
|
|
|
archive_name = archive_cell.text()
|
|
|
|
params = BorgListArchiveThread.prepare(profile)
|
|
|
|
|
|
|
|
if not params['ok']:
|
2019-02-19 13:42:19 +00:00
|
|
|
self._set_status(params['message'])
|
2018-11-27 11:33:16 +00:00
|
|
|
return
|
|
|
|
params['cmd'][-1] += f'::{archive_name}'
|
|
|
|
params['archive_name'] = archive_name
|
|
|
|
self._set_status('')
|
|
|
|
self._toggle_all_buttons(False)
|
|
|
|
|
2020-10-30 05:17:24 +00:00
|
|
|
thread = BorgListArchiveThread(params['cmd'], params, parent=self.app)
|
2018-11-27 11:33:16 +00:00
|
|
|
thread.updated.connect(self.mountErrors.setText)
|
|
|
|
thread.result.connect(self.list_archive_result)
|
|
|
|
thread.start()
|
|
|
|
else:
|
2019-01-20 03:50:10 +00:00
|
|
|
self._set_status(self.tr('Select an archive to restore first.'))
|
2018-11-27 11:33:16 +00:00
|
|
|
|
|
|
|
def list_archive_result(self, result):
|
|
|
|
self._set_status('')
|
|
|
|
if result['returncode'] == 0:
|
2020-11-20 00:46:09 +00:00
|
|
|
def process_result():
|
2018-11-27 11:33:16 +00:00
|
|
|
def receive():
|
|
|
|
extraction_folder = dialog.selectedFiles()
|
|
|
|
if extraction_folder:
|
|
|
|
params = BorgExtractThread.prepare(
|
|
|
|
self.profile(), archive.name, window.selected, extraction_folder[0])
|
|
|
|
if params['ok']:
|
|
|
|
self._toggle_all_buttons(False)
|
2020-10-30 05:17:24 +00:00
|
|
|
thread = BorgExtractThread(params['cmd'], params, parent=self.app)
|
2018-11-27 11:33:16 +00:00
|
|
|
thread.updated.connect(self.mountErrors.setText)
|
|
|
|
thread.result.connect(self.extract_archive_result)
|
|
|
|
thread.start()
|
|
|
|
else:
|
2019-02-19 13:42:19 +00:00
|
|
|
self._set_status(params['message'])
|
2018-11-27 11:33:16 +00:00
|
|
|
|
2019-01-21 10:44:01 +00:00
|
|
|
dialog = choose_file_dialog(self, self.tr("Choose Extraction Point"), want_folder=True)
|
2018-11-27 11:33:16 +00:00
|
|
|
dialog.open(receive)
|
|
|
|
|
2020-11-20 00:46:09 +00:00
|
|
|
archive = ArchiveModel.get(name=result['params']['archive_name'])
|
|
|
|
window = ExtractDialog(result['data'], archive)
|
|
|
|
self._toggle_all_buttons(True)
|
|
|
|
window.setParent(self, QtCore.Qt.Sheet)
|
|
|
|
self._window = window # for testing
|
|
|
|
window.show()
|
|
|
|
window.accepted.connect(process_result)
|
|
|
|
|
2018-11-27 11:33:16 +00:00
|
|
|
def extract_archive_result(self, result):
|
|
|
|
self._toggle_all_buttons(True)
|
2019-01-21 10:44:01 +00:00
|
|
|
|
|
|
|
def update_mount_button_text(self):
|
|
|
|
archive_name = self.selected_archive_name()
|
|
|
|
if not archive_name:
|
|
|
|
return
|
|
|
|
|
|
|
|
mode = 'Unmount' if archive_name in self.mount_points else 'Mount'
|
|
|
|
self.set_mount_button_mode(mode)
|
|
|
|
|
|
|
|
def cell_double_clicked(self, row, column):
|
|
|
|
if column == 3:
|
|
|
|
archive_name = self.selected_archive_name()
|
|
|
|
if not archive_name:
|
|
|
|
return
|
|
|
|
|
|
|
|
mount_point = self.mount_points.get(archive_name)
|
|
|
|
|
|
|
|
if mount_point is not None:
|
|
|
|
QDesktopServices.openUrl(QtCore.QUrl(f'file:///{mount_point}'))
|
|
|
|
|
|
|
|
def row_of_archive(self, archive_name):
|
|
|
|
items = self.archiveTable.findItems(archive_name, QtCore.Qt.MatchExactly)
|
|
|
|
rows = [item.row() for item in items if item.column() == 4]
|
|
|
|
return rows[0] if rows else None
|
2019-01-24 00:36:44 +00:00
|
|
|
|
2019-02-02 02:01:09 +00:00
|
|
|
def confirm_dialog(self, title, text):
|
2019-02-02 04:29:33 +00:00
|
|
|
msg = QMessageBox()
|
|
|
|
msg.setIcon(QMessageBox.Information)
|
|
|
|
msg.setText(text)
|
|
|
|
msg.setWindowTitle(title)
|
|
|
|
msg.setStandardButtons(QMessageBox.Yes | QMessageBox.Cancel)
|
|
|
|
msg.button(msg.Yes).setText(self.tr("Yes"))
|
|
|
|
msg.button(msg.Cancel).setText(self.tr("Cancel"))
|
|
|
|
return msg.exec_() == QMessageBox.Yes
|
2019-02-02 02:01:09 +00:00
|
|
|
|
2019-01-24 00:36:44 +00:00
|
|
|
def delete_action(self):
|
|
|
|
params = BorgDeleteThread.prepare(self.profile())
|
|
|
|
if not params['ok']:
|
2019-02-19 13:42:19 +00:00
|
|
|
self._set_status(params['message'])
|
2019-01-24 00:36:44 +00:00
|
|
|
return
|
|
|
|
|
2020-11-20 00:46:09 +00:00
|
|
|
self.archive_name = self.selected_archive_name()
|
|
|
|
if self.archive_name is not None:
|
2019-02-02 04:29:33 +00:00
|
|
|
if not self.confirm_dialog(trans_late('ArchiveTab', "Confirm deletion"),
|
|
|
|
trans_late('ArchiveTab', "Are you sure you want to delete the archive?")):
|
2019-02-02 02:01:09 +00:00
|
|
|
return
|
2020-11-20 00:46:09 +00:00
|
|
|
params['cmd'][-1] += f'::{self.archive_name}'
|
2019-01-24 00:36:44 +00:00
|
|
|
|
2020-10-30 05:17:24 +00:00
|
|
|
thread = BorgDeleteThread(params['cmd'], params, parent=self.app)
|
2019-01-24 00:36:44 +00:00
|
|
|
thread.updated.connect(self._set_status)
|
|
|
|
thread.result.connect(self.delete_result)
|
|
|
|
self._toggle_all_buttons(False)
|
|
|
|
thread.start()
|
|
|
|
else:
|
2019-02-02 02:01:09 +00:00
|
|
|
self._set_status(self.tr("No archive selected"))
|
2019-01-24 00:36:44 +00:00
|
|
|
|
|
|
|
def delete_result(self, result):
|
|
|
|
if result['returncode'] == 0:
|
|
|
|
self._set_status(self.tr('Archive deleted.'))
|
2020-11-20 00:46:09 +00:00
|
|
|
deleted_row = self.archiveTable.findItems(self.archive_name, QtCore.Qt.MatchExactly)[0].row()
|
|
|
|
self.archiveTable.removeRow(deleted_row)
|
|
|
|
ArchiveModel.get(name=self.archive_name).delete_instance()
|
|
|
|
del self.archive_name
|
2019-01-24 00:36:44 +00:00
|
|
|
else:
|
|
|
|
self._toggle_all_buttons(True)
|
2019-07-04 19:17:09 +00:00
|
|
|
|
|
|
|
def diff_action(self):
|
2020-11-20 00:46:09 +00:00
|
|
|
def process_result():
|
2020-03-23 06:20:09 +00:00
|
|
|
if window.selected_archives:
|
|
|
|
self.selected_archives = window.selected_archives
|
|
|
|
archive_cell_newer = self.archiveTable.item(self.selected_archives[0], 4)
|
|
|
|
archive_cell_older = self.archiveTable.item(self.selected_archives[1], 4)
|
2019-07-04 19:17:09 +00:00
|
|
|
if archive_cell_older and archive_cell_newer:
|
|
|
|
archive_name_newer = archive_cell_newer.text()
|
|
|
|
archive_name_older = archive_cell_older.text()
|
|
|
|
|
|
|
|
params = BorgDiffThread.prepare(profile, archive_name_older, archive_name_newer)
|
|
|
|
params['archive_name_newer'] = archive_name_newer
|
|
|
|
params['archive_name_older'] = archive_name_older
|
|
|
|
|
|
|
|
if params['ok']:
|
|
|
|
self._toggle_all_buttons(False)
|
2020-10-30 05:17:24 +00:00
|
|
|
thread = BorgDiffThread(params['cmd'], params, parent=self.app)
|
2019-07-04 19:17:09 +00:00
|
|
|
thread.updated.connect(self.mountErrors.setText)
|
|
|
|
thread.result.connect(self.list_diff_result)
|
|
|
|
thread.start()
|
|
|
|
else:
|
|
|
|
self._set_status(params['message'])
|
|
|
|
|
2020-11-20 00:46:09 +00:00
|
|
|
profile = self.profile()
|
|
|
|
|
|
|
|
window = DiffDialog(self.archiveTable)
|
|
|
|
self._toggle_all_buttons(True)
|
|
|
|
window.setParent(self, QtCore.Qt.Sheet)
|
|
|
|
self._window = window # for testing
|
|
|
|
window.show()
|
|
|
|
window.accepted.connect(process_result)
|
|
|
|
|
2019-07-04 19:17:09 +00:00
|
|
|
def list_diff_result(self, result):
|
|
|
|
self._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'])
|
|
|
|
window = DiffResult(result['data'], archive_newer, archive_older)
|
|
|
|
self._toggle_all_buttons(True)
|
|
|
|
window.setParent(self, QtCore.Qt.Sheet)
|
2020-03-23 06:20:09 +00:00
|
|
|
self._resultwindow = window # for testing
|
2019-07-04 19:17:09 +00:00
|
|
|
window.show()
|