Merge pull request #726 from hgiesel/resethook
Add main_window_will_require_reset gui_hook
This commit is contained in:
commit
56431872fb
@ -12,6 +12,7 @@ from anki.lang import _
|
||||
from anki.notes import Note
|
||||
from anki.utils import htmlToTextLine, isMac
|
||||
from aqt import AnkiQt, gui_hooks
|
||||
from aqt.main import ResetReason
|
||||
from aqt.qt import *
|
||||
from aqt.sound import av_player
|
||||
from aqt.utils import (
|
||||
@ -177,8 +178,8 @@ class AddCards(QDialog):
|
||||
self.mw.col.add_note(note, self.deckChooser.selectedId())
|
||||
self.mw.col.clearUndo()
|
||||
self.addHistory(note)
|
||||
self.mw.requireReset()
|
||||
self.previousNote = note
|
||||
self.mw.requireReset(reason=ResetReason.AddCardsAddNote, context=self)
|
||||
gui_hooks.add_cards_did_add_note(note)
|
||||
return note
|
||||
|
||||
|
@ -26,6 +26,7 @@ from anki.utils import htmlToTextLine, ids2str, intTime, isMac, isWin
|
||||
from aqt import AnkiQt, gui_hooks
|
||||
from aqt.editor import Editor
|
||||
from aqt.exporting import ExportDialog
|
||||
from aqt.main import ResetReason
|
||||
from aqt.previewer import BrowserPreviewer as PreviewDialog
|
||||
from aqt.previewer import Previewer
|
||||
from aqt.qt import *
|
||||
@ -1616,7 +1617,7 @@ update cards set usn=?, mod=?, did=? where id in """
|
||||
did,
|
||||
)
|
||||
self.model.endReset()
|
||||
self.mw.requireReset()
|
||||
self.mw.requireReset(reason=ResetReason.BrowserSetDeck, context=self)
|
||||
|
||||
# Tags
|
||||
######################################################################
|
||||
@ -1642,7 +1643,7 @@ update cards set usn=?, mod=?, did=? where id in """
|
||||
self.model.beginReset()
|
||||
func(self.selectedNotes(), tags)
|
||||
self.model.endReset()
|
||||
self.mw.requireReset()
|
||||
self.mw.requireReset(reason=ResetReason.BrowserAddTags, context=self)
|
||||
|
||||
def deleteTags(self, tags=None, label=None):
|
||||
if label is None:
|
||||
@ -1675,7 +1676,7 @@ update cards set usn=?, mod=?, did=? where id in """
|
||||
else:
|
||||
self.col.sched.unsuspendCards(c)
|
||||
self.model.reset()
|
||||
self.mw.requireReset()
|
||||
self.mw.requireReset(reason=ResetReason.BrowserSuspend, context=self)
|
||||
|
||||
# Exporting
|
||||
######################################################################
|
||||
@ -1763,7 +1764,7 @@ update cards set usn=?, mod=?, did=? where id in """
|
||||
shift=frm.shift.isChecked(),
|
||||
)
|
||||
self.search()
|
||||
self.mw.requireReset()
|
||||
self.mw.requireReset(reason=ResetReason.BrowserReposition, context=self)
|
||||
self.model.endReset()
|
||||
|
||||
# Rescheduling
|
||||
@ -1789,7 +1790,7 @@ update cards set usn=?, mod=?, did=? where id in """
|
||||
fmax = max(fmin, fmax)
|
||||
self.col.sched.reschedCards(self.selectedCards(), fmin, fmax)
|
||||
self.search()
|
||||
self.mw.requireReset()
|
||||
self.mw.requireReset(reason=ResetReason.BrowserReschedule, context=self)
|
||||
self.model.endReset()
|
||||
|
||||
# Edit: selection
|
||||
@ -1923,7 +1924,7 @@ update cards set usn=?, mod=?, did=? where id in """
|
||||
|
||||
def on_done(fut):
|
||||
self.search()
|
||||
self.mw.requireReset()
|
||||
self.mw.requireReset(reason=ResetReason.BrowserFindReplace, context=self)
|
||||
self.model.endReset()
|
||||
|
||||
total = len(nids)
|
||||
@ -2025,7 +2026,7 @@ update cards set usn=?, mod=?, did=? where id in """
|
||||
self.col.tags.bulkAdd(list(nids), _("duplicate"))
|
||||
self.mw.progress.finish()
|
||||
self.model.endReset()
|
||||
self.mw.requireReset()
|
||||
self.mw.requireReset(reason=ResetReason.BrowserTagDupes, context=self)
|
||||
tooltip(_("Notes tagged."))
|
||||
|
||||
def dupeLinkClicked(self, link):
|
||||
|
@ -5,6 +5,7 @@
|
||||
import aqt.editor
|
||||
from anki.lang import _
|
||||
from aqt import gui_hooks
|
||||
from aqt.main import ResetReason
|
||||
from aqt.qt import *
|
||||
from aqt.utils import restoreGeom, saveGeom, tooltip
|
||||
|
||||
@ -27,7 +28,7 @@ class EditCurrent(QDialog):
|
||||
self.editor.setNote(self.mw.reviewer.card.note(), focusTo=0)
|
||||
restoreGeom(self, "editcurrent")
|
||||
gui_hooks.state_did_reset.append(self.onReset)
|
||||
self.mw.requireReset()
|
||||
self.mw.requireReset(reason=ResetReason.EditCurrentInit, context=self)
|
||||
self.show()
|
||||
# reset focus after open, taking care not to retain webview
|
||||
# pylint: disable=unnecessary-lambda
|
||||
|
@ -26,6 +26,7 @@ from anki.lang import _
|
||||
from anki.notes import Note
|
||||
from anki.utils import checksum, isLin, isWin, namedtmp, stripHTMLMedia
|
||||
from aqt import AnkiQt, gui_hooks
|
||||
from aqt.main import ResetReason
|
||||
from aqt.qt import *
|
||||
from aqt.sound import av_player, getAudio
|
||||
from aqt.theme import theme_manager
|
||||
@ -393,7 +394,7 @@ class Editor:
|
||||
|
||||
if not self.addMode:
|
||||
self.note.flush()
|
||||
self.mw.requireReset()
|
||||
self.mw.requireReset(reason=ResetReason.EditorBridgeCmd, context=self)
|
||||
if type == "blur":
|
||||
self.currentField = None
|
||||
# run any filters
|
||||
|
@ -7,7 +7,7 @@ See pylib/anki/hooks.py
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import Any, Callable, List, Optional, Tuple
|
||||
from typing import Any, Callable, List, Optional, Tuple, Union
|
||||
|
||||
import anki
|
||||
import aqt
|
||||
@ -1737,6 +1737,57 @@ class _MainWindowDidInitHook:
|
||||
main_window_did_init = _MainWindowDidInitHook()
|
||||
|
||||
|
||||
class _MainWindowShouldRequireResetFilter:
|
||||
"""Executed before the main window will require a reset
|
||||
|
||||
This hook can be used to change the behavior of the main window,
|
||||
when other dialogs, like the AddCards or Browser, require a reset
|
||||
from the main window.
|
||||
If you decide to use this hook, make you sure you check the reason for the reset.
|
||||
Some reasons require more attention than others, and skipping important ones might
|
||||
put the main window into an invalid state (e.g. display a deleted note).
|
||||
"""
|
||||
|
||||
_hooks: List[
|
||||
Callable[[bool, "Union[aqt.main.ResetReason, str]", Optional[Any]], bool]
|
||||
] = []
|
||||
|
||||
def append(
|
||||
self,
|
||||
cb: Callable[[bool, "Union[aqt.main.ResetReason, str]", Optional[Any]], bool],
|
||||
) -> None:
|
||||
"""(will_reset: bool, reason: Union[aqt.main.ResetReason, str], context: Optional[Any])"""
|
||||
self._hooks.append(cb)
|
||||
|
||||
def remove(
|
||||
self,
|
||||
cb: Callable[[bool, "Union[aqt.main.ResetReason, str]", Optional[Any]], bool],
|
||||
) -> None:
|
||||
if cb in self._hooks:
|
||||
self._hooks.remove(cb)
|
||||
|
||||
def count(self) -> int:
|
||||
return len(self._hooks)
|
||||
|
||||
def __call__(
|
||||
self,
|
||||
will_reset: bool,
|
||||
reason: Union[aqt.main.ResetReason, str],
|
||||
context: Optional[Any],
|
||||
) -> bool:
|
||||
for filter in self._hooks:
|
||||
try:
|
||||
will_reset = filter(will_reset, reason, context)
|
||||
except:
|
||||
# if the hook fails, remove it
|
||||
self._hooks.remove(filter)
|
||||
raise
|
||||
return will_reset
|
||||
|
||||
|
||||
main_window_should_require_reset = _MainWindowShouldRequireResetFilter()
|
||||
|
||||
|
||||
class _MediaSyncDidProgressHook:
|
||||
_hooks: List[Callable[["aqt.mediasync.LogEntryWithTime"], None]] = []
|
||||
|
||||
|
@ -4,6 +4,7 @@
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import enum
|
||||
import faulthandler
|
||||
import gc
|
||||
import os
|
||||
@ -68,6 +69,19 @@ from aqt.utils import (
|
||||
install_pylib_legacy()
|
||||
|
||||
|
||||
class ResetReason(enum.Enum):
|
||||
AddCardsAddNote = "addCardsAddNote"
|
||||
EditCurrentInit = "editCurrentInit"
|
||||
EditorBridgeCmd = "editorBridgeCmd"
|
||||
BrowserSetDeck = "browserSetDeck"
|
||||
BrowserAddTags = "browserAddTags"
|
||||
BrowserSuspend = "browserSuspend"
|
||||
BrowserReposition = "browserReposition"
|
||||
BrowserReschedule = "browserReschedule"
|
||||
BrowserFindReplace = "browserFindReplace"
|
||||
BrowserTagDupes = "browserTagDupes"
|
||||
|
||||
|
||||
class ResetRequired:
|
||||
def __init__(self, mw: AnkiQt):
|
||||
self.mw = mw
|
||||
@ -684,11 +698,13 @@ from the profile screen."
|
||||
self.maybeEnableUndo()
|
||||
self.moveToState(self.state)
|
||||
|
||||
def requireReset(self, modal=False):
|
||||
def requireReset(self, modal=False, reason="unknown", context=None):
|
||||
"Signal queue needs to be rebuilt when edits are finished or by user."
|
||||
self.autosave()
|
||||
self.resetModal = modal
|
||||
if self.interactiveState():
|
||||
if gui_hooks.main_window_should_require_reset(
|
||||
self.interactiveState(), reason, context
|
||||
):
|
||||
self.moveToState("resetRequired")
|
||||
|
||||
def interactiveState(self):
|
||||
|
@ -440,6 +440,24 @@ hooks = [
|
||||
is thus suitable for single-shot subscribers.
|
||||
""",
|
||||
),
|
||||
Hook(
|
||||
name="main_window_should_require_reset",
|
||||
args=[
|
||||
"will_reset: bool",
|
||||
"reason: Union[aqt.main.ResetReason, str]",
|
||||
"context: Optional[Any]",
|
||||
],
|
||||
return_type="bool",
|
||||
doc="""Executed before the main window will require a reset
|
||||
|
||||
This hook can be used to change the behavior of the main window,
|
||||
when other dialogs, like the AddCards or Browser, require a reset
|
||||
from the main window.
|
||||
If you decide to use this hook, make you sure you check the reason for the reset.
|
||||
Some reasons require more attention than others, and skipping important ones might
|
||||
put the main window into an invalid state (e.g. display a deleted note).
|
||||
""",
|
||||
),
|
||||
Hook(name="backup_did_complete"),
|
||||
Hook(
|
||||
name="profile_did_open",
|
||||
|
Loading…
Reference in New Issue
Block a user