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:
parent
92f285f623
commit
30c572250f
5 changed files with 70 additions and 62 deletions
|
@ -257,7 +257,7 @@
|
|||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<item>
|
||||
<widget class="QToolButton" name="bRename">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Fixed">
|
||||
|
|
|
@ -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']
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
Loading…
Reference in a new issue