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.notes import Note
|
||||||
from anki.utils import htmlToTextLine, isMac
|
from anki.utils import htmlToTextLine, isMac
|
||||||
from aqt import AnkiQt, gui_hooks
|
from aqt import AnkiQt, gui_hooks
|
||||||
|
from aqt.main import ResetReason
|
||||||
from aqt.qt import *
|
from aqt.qt import *
|
||||||
from aqt.sound import av_player
|
from aqt.sound import av_player
|
||||||
from aqt.utils import (
|
from aqt.utils import (
|
||||||
@ -177,8 +178,8 @@ class AddCards(QDialog):
|
|||||||
self.mw.col.add_note(note, self.deckChooser.selectedId())
|
self.mw.col.add_note(note, self.deckChooser.selectedId())
|
||||||
self.mw.col.clearUndo()
|
self.mw.col.clearUndo()
|
||||||
self.addHistory(note)
|
self.addHistory(note)
|
||||||
self.mw.requireReset()
|
|
||||||
self.previousNote = note
|
self.previousNote = note
|
||||||
|
self.mw.requireReset(reason=ResetReason.AddCardsAddNote, context=self)
|
||||||
gui_hooks.add_cards_did_add_note(note)
|
gui_hooks.add_cards_did_add_note(note)
|
||||||
return note
|
return note
|
||||||
|
|
||||||
|
@ -26,6 +26,7 @@ from anki.utils import htmlToTextLine, ids2str, intTime, isMac, isWin
|
|||||||
from aqt import AnkiQt, gui_hooks
|
from aqt import AnkiQt, gui_hooks
|
||||||
from aqt.editor import Editor
|
from aqt.editor import Editor
|
||||||
from aqt.exporting import ExportDialog
|
from aqt.exporting import ExportDialog
|
||||||
|
from aqt.main import ResetReason
|
||||||
from aqt.previewer import BrowserPreviewer as PreviewDialog
|
from aqt.previewer import BrowserPreviewer as PreviewDialog
|
||||||
from aqt.previewer import Previewer
|
from aqt.previewer import Previewer
|
||||||
from aqt.qt import *
|
from aqt.qt import *
|
||||||
@ -1616,7 +1617,7 @@ update cards set usn=?, mod=?, did=? where id in """
|
|||||||
did,
|
did,
|
||||||
)
|
)
|
||||||
self.model.endReset()
|
self.model.endReset()
|
||||||
self.mw.requireReset()
|
self.mw.requireReset(reason=ResetReason.BrowserSetDeck, context=self)
|
||||||
|
|
||||||
# Tags
|
# Tags
|
||||||
######################################################################
|
######################################################################
|
||||||
@ -1642,7 +1643,7 @@ update cards set usn=?, mod=?, did=? where id in """
|
|||||||
self.model.beginReset()
|
self.model.beginReset()
|
||||||
func(self.selectedNotes(), tags)
|
func(self.selectedNotes(), tags)
|
||||||
self.model.endReset()
|
self.model.endReset()
|
||||||
self.mw.requireReset()
|
self.mw.requireReset(reason=ResetReason.BrowserAddTags, context=self)
|
||||||
|
|
||||||
def deleteTags(self, tags=None, label=None):
|
def deleteTags(self, tags=None, label=None):
|
||||||
if label is None:
|
if label is None:
|
||||||
@ -1675,7 +1676,7 @@ update cards set usn=?, mod=?, did=? where id in """
|
|||||||
else:
|
else:
|
||||||
self.col.sched.unsuspendCards(c)
|
self.col.sched.unsuspendCards(c)
|
||||||
self.model.reset()
|
self.model.reset()
|
||||||
self.mw.requireReset()
|
self.mw.requireReset(reason=ResetReason.BrowserSuspend, context=self)
|
||||||
|
|
||||||
# Exporting
|
# Exporting
|
||||||
######################################################################
|
######################################################################
|
||||||
@ -1763,7 +1764,7 @@ update cards set usn=?, mod=?, did=? where id in """
|
|||||||
shift=frm.shift.isChecked(),
|
shift=frm.shift.isChecked(),
|
||||||
)
|
)
|
||||||
self.search()
|
self.search()
|
||||||
self.mw.requireReset()
|
self.mw.requireReset(reason=ResetReason.BrowserReposition, context=self)
|
||||||
self.model.endReset()
|
self.model.endReset()
|
||||||
|
|
||||||
# Rescheduling
|
# Rescheduling
|
||||||
@ -1789,7 +1790,7 @@ update cards set usn=?, mod=?, did=? where id in """
|
|||||||
fmax = max(fmin, fmax)
|
fmax = max(fmin, fmax)
|
||||||
self.col.sched.reschedCards(self.selectedCards(), fmin, fmax)
|
self.col.sched.reschedCards(self.selectedCards(), fmin, fmax)
|
||||||
self.search()
|
self.search()
|
||||||
self.mw.requireReset()
|
self.mw.requireReset(reason=ResetReason.BrowserReschedule, context=self)
|
||||||
self.model.endReset()
|
self.model.endReset()
|
||||||
|
|
||||||
# Edit: selection
|
# Edit: selection
|
||||||
@ -1923,7 +1924,7 @@ update cards set usn=?, mod=?, did=? where id in """
|
|||||||
|
|
||||||
def on_done(fut):
|
def on_done(fut):
|
||||||
self.search()
|
self.search()
|
||||||
self.mw.requireReset()
|
self.mw.requireReset(reason=ResetReason.BrowserFindReplace, context=self)
|
||||||
self.model.endReset()
|
self.model.endReset()
|
||||||
|
|
||||||
total = len(nids)
|
total = len(nids)
|
||||||
@ -2025,7 +2026,7 @@ update cards set usn=?, mod=?, did=? where id in """
|
|||||||
self.col.tags.bulkAdd(list(nids), _("duplicate"))
|
self.col.tags.bulkAdd(list(nids), _("duplicate"))
|
||||||
self.mw.progress.finish()
|
self.mw.progress.finish()
|
||||||
self.model.endReset()
|
self.model.endReset()
|
||||||
self.mw.requireReset()
|
self.mw.requireReset(reason=ResetReason.BrowserTagDupes, context=self)
|
||||||
tooltip(_("Notes tagged."))
|
tooltip(_("Notes tagged."))
|
||||||
|
|
||||||
def dupeLinkClicked(self, link):
|
def dupeLinkClicked(self, link):
|
||||||
|
@ -5,6 +5,7 @@
|
|||||||
import aqt.editor
|
import aqt.editor
|
||||||
from anki.lang import _
|
from anki.lang import _
|
||||||
from aqt import gui_hooks
|
from aqt import gui_hooks
|
||||||
|
from aqt.main import ResetReason
|
||||||
from aqt.qt import *
|
from aqt.qt import *
|
||||||
from aqt.utils import restoreGeom, saveGeom, tooltip
|
from aqt.utils import restoreGeom, saveGeom, tooltip
|
||||||
|
|
||||||
@ -27,7 +28,7 @@ class EditCurrent(QDialog):
|
|||||||
self.editor.setNote(self.mw.reviewer.card.note(), focusTo=0)
|
self.editor.setNote(self.mw.reviewer.card.note(), focusTo=0)
|
||||||
restoreGeom(self, "editcurrent")
|
restoreGeom(self, "editcurrent")
|
||||||
gui_hooks.state_did_reset.append(self.onReset)
|
gui_hooks.state_did_reset.append(self.onReset)
|
||||||
self.mw.requireReset()
|
self.mw.requireReset(reason=ResetReason.EditCurrentInit, context=self)
|
||||||
self.show()
|
self.show()
|
||||||
# reset focus after open, taking care not to retain webview
|
# reset focus after open, taking care not to retain webview
|
||||||
# pylint: disable=unnecessary-lambda
|
# pylint: disable=unnecessary-lambda
|
||||||
|
@ -26,6 +26,7 @@ from anki.lang import _
|
|||||||
from anki.notes import Note
|
from anki.notes import Note
|
||||||
from anki.utils import checksum, isLin, isWin, namedtmp, stripHTMLMedia
|
from anki.utils import checksum, isLin, isWin, namedtmp, stripHTMLMedia
|
||||||
from aqt import AnkiQt, gui_hooks
|
from aqt import AnkiQt, gui_hooks
|
||||||
|
from aqt.main import ResetReason
|
||||||
from aqt.qt import *
|
from aqt.qt import *
|
||||||
from aqt.sound import av_player, getAudio
|
from aqt.sound import av_player, getAudio
|
||||||
from aqt.theme import theme_manager
|
from aqt.theme import theme_manager
|
||||||
@ -393,7 +394,7 @@ class Editor:
|
|||||||
|
|
||||||
if not self.addMode:
|
if not self.addMode:
|
||||||
self.note.flush()
|
self.note.flush()
|
||||||
self.mw.requireReset()
|
self.mw.requireReset(reason=ResetReason.EditorBridgeCmd, context=self)
|
||||||
if type == "blur":
|
if type == "blur":
|
||||||
self.currentField = None
|
self.currentField = None
|
||||||
# run any filters
|
# run any filters
|
||||||
|
@ -7,7 +7,7 @@ See pylib/anki/hooks.py
|
|||||||
|
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
from typing import Any, Callable, List, Optional, Tuple
|
from typing import Any, Callable, List, Optional, Tuple, Union
|
||||||
|
|
||||||
import anki
|
import anki
|
||||||
import aqt
|
import aqt
|
||||||
@ -1737,6 +1737,57 @@ class _MainWindowDidInitHook:
|
|||||||
main_window_did_init = _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:
|
class _MediaSyncDidProgressHook:
|
||||||
_hooks: List[Callable[["aqt.mediasync.LogEntryWithTime"], None]] = []
|
_hooks: List[Callable[["aqt.mediasync.LogEntryWithTime"], None]] = []
|
||||||
|
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
|
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import enum
|
||||||
import faulthandler
|
import faulthandler
|
||||||
import gc
|
import gc
|
||||||
import os
|
import os
|
||||||
@ -68,6 +69,19 @@ from aqt.utils import (
|
|||||||
install_pylib_legacy()
|
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:
|
class ResetRequired:
|
||||||
def __init__(self, mw: AnkiQt):
|
def __init__(self, mw: AnkiQt):
|
||||||
self.mw = mw
|
self.mw = mw
|
||||||
@ -684,11 +698,13 @@ from the profile screen."
|
|||||||
self.maybeEnableUndo()
|
self.maybeEnableUndo()
|
||||||
self.moveToState(self.state)
|
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."
|
"Signal queue needs to be rebuilt when edits are finished or by user."
|
||||||
self.autosave()
|
self.autosave()
|
||||||
self.resetModal = modal
|
self.resetModal = modal
|
||||||
if self.interactiveState():
|
if gui_hooks.main_window_should_require_reset(
|
||||||
|
self.interactiveState(), reason, context
|
||||||
|
):
|
||||||
self.moveToState("resetRequired")
|
self.moveToState("resetRequired")
|
||||||
|
|
||||||
def interactiveState(self):
|
def interactiveState(self):
|
||||||
|
@ -440,6 +440,24 @@ hooks = [
|
|||||||
is thus suitable for single-shot subscribers.
|
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="backup_did_complete"),
|
||||||
Hook(
|
Hook(
|
||||||
name="profile_did_open",
|
name="profile_did_open",
|
||||||
|
Loading…
Reference in New Issue
Block a user