9f3f6bab7d
Also: - fix issues where the Undo action in the Browse screen was not consistent with the main window. The existing hook signature has been changed; from a snapshot of the add-on code from a few months ago, it was not a hook that was being used by anyone. - change the undo shortcut in the Browse window to match the main window. It was different because undoing a change in the editing area could accidentally trigger an undo of an operation, but the damage is limited now that (most) operations can be redone. If it still proves to be a problem, perhaps we should just always swallow ctrl+z when an editing field is focused.
90 lines
2.5 KiB
Python
90 lines
2.5 KiB
Python
# Copyright: Ankitects Pty Ltd and contributors
|
|
# License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
|
|
|
from __future__ import annotations
|
|
|
|
from anki.collection import LegacyCheckpoint, LegacyReviewUndo, OpChangesAfterUndo
|
|
from anki.errors import UndoEmpty
|
|
from anki.types import assert_exhaustive
|
|
from aqt import gui_hooks
|
|
from aqt.operations import CollectionOp
|
|
from aqt.qt import QWidget
|
|
from aqt.utils import showInfo, showWarning, tooltip, tr
|
|
|
|
|
|
def undo(*, parent: QWidget) -> None:
|
|
"Undo the last operation, and refresh the UI."
|
|
|
|
def on_success(out: OpChangesAfterUndo) -> None:
|
|
gui_hooks.state_did_undo(out)
|
|
tooltip(tr.undo_action_undone(action=out.operation), parent=parent)
|
|
|
|
def on_failure(exc: Exception) -> None:
|
|
if isinstance(exc, UndoEmpty):
|
|
# backend has no undo, but there may be a checkpoint
|
|
# or v1/v2 review waiting
|
|
_legacy_undo(parent=parent)
|
|
else:
|
|
showWarning(str(exc), parent=parent)
|
|
|
|
CollectionOp(parent, lambda col: col.undo()).success(on_success).failure(
|
|
on_failure
|
|
).run_in_background()
|
|
|
|
|
|
def redo(*, parent: QWidget) -> None:
|
|
"Redo the last operation, and refresh the UI."
|
|
|
|
def on_success(out: OpChangesAfterUndo) -> None:
|
|
tooltip(tr.undo_action_redone(action=out.operation), parent=parent)
|
|
|
|
CollectionOp(parent, lambda col: col.redo()).success(on_success).run_in_background()
|
|
|
|
|
|
def _legacy_undo(*, parent: QWidget) -> None:
|
|
from aqt import mw
|
|
|
|
assert mw
|
|
assert mw.col
|
|
|
|
reviewing = mw.state == "review"
|
|
just_refresh_reviewer = False
|
|
|
|
result = mw.col.undo_legacy()
|
|
|
|
if result is None:
|
|
# should not happen
|
|
showInfo("nothing to undo", parent=parent)
|
|
mw.update_undo_actions()
|
|
return
|
|
|
|
elif isinstance(result, LegacyReviewUndo):
|
|
name = tr.scheduling_review()
|
|
|
|
if reviewing:
|
|
# push the undone card to the top of the queue
|
|
cid = result.card.id
|
|
card = mw.col.getCard(cid)
|
|
mw.reviewer.cardQueue.append(card)
|
|
|
|
gui_hooks.review_did_undo(cid)
|
|
|
|
just_refresh_reviewer = True
|
|
|
|
elif isinstance(result, LegacyCheckpoint):
|
|
name = result.name
|
|
|
|
else:
|
|
assert_exhaustive(result)
|
|
assert False
|
|
|
|
if just_refresh_reviewer:
|
|
mw.reviewer.nextCard()
|
|
else:
|
|
# full queue+gui reset required
|
|
mw.reset()
|
|
|
|
tooltip(tr.undo_action_undone(action=name), parent=parent)
|
|
gui_hooks.state_did_revert(name)
|
|
mw.update_undo_actions()
|