1
0
Fork 0
mirror of https://github.com/borgbase/vorta synced 2024-12-22 07:43:09 +00:00

Inline archive renaming. By @diivi (#1734)

This commit is contained in:
Divyansh Singh 2023-08-15 17:08:51 +05:30 committed by GitHub
parent 92f285f623
commit 30c572250f
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 70 additions and 62 deletions

View file

@ -257,7 +257,7 @@
</property>
</widget>
</item>
<item>
<item>
<widget class="QToolButton" name="bRename">
<property name="sizePolicy">
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Fixed">

View file

@ -41,6 +41,11 @@ def process_result(self, result):
# Update remote archives.
for remote_archive in remote_archives:
archive = ArchiveModel.get_or_none(snapshot_id=remote_archive['id'], repo=repo_id)
if archive is None:
# archive id was changed during rename, so we need to find it by name
archive = ArchiveModel.get_or_none(name=remote_archive['name'], repo=repo_id)
archive.snapshot_id = remote_archive['id']
archive.name = remote_archive['name'] # incase name changed
# archive.time = parser.parse(remote_archive['time'])
archive.duration = remote_archive['duration']

View file

@ -10,7 +10,6 @@
QAbstractItemView,
QApplication,
QHeaderView,
QInputDialog,
QLayout,
QMenu,
QMessageBox,
@ -79,6 +78,7 @@ def __init__(self, parent=None, app=None):
self.app = app
self.toolBox.setCurrentIndex(0)
self.repoactions_enabled = True
self.renamed_archive_original_name = None
self.remaining_refresh_archives = (
0 # number of archives that are left to refresh before action buttons are enabled again
)
@ -111,6 +111,7 @@ def __init__(self, parent=None, app=None):
self.archiveTable.setTextElideMode(QtCore.Qt.TextElideMode.ElideLeft)
self.archiveTable.setAlternatingRowColors(True)
self.archiveTable.cellDoubleClicked.connect(self.cell_double_clicked)
self.archiveTable.cellChanged.connect(self.cell_changed)
self.archiveTable.setSortingEnabled(True)
self.archiveTable.setContextMenuPolicy(Qt.ContextMenuPolicy.CustomContextMenu)
self.archiveTable.customContextMenuRequested.connect(self.archiveitem_contextmenu)
@ -126,7 +127,7 @@ def __init__(self, parent=None, app=None):
# connect archive actions
self.bMountArchive.clicked.connect(self.bmountarchive_clicked)
self.bRefreshArchive.clicked.connect(self.refresh_archive_info)
self.bRename.clicked.connect(self.rename_action)
self.bRename.clicked.connect(self.cell_double_clicked)
self.bDelete.clicked.connect(self.delete_action)
self.bExtract.clicked.connect(self.extract_action)
self.compactButton.clicked.connect(self.compact_action)
@ -206,7 +207,7 @@ def archiveitem_contextmenu(self, pos: QPoint):
)
)
archive_actions.append(menu.addAction(self.bExtract.icon(), self.bExtract.text(), self.extract_action))
archive_actions.append(menu.addAction(self.bRename.icon(), self.bRename.text(), self.rename_action))
archive_actions.append(menu.addAction(self.bRename.icon(), self.bRename.text(), self.cell_double_clicked))
# deletion possible with one but also multiple archives
menu.addAction(self.bDelete.icon(), self.bDelete.text(), self.delete_action)
@ -823,7 +824,11 @@ def extract_archive_result(self, result):
"""Finished extraction."""
self._toggle_all_buttons(True)
def cell_double_clicked(self, row, column):
def cell_double_clicked(self, row=None, column=None):
if not row or not column:
row = self.archiveTable.currentRow()
column = self.archiveTable.currentColumn()
if column == 3:
archive_name = self.selected_archive_name()
if not archive_name:
@ -834,6 +839,46 @@ def cell_double_clicked(self, row, column):
if mount_point is not None:
QDesktopServices.openUrl(QtCore.QUrl(f'file:///{mount_point}'))
if column == 4:
item = self.archiveTable.item(row, column)
self.renamed_archive_original_name = item.text()
item.setFlags(item.flags() | QtCore.Qt.ItemFlag.ItemIsEditable)
self.archiveTable.editItem(item)
def cell_changed(self, row, column):
# return if this is not a name change
if column != 4:
return
item = self.archiveTable.item(row, column)
new_name = item.text()
profile = self.profile()
# if the name hasn't changed or if this slot is called when first repopulating the table, do nothing.
if new_name == self.renamed_archive_original_name or not self.renamed_archive_original_name:
return
if not new_name:
item.setText(self.renamed_archive_original_name)
self._set_status(self.tr('Archive name cannot be blank.'))
return
new_name_exists = ArchiveModel.get_or_none(name=new_name, repo=profile.repo)
if new_name_exists is not None:
self._set_status(self.tr('An archive with this name already exists.'))
item.setText(self.renamed_archive_original_name)
return
params = BorgRenameJob.prepare(profile, self.renamed_archive_original_name, new_name)
if not params['ok']:
self._set_status(params['message'])
job = BorgRenameJob(params['cmd'], params, self.profile().repo.id)
job.updated.connect(self._set_status)
job.result.connect(self.rename_result)
self._toggle_all_buttons(False)
self.app.jobs_manager.add_job(job)
def row_of_archive(self, archive_name):
items = self.archiveTable.findItems(archive_name, QtCore.Qt.MatchFlag.MatchExactly)
rows = [item.row() for item in items if item.column() == 4]
@ -968,45 +1013,11 @@ def show_diff_result(self, archive_newer, archive_older, model):
self._resultwindow = window # for testing
window.show()
def rename_action(self):
profile = self.profile()
archive_name = self.selected_archive_name()
if archive_name is not None:
new_name, finished = QInputDialog.getText(
self,
self.tr("Change name"),
self.tr("New archive name:"),
text=archive_name,
)
if not finished:
return
if not new_name:
self._set_status(self.tr('Archive name cannot be blank.'))
return
new_name_exists = ArchiveModel.get_or_none(name=new_name, repo=profile.repo)
if new_name_exists is not None:
self._set_status(self.tr('An archive with this name already exists.'))
return
params = BorgRenameJob.prepare(profile, archive_name, new_name)
if not params['ok']:
self._set_status(params['message'])
job = BorgRenameJob(params['cmd'], params, self.profile().repo.id)
job.updated.connect(self._set_status)
job.result.connect(self.rename_result)
self._toggle_all_buttons(False)
self.app.jobs_manager.add_job(job)
else:
self._set_status(self.tr("No archive selected"))
def rename_result(self, result):
if result['returncode'] == 0:
self.refresh_archive_info()
self._set_status(self.tr('Archive renamed.'))
self.renamed_archive_original_name = None
self.populate_from_profile()
else:
self._toggle_all_buttons(True)

View file

@ -171,15 +171,11 @@ def test_archive_rename(qapp, qtbot, mocker):
tab.archiveTable.selectRow(0)
new_archive_name = 'idf89d8f9d8fd98'
mocker.patch.object(vorta.views.archive_tab.QInputDialog, 'getText', return_value=(new_archive_name, True))
tab.rename_action()
pos = tab.archiveTable.visualRect(tab.archiveTable.model().index(0, 4)).center()
qtbot.mouseClick(tab.archiveTable.viewport(), QtCore.Qt.MouseButton.LeftButton, pos=pos)
qtbot.mouseDClick(tab.archiveTable.viewport(), QtCore.Qt.MouseButton.LeftButton, pos=pos)
qtbot.keyClicks(tab.archiveTable.viewport().focusWidget(), new_archive_name)
qtbot.keyClick(tab.archiveTable.viewport().focusWidget(), QtCore.Qt.Key.Key_Return)
# Successful rename case
qtbot.waitUntil(lambda: tab.mountErrors.text() == 'Archive renamed.', **pytest._wait_defaults)
assert ArchiveModel.select().filter(name=new_archive_name).count() == 1
# Duplicate name case
tab.archiveTable.selectRow(0)
exp_text = 'An archive with this name already exists.'
tab.rename_action()
qtbot.waitUntil(lambda: tab.mountErrors.text() == exp_text, **pytest._wait_defaults)
qtbot.waitUntil(lambda: tab.archiveTable.model().index(0, 4).data() == new_archive_name, **pytest._wait_defaults)

View file

@ -183,16 +183,12 @@ def test_archive_rename(qapp, qtbot, mocker, borg_json_output):
stdout, stderr = borg_json_output('rename')
popen_result = mocker.MagicMock(stdout=stdout, stderr=stderr, returncode=0)
mocker.patch.object(vorta.borg.borg_job, 'Popen', return_value=popen_result)
mocker.patch.object(vorta.views.archive_tab.QInputDialog, 'getText', return_value=(new_archive_name, True))
tab.rename_action()
pos = tab.archiveTable.visualRect(tab.archiveTable.model().index(0, 4)).center()
qtbot.mouseClick(tab.archiveTable.viewport(), QtCore.Qt.MouseButton.LeftButton, pos=pos)
qtbot.mouseDClick(tab.archiveTable.viewport(), QtCore.Qt.MouseButton.LeftButton, pos=pos)
qtbot.keyClicks(tab.archiveTable.viewport().focusWidget(), new_archive_name)
qtbot.keyClick(tab.archiveTable.viewport().focusWidget(), QtCore.Qt.Key.Key_Return)
# Successful rename case
qtbot.waitUntil(lambda: tab.mountErrors.text() == 'Archive renamed.', **pytest._wait_defaults)
assert ArchiveModel.select().filter(name=new_archive_name).count() == 1
# Duplicate name case
tab.archiveTable.selectRow(0)
exp_text = 'An archive with this name already exists.'
mocker.patch.object(vorta.views.archive_tab.QInputDialog, 'getText', return_value=(new_archive_name, True))
tab.rename_action()
qtbot.waitUntil(lambda: tab.mountErrors.text() == exp_text, **pytest._wait_defaults)
qtbot.waitUntil(lambda: tab.archiveTable.model().index(0, 4).data() == new_archive_name, **pytest._wait_defaults)