2020-01-13 05:38:05 +01:00
|
|
|
# Copyright: Ankitects Pty Ltd and contributors
|
|
|
|
# License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
|
|
|
|
|
|
|
"""
|
|
|
|
See pylib/anki/hooks.py
|
|
|
|
"""
|
|
|
|
|
|
|
|
from __future__ import annotations
|
|
|
|
|
2020-08-16 23:34:24 +02:00
|
|
|
from typing import Any, Callable, List, Optional, Tuple, Union
|
2020-01-13 05:38:05 +01:00
|
|
|
|
2020-01-15 03:16:54 +01:00
|
|
|
import anki
|
2020-01-14 23:53:57 +01:00
|
|
|
import aqt
|
2020-01-13 09:37:08 +01:00
|
|
|
from anki.cards import Card
|
2020-08-11 22:56:58 +02:00
|
|
|
from anki.decks import Deck, DeckConfig
|
2020-01-15 03:16:54 +01:00
|
|
|
from anki.hooks import runFilter, runHook
|
2020-08-11 22:56:58 +02:00
|
|
|
from anki.models import NoteType
|
2020-03-31 15:00:26 +02:00
|
|
|
from aqt.qt import QDialog, QEvent, QMenu
|
|
|
|
from aqt.tagedit import TagEdit
|
2020-01-13 05:38:05 +01:00
|
|
|
|
|
|
|
# New hook/filter handling
|
|
|
|
##############################################################################
|
|
|
|
# The code in this section is automatically generated - any edits you make
|
2020-01-15 06:29:23 +01:00
|
|
|
# will be lost. To add new hooks, see ../tools/genhooks_gui.py
|
2020-01-13 05:38:05 +01:00
|
|
|
#
|
|
|
|
# @@AUTOGEN@@
|
|
|
|
|
2020-01-13 09:37:08 +01:00
|
|
|
|
2020-03-20 11:59:59 +01:00
|
|
|
class _AddCardsDidAddNoteHook:
|
|
|
|
_hooks: List[Callable[["anki.notes.Note"], None]] = []
|
|
|
|
|
|
|
|
def append(self, cb: Callable[["anki.notes.Note"], None]) -> None:
|
|
|
|
"""(note: anki.notes.Note)"""
|
|
|
|
self._hooks.append(cb)
|
|
|
|
|
|
|
|
def remove(self, cb: Callable[["anki.notes.Note"], None]) -> None:
|
|
|
|
if cb in self._hooks:
|
|
|
|
self._hooks.remove(cb)
|
|
|
|
|
2020-06-04 10:20:03 +02:00
|
|
|
def count(self) -> int:
|
|
|
|
return len(self._hooks)
|
|
|
|
|
2020-03-20 11:59:59 +01:00
|
|
|
def __call__(self, note: anki.notes.Note) -> None:
|
|
|
|
for hook in self._hooks:
|
|
|
|
try:
|
|
|
|
hook(note)
|
|
|
|
except:
|
|
|
|
# if the hook fails, remove it
|
|
|
|
self._hooks.remove(hook)
|
|
|
|
raise
|
|
|
|
# legacy support
|
|
|
|
runHook("AddCards.noteAdded", note)
|
|
|
|
|
|
|
|
|
|
|
|
add_cards_did_add_note = _AddCardsDidAddNoteHook()
|
|
|
|
|
|
|
|
|
2020-04-03 10:54:54 +02:00
|
|
|
class _AddCardsDidInitHook:
|
|
|
|
_hooks: List[Callable[["aqt.addcards.AddCards"], None]] = []
|
|
|
|
|
|
|
|
def append(self, cb: Callable[["aqt.addcards.AddCards"], None]) -> None:
|
|
|
|
"""(addcards: aqt.addcards.AddCards)"""
|
|
|
|
self._hooks.append(cb)
|
|
|
|
|
|
|
|
def remove(self, cb: Callable[["aqt.addcards.AddCards"], None]) -> None:
|
|
|
|
if cb in self._hooks:
|
|
|
|
self._hooks.remove(cb)
|
|
|
|
|
2020-06-04 10:20:03 +02:00
|
|
|
def count(self) -> int:
|
|
|
|
return len(self._hooks)
|
|
|
|
|
2020-04-03 10:54:54 +02:00
|
|
|
def __call__(self, addcards: aqt.addcards.AddCards) -> None:
|
|
|
|
for hook in self._hooks:
|
|
|
|
try:
|
|
|
|
hook(addcards)
|
|
|
|
except:
|
|
|
|
# if the hook fails, remove it
|
|
|
|
self._hooks.remove(hook)
|
|
|
|
raise
|
|
|
|
|
|
|
|
|
|
|
|
add_cards_did_init = _AddCardsDidInitHook()
|
|
|
|
|
|
|
|
|
2020-03-20 11:59:59 +01:00
|
|
|
class _AddCardsWillAddNoteFilter:
|
2020-03-06 16:25:02 +01:00
|
|
|
"""Decides whether the note should be added to the collection or
|
|
|
|
not. It is assumed to come from the addCards window.
|
|
|
|
|
|
|
|
reason_to_already_reject is the first reason to reject that
|
|
|
|
was found, or None. If your filter wants to reject, it should
|
|
|
|
replace return the reason to reject. Otherwise return the
|
|
|
|
input."""
|
|
|
|
|
|
|
|
_hooks: List[Callable[[Optional[str], "anki.notes.Note"], Optional[str]]] = []
|
|
|
|
|
|
|
|
def append(
|
|
|
|
self, cb: Callable[[Optional[str], "anki.notes.Note"], Optional[str]]
|
|
|
|
) -> None:
|
2020-03-20 11:59:59 +01:00
|
|
|
"""(problem: Optional[str], note: anki.notes.Note)"""
|
2020-03-06 16:25:02 +01:00
|
|
|
self._hooks.append(cb)
|
|
|
|
|
|
|
|
def remove(
|
|
|
|
self, cb: Callable[[Optional[str], "anki.notes.Note"], Optional[str]]
|
|
|
|
) -> None:
|
|
|
|
if cb in self._hooks:
|
|
|
|
self._hooks.remove(cb)
|
|
|
|
|
2020-06-04 10:20:03 +02:00
|
|
|
def count(self) -> int:
|
|
|
|
return len(self._hooks)
|
|
|
|
|
2020-03-20 11:59:59 +01:00
|
|
|
def __call__(self, problem: Optional[str], note: anki.notes.Note) -> Optional[str]:
|
2020-03-06 16:25:02 +01:00
|
|
|
for filter in self._hooks:
|
|
|
|
try:
|
2020-03-20 11:59:59 +01:00
|
|
|
problem = filter(problem, note)
|
2020-03-06 16:25:02 +01:00
|
|
|
except:
|
|
|
|
# if the hook fails, remove it
|
|
|
|
self._hooks.remove(filter)
|
|
|
|
raise
|
2020-03-20 11:59:59 +01:00
|
|
|
return problem
|
2020-03-06 16:25:02 +01:00
|
|
|
|
|
|
|
|
2020-03-20 11:59:59 +01:00
|
|
|
add_cards_will_add_note = _AddCardsWillAddNoteFilter()
|
2020-01-15 03:16:54 +01:00
|
|
|
|
|
|
|
|
2020-01-15 08:45:35 +01:00
|
|
|
class _AddCardsWillShowHistoryMenuHook:
|
|
|
|
_hooks: List[Callable[["aqt.addcards.AddCards", QMenu], None]] = []
|
2020-01-15 03:16:54 +01:00
|
|
|
|
2020-01-15 08:45:35 +01:00
|
|
|
def append(self, cb: Callable[["aqt.addcards.AddCards", QMenu], None]) -> None:
|
|
|
|
"""(addcards: aqt.addcards.AddCards, menu: QMenu)"""
|
2020-01-15 03:16:54 +01:00
|
|
|
self._hooks.append(cb)
|
|
|
|
|
2020-01-15 08:45:35 +01:00
|
|
|
def remove(self, cb: Callable[["aqt.addcards.AddCards", QMenu], None]) -> None:
|
2020-01-15 04:07:05 +01:00
|
|
|
if cb in self._hooks:
|
|
|
|
self._hooks.remove(cb)
|
2020-01-15 03:16:54 +01:00
|
|
|
|
2020-06-04 10:20:03 +02:00
|
|
|
def count(self) -> int:
|
|
|
|
return len(self._hooks)
|
|
|
|
|
2020-01-15 08:45:35 +01:00
|
|
|
def __call__(self, addcards: aqt.addcards.AddCards, menu: QMenu) -> None:
|
2020-01-15 03:16:54 +01:00
|
|
|
for hook in self._hooks:
|
|
|
|
try:
|
2020-01-15 08:45:35 +01:00
|
|
|
hook(addcards, menu)
|
2020-01-15 03:16:54 +01:00
|
|
|
except:
|
|
|
|
# if the hook fails, remove it
|
|
|
|
self._hooks.remove(hook)
|
|
|
|
raise
|
|
|
|
# legacy support
|
2020-01-15 08:45:35 +01:00
|
|
|
runHook("AddCards.onHistory", addcards, menu)
|
2020-01-15 03:16:54 +01:00
|
|
|
|
|
|
|
|
2020-01-15 08:45:35 +01:00
|
|
|
add_cards_will_show_history_menu = _AddCardsWillShowHistoryMenuHook()
|
2020-01-15 03:16:54 +01:00
|
|
|
|
|
|
|
|
2020-06-03 23:29:09 +02:00
|
|
|
class _AddcardsWillAddHistoryEntryFilter:
|
|
|
|
"""Allows changing the history line in the add-card window."""
|
|
|
|
|
|
|
|
_hooks: List[Callable[[str, "anki.notes.Note"], str]] = []
|
|
|
|
|
|
|
|
def append(self, cb: Callable[[str, "anki.notes.Note"], str]) -> None:
|
|
|
|
"""(line: str, note: anki.notes.Note)"""
|
|
|
|
self._hooks.append(cb)
|
|
|
|
|
|
|
|
def remove(self, cb: Callable[[str, "anki.notes.Note"], str]) -> None:
|
|
|
|
if cb in self._hooks:
|
|
|
|
self._hooks.remove(cb)
|
|
|
|
|
|
|
|
def count(self) -> int:
|
|
|
|
return len(self._hooks)
|
|
|
|
|
|
|
|
def __call__(self, line: str, note: anki.notes.Note) -> str:
|
|
|
|
for filter in self._hooks:
|
|
|
|
try:
|
|
|
|
line = filter(line, note)
|
|
|
|
except:
|
|
|
|
# if the hook fails, remove it
|
|
|
|
self._hooks.remove(filter)
|
|
|
|
raise
|
|
|
|
return line
|
|
|
|
|
|
|
|
|
|
|
|
addcards_will_add_history_entry = _AddcardsWillAddHistoryEntryFilter()
|
|
|
|
|
|
|
|
|
2020-03-02 00:54:58 +01:00
|
|
|
class _AddonConfigEditorWillDisplayJsonFilter:
|
|
|
|
"""Allows changing the text of the json configuration before actually
|
|
|
|
displaying it to the user. For example, you can replace "\n" by
|
|
|
|
some actual new line. Then you can replace the new lines by "\n"
|
|
|
|
while reading the file and let the user uses real new line in
|
|
|
|
string instead of its encoding."""
|
|
|
|
|
|
|
|
_hooks: List[Callable[[str], str]] = []
|
|
|
|
|
|
|
|
def append(self, cb: Callable[[str], str]) -> None:
|
|
|
|
"""(text: str)"""
|
|
|
|
self._hooks.append(cb)
|
|
|
|
|
|
|
|
def remove(self, cb: Callable[[str], str]) -> None:
|
|
|
|
if cb in self._hooks:
|
|
|
|
self._hooks.remove(cb)
|
|
|
|
|
2020-06-04 10:20:03 +02:00
|
|
|
def count(self) -> int:
|
|
|
|
return len(self._hooks)
|
|
|
|
|
2020-03-02 00:54:58 +01:00
|
|
|
def __call__(self, text: str) -> str:
|
|
|
|
for filter in self._hooks:
|
|
|
|
try:
|
|
|
|
text = filter(text)
|
|
|
|
except:
|
|
|
|
# if the hook fails, remove it
|
|
|
|
self._hooks.remove(filter)
|
|
|
|
raise
|
|
|
|
return text
|
|
|
|
|
|
|
|
|
|
|
|
addon_config_editor_will_display_json = _AddonConfigEditorWillDisplayJsonFilter()
|
|
|
|
|
|
|
|
|
2020-03-02 01:09:52 +01:00
|
|
|
class _AddonConfigEditorWillSaveJsonFilter:
|
|
|
|
"""Allows changing the text of the json configuration that was
|
|
|
|
received from the user before actually reading it. For
|
|
|
|
example, you can replace new line in strings by some "\n"."""
|
|
|
|
|
|
|
|
_hooks: List[Callable[[str], str]] = []
|
|
|
|
|
|
|
|
def append(self, cb: Callable[[str], str]) -> None:
|
|
|
|
"""(text: str)"""
|
|
|
|
self._hooks.append(cb)
|
|
|
|
|
|
|
|
def remove(self, cb: Callable[[str], str]) -> None:
|
|
|
|
if cb in self._hooks:
|
|
|
|
self._hooks.remove(cb)
|
|
|
|
|
2020-06-04 10:20:03 +02:00
|
|
|
def count(self) -> int:
|
|
|
|
return len(self._hooks)
|
|
|
|
|
2020-03-02 01:09:52 +01:00
|
|
|
def __call__(self, text: str) -> str:
|
|
|
|
for filter in self._hooks:
|
|
|
|
try:
|
|
|
|
text = filter(text)
|
|
|
|
except:
|
|
|
|
# if the hook fails, remove it
|
|
|
|
self._hooks.remove(filter)
|
|
|
|
raise
|
|
|
|
return text
|
|
|
|
|
|
|
|
|
|
|
|
addon_config_editor_will_save_json = _AddonConfigEditorWillSaveJsonFilter()
|
|
|
|
|
|
|
|
|
2020-03-06 22:21:42 +01:00
|
|
|
class _AddonsDialogDidChangeSelectedAddonHook:
|
|
|
|
"""Allows doing an action when a single add-on is selected."""
|
|
|
|
|
|
|
|
_hooks: List[
|
|
|
|
Callable[["aqt.addons.AddonsDialog", "aqt.addons.AddonMeta"], None]
|
|
|
|
] = []
|
|
|
|
|
|
|
|
def append(
|
|
|
|
self, cb: Callable[["aqt.addons.AddonsDialog", "aqt.addons.AddonMeta"], None]
|
|
|
|
) -> None:
|
|
|
|
"""(dialog: aqt.addons.AddonsDialog, add_on: aqt.addons.AddonMeta)"""
|
|
|
|
self._hooks.append(cb)
|
|
|
|
|
|
|
|
def remove(
|
|
|
|
self, cb: Callable[["aqt.addons.AddonsDialog", "aqt.addons.AddonMeta"], None]
|
|
|
|
) -> None:
|
|
|
|
if cb in self._hooks:
|
|
|
|
self._hooks.remove(cb)
|
|
|
|
|
2020-06-04 10:20:03 +02:00
|
|
|
def count(self) -> int:
|
|
|
|
return len(self._hooks)
|
|
|
|
|
2020-03-06 22:21:42 +01:00
|
|
|
def __call__(
|
|
|
|
self, dialog: aqt.addons.AddonsDialog, add_on: aqt.addons.AddonMeta
|
|
|
|
) -> None:
|
|
|
|
for hook in self._hooks:
|
|
|
|
try:
|
|
|
|
hook(dialog, add_on)
|
|
|
|
except:
|
|
|
|
# if the hook fails, remove it
|
|
|
|
self._hooks.remove(hook)
|
|
|
|
raise
|
|
|
|
|
|
|
|
|
|
|
|
addons_dialog_did_change_selected_addon = _AddonsDialogDidChangeSelectedAddonHook()
|
|
|
|
|
|
|
|
|
2020-03-06 21:04:51 +01:00
|
|
|
class _AddonsDialogWillShowHook:
|
|
|
|
"""Allows changing the add-on dialog before it is shown. E.g. add
|
|
|
|
buttons."""
|
|
|
|
|
|
|
|
_hooks: List[Callable[["aqt.addons.AddonsDialog"], None]] = []
|
|
|
|
|
|
|
|
def append(self, cb: Callable[["aqt.addons.AddonsDialog"], None]) -> None:
|
|
|
|
"""(dialog: aqt.addons.AddonsDialog)"""
|
|
|
|
self._hooks.append(cb)
|
|
|
|
|
|
|
|
def remove(self, cb: Callable[["aqt.addons.AddonsDialog"], None]) -> None:
|
|
|
|
if cb in self._hooks:
|
|
|
|
self._hooks.remove(cb)
|
|
|
|
|
2020-06-04 10:20:03 +02:00
|
|
|
def count(self) -> int:
|
|
|
|
return len(self._hooks)
|
|
|
|
|
2020-03-06 21:04:51 +01:00
|
|
|
def __call__(self, dialog: aqt.addons.AddonsDialog) -> None:
|
|
|
|
for hook in self._hooks:
|
|
|
|
try:
|
|
|
|
hook(dialog)
|
|
|
|
except:
|
|
|
|
# if the hook fails, remove it
|
|
|
|
self._hooks.remove(hook)
|
|
|
|
raise
|
|
|
|
|
|
|
|
|
|
|
|
addons_dialog_will_show = _AddonsDialogWillShowHook()
|
|
|
|
|
|
|
|
|
2020-01-22 05:39:18 +01:00
|
|
|
class _AvPlayerDidBeginPlayingHook:
|
|
|
|
_hooks: List[Callable[["aqt.sound.Player", "anki.sound.AVTag"], None]] = []
|
2020-01-20 13:01:38 +01:00
|
|
|
|
2020-01-22 05:39:18 +01:00
|
|
|
def append(
|
|
|
|
self, cb: Callable[["aqt.sound.Player", "anki.sound.AVTag"], None]
|
|
|
|
) -> None:
|
|
|
|
"""(player: aqt.sound.Player, tag: anki.sound.AVTag)"""
|
2020-01-20 13:01:38 +01:00
|
|
|
self._hooks.append(cb)
|
|
|
|
|
2020-01-22 05:39:18 +01:00
|
|
|
def remove(
|
|
|
|
self, cb: Callable[["aqt.sound.Player", "anki.sound.AVTag"], None]
|
|
|
|
) -> None:
|
2020-01-20 13:01:38 +01:00
|
|
|
if cb in self._hooks:
|
|
|
|
self._hooks.remove(cb)
|
|
|
|
|
2020-06-04 10:20:03 +02:00
|
|
|
def count(self) -> int:
|
|
|
|
return len(self._hooks)
|
|
|
|
|
2020-01-22 05:39:18 +01:00
|
|
|
def __call__(self, player: aqt.sound.Player, tag: anki.sound.AVTag) -> None:
|
2020-01-20 13:01:38 +01:00
|
|
|
for hook in self._hooks:
|
|
|
|
try:
|
2020-01-22 05:39:18 +01:00
|
|
|
hook(player, tag)
|
2020-01-20 13:01:38 +01:00
|
|
|
except:
|
|
|
|
# if the hook fails, remove it
|
|
|
|
self._hooks.remove(hook)
|
|
|
|
raise
|
|
|
|
|
|
|
|
|
2020-01-22 05:39:18 +01:00
|
|
|
av_player_did_begin_playing = _AvPlayerDidBeginPlayingHook()
|
|
|
|
|
|
|
|
|
|
|
|
class _AvPlayerDidEndPlayingHook:
|
|
|
|
_hooks: List[Callable[["aqt.sound.Player"], None]] = []
|
|
|
|
|
|
|
|
def append(self, cb: Callable[["aqt.sound.Player"], None]) -> None:
|
|
|
|
"""(player: aqt.sound.Player)"""
|
|
|
|
self._hooks.append(cb)
|
|
|
|
|
|
|
|
def remove(self, cb: Callable[["aqt.sound.Player"], None]) -> None:
|
|
|
|
if cb in self._hooks:
|
|
|
|
self._hooks.remove(cb)
|
|
|
|
|
2020-06-04 10:20:03 +02:00
|
|
|
def count(self) -> int:
|
|
|
|
return len(self._hooks)
|
|
|
|
|
2020-01-22 05:39:18 +01:00
|
|
|
def __call__(self, player: aqt.sound.Player) -> None:
|
|
|
|
for hook in self._hooks:
|
|
|
|
try:
|
|
|
|
hook(player)
|
|
|
|
except:
|
|
|
|
# if the hook fails, remove it
|
|
|
|
self._hooks.remove(hook)
|
|
|
|
raise
|
|
|
|
|
|
|
|
|
|
|
|
av_player_did_end_playing = _AvPlayerDidEndPlayingHook()
|
2020-01-20 13:01:38 +01:00
|
|
|
|
|
|
|
|
|
|
|
class _AvPlayerWillPlayHook:
|
|
|
|
_hooks: List[Callable[["anki.sound.AVTag"], None]] = []
|
|
|
|
|
|
|
|
def append(self, cb: Callable[["anki.sound.AVTag"], None]) -> None:
|
|
|
|
"""(tag: anki.sound.AVTag)"""
|
|
|
|
self._hooks.append(cb)
|
|
|
|
|
|
|
|
def remove(self, cb: Callable[["anki.sound.AVTag"], None]) -> None:
|
|
|
|
if cb in self._hooks:
|
|
|
|
self._hooks.remove(cb)
|
|
|
|
|
2020-06-04 10:20:03 +02:00
|
|
|
def count(self) -> int:
|
|
|
|
return len(self._hooks)
|
|
|
|
|
2020-01-20 13:01:38 +01:00
|
|
|
def __call__(self, tag: anki.sound.AVTag) -> None:
|
|
|
|
for hook in self._hooks:
|
|
|
|
try:
|
|
|
|
hook(tag)
|
|
|
|
except:
|
|
|
|
# if the hook fails, remove it
|
|
|
|
self._hooks.remove(hook)
|
|
|
|
raise
|
|
|
|
|
|
|
|
|
|
|
|
av_player_will_play = _AvPlayerWillPlayHook()
|
|
|
|
|
|
|
|
|
2020-03-20 11:59:59 +01:00
|
|
|
class _BackupDidCompleteHook:
|
2020-03-19 13:20:06 +01:00
|
|
|
_hooks: List[Callable[[], None]] = []
|
|
|
|
|
|
|
|
def append(self, cb: Callable[[], None]) -> None:
|
|
|
|
"""()"""
|
|
|
|
self._hooks.append(cb)
|
|
|
|
|
|
|
|
def remove(self, cb: Callable[[], None]) -> None:
|
|
|
|
if cb in self._hooks:
|
|
|
|
self._hooks.remove(cb)
|
|
|
|
|
2020-06-04 10:20:03 +02:00
|
|
|
def count(self) -> int:
|
|
|
|
return len(self._hooks)
|
|
|
|
|
2020-03-19 13:20:06 +01:00
|
|
|
def __call__(self) -> None:
|
|
|
|
for hook in self._hooks:
|
|
|
|
try:
|
|
|
|
hook()
|
|
|
|
except:
|
|
|
|
# if the hook fails, remove it
|
|
|
|
self._hooks.remove(hook)
|
|
|
|
raise
|
|
|
|
|
|
|
|
|
2020-03-20 11:59:59 +01:00
|
|
|
backup_did_complete = _BackupDidCompleteHook()
|
2020-03-19 13:20:06 +01:00
|
|
|
|
|
|
|
|
2020-01-15 08:45:35 +01:00
|
|
|
class _BrowserDidChangeRowHook:
|
|
|
|
_hooks: List[Callable[["aqt.browser.Browser"], None]] = []
|
2020-01-14 23:53:57 +01:00
|
|
|
|
2020-01-15 08:45:35 +01:00
|
|
|
def append(self, cb: Callable[["aqt.browser.Browser"], None]) -> None:
|
|
|
|
"""(browser: aqt.browser.Browser)"""
|
2020-01-14 23:53:57 +01:00
|
|
|
self._hooks.append(cb)
|
|
|
|
|
2020-01-15 08:45:35 +01:00
|
|
|
def remove(self, cb: Callable[["aqt.browser.Browser"], None]) -> None:
|
2020-01-15 04:07:05 +01:00
|
|
|
if cb in self._hooks:
|
|
|
|
self._hooks.remove(cb)
|
2020-01-14 23:53:57 +01:00
|
|
|
|
2020-06-04 10:20:03 +02:00
|
|
|
def count(self) -> int:
|
|
|
|
return len(self._hooks)
|
|
|
|
|
2020-01-15 08:45:35 +01:00
|
|
|
def __call__(self, browser: aqt.browser.Browser) -> None:
|
2020-01-14 23:53:57 +01:00
|
|
|
for hook in self._hooks:
|
|
|
|
try:
|
2020-01-15 08:45:35 +01:00
|
|
|
hook(browser)
|
2020-01-14 23:53:57 +01:00
|
|
|
except:
|
|
|
|
# if the hook fails, remove it
|
|
|
|
self._hooks.remove(hook)
|
|
|
|
raise
|
|
|
|
# legacy support
|
2020-01-15 08:45:35 +01:00
|
|
|
runHook("browser.rowChanged", browser)
|
2020-01-14 23:53:57 +01:00
|
|
|
|
|
|
|
|
2020-01-15 08:45:35 +01:00
|
|
|
browser_did_change_row = _BrowserDidChangeRowHook()
|
2020-01-14 23:53:57 +01:00
|
|
|
|
|
|
|
|
2020-03-21 07:38:46 +01:00
|
|
|
class _BrowserDidSearchHook:
|
|
|
|
"""Allows you to modify the list of returned card ids from a search."""
|
|
|
|
|
|
|
|
_hooks: List[Callable[["aqt.browser.SearchContext"], None]] = []
|
|
|
|
|
|
|
|
def append(self, cb: Callable[["aqt.browser.SearchContext"], None]) -> None:
|
|
|
|
"""(context: aqt.browser.SearchContext)"""
|
|
|
|
self._hooks.append(cb)
|
|
|
|
|
|
|
|
def remove(self, cb: Callable[["aqt.browser.SearchContext"], None]) -> None:
|
|
|
|
if cb in self._hooks:
|
|
|
|
self._hooks.remove(cb)
|
|
|
|
|
2020-06-04 10:20:03 +02:00
|
|
|
def count(self) -> int:
|
|
|
|
return len(self._hooks)
|
|
|
|
|
2020-03-21 07:38:46 +01:00
|
|
|
def __call__(self, context: aqt.browser.SearchContext) -> None:
|
|
|
|
for hook in self._hooks:
|
|
|
|
try:
|
|
|
|
hook(context)
|
|
|
|
except:
|
|
|
|
# if the hook fails, remove it
|
|
|
|
self._hooks.remove(hook)
|
|
|
|
raise
|
|
|
|
|
|
|
|
|
|
|
|
browser_did_search = _BrowserDidSearchHook()
|
|
|
|
|
|
|
|
|
2020-03-27 23:06:22 +01:00
|
|
|
class _BrowserHeaderWillShowContextMenuHook:
|
|
|
|
_hooks: List[Callable[["aqt.browser.Browser", QMenu], None]] = []
|
|
|
|
|
|
|
|
def append(self, cb: Callable[["aqt.browser.Browser", QMenu], None]) -> None:
|
|
|
|
"""(browser: aqt.browser.Browser, menu: QMenu)"""
|
|
|
|
self._hooks.append(cb)
|
|
|
|
|
|
|
|
def remove(self, cb: Callable[["aqt.browser.Browser", QMenu], None]) -> None:
|
|
|
|
if cb in self._hooks:
|
|
|
|
self._hooks.remove(cb)
|
|
|
|
|
2020-06-04 10:20:03 +02:00
|
|
|
def count(self) -> int:
|
|
|
|
return len(self._hooks)
|
|
|
|
|
2020-03-27 23:06:22 +01:00
|
|
|
def __call__(self, browser: aqt.browser.Browser, menu: QMenu) -> None:
|
|
|
|
for hook in self._hooks:
|
|
|
|
try:
|
|
|
|
hook(browser, menu)
|
|
|
|
except:
|
|
|
|
# if the hook fails, remove it
|
|
|
|
self._hooks.remove(hook)
|
|
|
|
raise
|
|
|
|
|
|
|
|
|
|
|
|
browser_header_will_show_context_menu = _BrowserHeaderWillShowContextMenuHook()
|
|
|
|
|
|
|
|
|
2020-01-15 08:18:11 +01:00
|
|
|
class _BrowserMenusDidInitHook:
|
2020-01-14 23:53:57 +01:00
|
|
|
_hooks: List[Callable[["aqt.browser.Browser"], None]] = []
|
|
|
|
|
|
|
|
def append(self, cb: Callable[["aqt.browser.Browser"], None]) -> None:
|
|
|
|
"""(browser: aqt.browser.Browser)"""
|
|
|
|
self._hooks.append(cb)
|
|
|
|
|
|
|
|
def remove(self, cb: Callable[["aqt.browser.Browser"], None]) -> None:
|
2020-01-15 04:07:05 +01:00
|
|
|
if cb in self._hooks:
|
|
|
|
self._hooks.remove(cb)
|
2020-01-14 23:53:57 +01:00
|
|
|
|
2020-06-04 10:20:03 +02:00
|
|
|
def count(self) -> int:
|
|
|
|
return len(self._hooks)
|
|
|
|
|
2020-01-14 23:53:57 +01:00
|
|
|
def __call__(self, browser: aqt.browser.Browser) -> None:
|
|
|
|
for hook in self._hooks:
|
|
|
|
try:
|
|
|
|
hook(browser)
|
|
|
|
except:
|
|
|
|
# if the hook fails, remove it
|
|
|
|
self._hooks.remove(hook)
|
|
|
|
raise
|
|
|
|
# legacy support
|
2020-01-15 03:16:54 +01:00
|
|
|
runHook("browser.setupMenus", browser)
|
2020-01-14 23:53:57 +01:00
|
|
|
|
|
|
|
|
2020-01-15 08:18:11 +01:00
|
|
|
browser_menus_did_init = _BrowserMenusDidInitHook()
|
2020-01-14 23:53:57 +01:00
|
|
|
|
|
|
|
|
2020-02-15 21:03:15 +01:00
|
|
|
class _BrowserWillBuildTreeFilter:
|
|
|
|
"""Used to add or replace items in the browser sidebar tree
|
|
|
|
|
|
|
|
'tree' is the root SidebarItem that all other items are added to.
|
|
|
|
|
|
|
|
'stage' is an enum describing the different construction stages of
|
|
|
|
the sidebar tree at which you can interject your changes.
|
|
|
|
The different values can be inspected by looking at
|
|
|
|
aqt.browser.SidebarStage.
|
|
|
|
|
|
|
|
If you want Anki to proceed with the construction of the tree stage
|
|
|
|
in question after your have performed your changes or additions,
|
|
|
|
return the 'handled' boolean unchanged.
|
|
|
|
|
|
|
|
On the other hand, if you want to prevent Anki from adding its own
|
|
|
|
items at a particular construction stage (e.g. in case your add-on
|
|
|
|
implements its own version of that particular stage), return 'True'.
|
|
|
|
|
|
|
|
If you return 'True' at SidebarStage.ROOT, the sidebar will not be
|
|
|
|
populated by any of the other construction stages. For any other stage
|
|
|
|
the tree construction will just continue as usual.
|
|
|
|
|
|
|
|
For example, if your code wishes to replace the tag tree, you could do:
|
|
|
|
|
|
|
|
def on_browser_will_build_tree(handled, root, stage, browser):
|
|
|
|
if stage != SidebarStage.TAGS:
|
|
|
|
# not at tag tree building stage, pass on
|
|
|
|
return handled
|
|
|
|
|
|
|
|
# your tag tree construction code
|
|
|
|
# root.addChild(...)
|
|
|
|
|
|
|
|
# your code handled tag tree construction, no need for Anki
|
|
|
|
# or other add-ons to build the tag tree
|
|
|
|
return True
|
|
|
|
"""
|
|
|
|
|
|
|
|
_hooks: List[
|
|
|
|
Callable[
|
|
|
|
[
|
|
|
|
bool,
|
|
|
|
"aqt.browser.SidebarItem",
|
|
|
|
"aqt.browser.SidebarStage",
|
|
|
|
"aqt.browser.Browser",
|
|
|
|
],
|
|
|
|
bool,
|
|
|
|
]
|
|
|
|
] = []
|
|
|
|
|
|
|
|
def append(
|
|
|
|
self,
|
|
|
|
cb: Callable[
|
|
|
|
[
|
|
|
|
bool,
|
|
|
|
"aqt.browser.SidebarItem",
|
|
|
|
"aqt.browser.SidebarStage",
|
|
|
|
"aqt.browser.Browser",
|
|
|
|
],
|
|
|
|
bool,
|
|
|
|
],
|
|
|
|
) -> None:
|
|
|
|
"""(handled: bool, tree: aqt.browser.SidebarItem, stage: aqt.browser.SidebarStage, browser: aqt.browser.Browser)"""
|
|
|
|
self._hooks.append(cb)
|
|
|
|
|
|
|
|
def remove(
|
|
|
|
self,
|
|
|
|
cb: Callable[
|
|
|
|
[
|
|
|
|
bool,
|
|
|
|
"aqt.browser.SidebarItem",
|
|
|
|
"aqt.browser.SidebarStage",
|
|
|
|
"aqt.browser.Browser",
|
|
|
|
],
|
|
|
|
bool,
|
|
|
|
],
|
|
|
|
) -> None:
|
|
|
|
if cb in self._hooks:
|
|
|
|
self._hooks.remove(cb)
|
|
|
|
|
2020-06-04 10:20:03 +02:00
|
|
|
def count(self) -> int:
|
|
|
|
return len(self._hooks)
|
|
|
|
|
2020-02-15 21:03:15 +01:00
|
|
|
def __call__(
|
|
|
|
self,
|
|
|
|
handled: bool,
|
|
|
|
tree: aqt.browser.SidebarItem,
|
|
|
|
stage: aqt.browser.SidebarStage,
|
|
|
|
browser: aqt.browser.Browser,
|
|
|
|
) -> bool:
|
|
|
|
for filter in self._hooks:
|
|
|
|
try:
|
|
|
|
handled = filter(handled, tree, stage, browser)
|
|
|
|
except:
|
|
|
|
# if the hook fails, remove it
|
|
|
|
self._hooks.remove(filter)
|
|
|
|
raise
|
|
|
|
return handled
|
|
|
|
|
|
|
|
|
|
|
|
browser_will_build_tree = _BrowserWillBuildTreeFilter()
|
|
|
|
|
|
|
|
|
2020-03-21 07:38:46 +01:00
|
|
|
class _BrowserWillSearchHook:
|
|
|
|
"""Allows you to modify the search text, or perform your own search.
|
|
|
|
|
|
|
|
You can modify context.search to change the text that is sent to the
|
|
|
|
searching backend.
|
|
|
|
|
|
|
|
If you set context.card_ids to a list of ids, the regular search will
|
|
|
|
not be performed, and the provided ids will be used instead.
|
|
|
|
|
|
|
|
Your add-on should check if context.card_ids is not None, and return
|
|
|
|
without making changes if it has been set.
|
|
|
|
"""
|
|
|
|
|
|
|
|
_hooks: List[Callable[["aqt.browser.SearchContext"], None]] = []
|
|
|
|
|
|
|
|
def append(self, cb: Callable[["aqt.browser.SearchContext"], None]) -> None:
|
|
|
|
"""(context: aqt.browser.SearchContext)"""
|
|
|
|
self._hooks.append(cb)
|
|
|
|
|
|
|
|
def remove(self, cb: Callable[["aqt.browser.SearchContext"], None]) -> None:
|
|
|
|
if cb in self._hooks:
|
|
|
|
self._hooks.remove(cb)
|
|
|
|
|
2020-06-04 10:20:03 +02:00
|
|
|
def count(self) -> int:
|
|
|
|
return len(self._hooks)
|
|
|
|
|
2020-03-21 07:38:46 +01:00
|
|
|
def __call__(self, context: aqt.browser.SearchContext) -> None:
|
|
|
|
for hook in self._hooks:
|
|
|
|
try:
|
|
|
|
hook(context)
|
|
|
|
except:
|
|
|
|
# if the hook fails, remove it
|
|
|
|
self._hooks.remove(hook)
|
|
|
|
raise
|
|
|
|
|
|
|
|
|
|
|
|
browser_will_search = _BrowserWillSearchHook()
|
|
|
|
|
|
|
|
|
2020-02-29 17:02:51 +01:00
|
|
|
class _BrowserWillShowHook:
|
|
|
|
_hooks: List[Callable[["aqt.browser.Browser"], None]] = []
|
|
|
|
|
|
|
|
def append(self, cb: Callable[["aqt.browser.Browser"], None]) -> None:
|
|
|
|
"""(browser: aqt.browser.Browser)"""
|
|
|
|
self._hooks.append(cb)
|
|
|
|
|
|
|
|
def remove(self, cb: Callable[["aqt.browser.Browser"], None]) -> None:
|
|
|
|
if cb in self._hooks:
|
|
|
|
self._hooks.remove(cb)
|
|
|
|
|
2020-06-04 10:20:03 +02:00
|
|
|
def count(self) -> int:
|
|
|
|
return len(self._hooks)
|
|
|
|
|
2020-02-29 17:02:51 +01:00
|
|
|
def __call__(self, browser: aqt.browser.Browser) -> None:
|
|
|
|
for hook in self._hooks:
|
|
|
|
try:
|
|
|
|
hook(browser)
|
|
|
|
except:
|
|
|
|
# if the hook fails, remove it
|
|
|
|
self._hooks.remove(hook)
|
|
|
|
raise
|
|
|
|
|
|
|
|
|
|
|
|
browser_will_show = _BrowserWillShowHook()
|
|
|
|
|
|
|
|
|
2020-01-15 08:45:35 +01:00
|
|
|
class _BrowserWillShowContextMenuHook:
|
|
|
|
_hooks: List[Callable[["aqt.browser.Browser", QMenu], None]] = []
|
2020-01-14 23:53:57 +01:00
|
|
|
|
2020-01-15 08:45:35 +01:00
|
|
|
def append(self, cb: Callable[["aqt.browser.Browser", QMenu], None]) -> None:
|
|
|
|
"""(browser: aqt.browser.Browser, menu: QMenu)"""
|
2020-01-14 23:53:57 +01:00
|
|
|
self._hooks.append(cb)
|
|
|
|
|
2020-01-15 08:45:35 +01:00
|
|
|
def remove(self, cb: Callable[["aqt.browser.Browser", QMenu], None]) -> None:
|
2020-01-15 04:07:05 +01:00
|
|
|
if cb in self._hooks:
|
|
|
|
self._hooks.remove(cb)
|
2020-01-14 23:53:57 +01:00
|
|
|
|
2020-06-04 10:20:03 +02:00
|
|
|
def count(self) -> int:
|
|
|
|
return len(self._hooks)
|
|
|
|
|
2020-01-15 08:45:35 +01:00
|
|
|
def __call__(self, browser: aqt.browser.Browser, menu: QMenu) -> None:
|
2020-01-14 23:53:57 +01:00
|
|
|
for hook in self._hooks:
|
|
|
|
try:
|
2020-01-15 08:45:35 +01:00
|
|
|
hook(browser, menu)
|
2020-01-14 23:53:57 +01:00
|
|
|
except:
|
|
|
|
# if the hook fails, remove it
|
|
|
|
self._hooks.remove(hook)
|
|
|
|
raise
|
|
|
|
# legacy support
|
2020-01-15 08:45:35 +01:00
|
|
|
runHook("browser.onContextMenu", browser, menu)
|
2020-01-14 23:53:57 +01:00
|
|
|
|
|
|
|
|
2020-01-15 08:45:35 +01:00
|
|
|
browser_will_show_context_menu = _BrowserWillShowContextMenuHook()
|
2020-01-14 23:53:57 +01:00
|
|
|
|
|
|
|
|
2020-02-28 13:34:54 +01:00
|
|
|
class _CardLayoutWillShowHook:
|
|
|
|
"""Allow to change the display of the card layout. After most values are
|
|
|
|
set and before the window is actually shown."""
|
|
|
|
|
|
|
|
_hooks: List[Callable[["aqt.clayout.CardLayout"], None]] = []
|
|
|
|
|
|
|
|
def append(self, cb: Callable[["aqt.clayout.CardLayout"], None]) -> None:
|
|
|
|
"""(clayout: aqt.clayout.CardLayout)"""
|
|
|
|
self._hooks.append(cb)
|
|
|
|
|
|
|
|
def remove(self, cb: Callable[["aqt.clayout.CardLayout"], None]) -> None:
|
|
|
|
if cb in self._hooks:
|
|
|
|
self._hooks.remove(cb)
|
|
|
|
|
2020-06-04 10:20:03 +02:00
|
|
|
def count(self) -> int:
|
|
|
|
return len(self._hooks)
|
|
|
|
|
2020-02-28 13:34:54 +01:00
|
|
|
def __call__(self, clayout: aqt.clayout.CardLayout) -> None:
|
|
|
|
for hook in self._hooks:
|
|
|
|
try:
|
|
|
|
hook(clayout)
|
|
|
|
except:
|
|
|
|
# if the hook fails, remove it
|
|
|
|
self._hooks.remove(hook)
|
|
|
|
raise
|
|
|
|
|
|
|
|
|
|
|
|
card_layout_will_show = _CardLayoutWillShowHook()
|
|
|
|
|
|
|
|
|
2020-01-15 08:45:35 +01:00
|
|
|
class _CardWillShowFilter:
|
2020-01-15 04:03:11 +01:00
|
|
|
"""Can modify card text before review/preview."""
|
|
|
|
|
2020-01-14 23:53:57 +01:00
|
|
|
_hooks: List[Callable[[str, Card, str], str]] = []
|
|
|
|
|
|
|
|
def append(self, cb: Callable[[str, Card, str], str]) -> None:
|
|
|
|
"""(text: str, card: Card, kind: str)"""
|
|
|
|
self._hooks.append(cb)
|
|
|
|
|
|
|
|
def remove(self, cb: Callable[[str, Card, str], str]) -> None:
|
2020-01-15 04:07:05 +01:00
|
|
|
if cb in self._hooks:
|
|
|
|
self._hooks.remove(cb)
|
2020-01-14 23:53:57 +01:00
|
|
|
|
2020-06-04 10:20:03 +02:00
|
|
|
def count(self) -> int:
|
|
|
|
return len(self._hooks)
|
|
|
|
|
2020-01-14 23:53:57 +01:00
|
|
|
def __call__(self, text: str, card: Card, kind: str) -> str:
|
|
|
|
for filter in self._hooks:
|
|
|
|
try:
|
|
|
|
text = filter(text, card, kind)
|
|
|
|
except:
|
|
|
|
# if the hook fails, remove it
|
|
|
|
self._hooks.remove(filter)
|
|
|
|
raise
|
|
|
|
# legacy support
|
2020-02-20 17:05:27 +01:00
|
|
|
text = runFilter("prepareQA", text, card, kind)
|
2020-01-14 23:53:57 +01:00
|
|
|
return text
|
|
|
|
|
|
|
|
|
2020-01-15 08:45:35 +01:00
|
|
|
card_will_show = _CardWillShowFilter()
|
2020-01-14 23:53:57 +01:00
|
|
|
|
|
|
|
|
2020-01-15 03:16:54 +01:00
|
|
|
class _CollectionDidLoadHook:
|
2020-05-20 09:56:52 +02:00
|
|
|
_hooks: List[Callable[["anki.collection.Collection"], None]] = []
|
2020-01-15 03:16:54 +01:00
|
|
|
|
2020-05-20 09:56:52 +02:00
|
|
|
def append(self, cb: Callable[["anki.collection.Collection"], None]) -> None:
|
2020-05-20 11:45:46 +02:00
|
|
|
"""(col: anki.collection.Collection)"""
|
2020-01-15 03:16:54 +01:00
|
|
|
self._hooks.append(cb)
|
|
|
|
|
2020-05-20 09:56:52 +02:00
|
|
|
def remove(self, cb: Callable[["anki.collection.Collection"], None]) -> None:
|
2020-01-15 04:07:05 +01:00
|
|
|
if cb in self._hooks:
|
|
|
|
self._hooks.remove(cb)
|
2020-01-15 03:16:54 +01:00
|
|
|
|
2020-06-04 10:20:03 +02:00
|
|
|
def count(self) -> int:
|
|
|
|
return len(self._hooks)
|
|
|
|
|
2020-05-20 09:56:52 +02:00
|
|
|
def __call__(self, col: anki.collection.Collection) -> None:
|
2020-01-15 03:16:54 +01:00
|
|
|
for hook in self._hooks:
|
|
|
|
try:
|
|
|
|
hook(col)
|
|
|
|
except:
|
|
|
|
# if the hook fails, remove it
|
|
|
|
self._hooks.remove(hook)
|
|
|
|
raise
|
|
|
|
# legacy support
|
|
|
|
runHook("colLoading", col)
|
|
|
|
|
|
|
|
|
2020-01-15 07:53:24 +01:00
|
|
|
collection_did_load = _CollectionDidLoadHook()
|
2020-01-15 03:16:54 +01:00
|
|
|
|
|
|
|
|
|
|
|
class _CurrentNoteTypeDidChangeHook:
|
2020-08-11 23:01:30 +02:00
|
|
|
_hooks: List[Callable[[NoteType], None]] = []
|
2020-01-14 23:53:57 +01:00
|
|
|
|
2020-08-11 23:01:30 +02:00
|
|
|
def append(self, cb: Callable[[NoteType], None]) -> None:
|
|
|
|
"""(notetype: NoteType)"""
|
2020-01-14 23:53:57 +01:00
|
|
|
self._hooks.append(cb)
|
|
|
|
|
2020-08-11 23:01:30 +02:00
|
|
|
def remove(self, cb: Callable[[NoteType], None]) -> None:
|
2020-01-15 04:07:05 +01:00
|
|
|
if cb in self._hooks:
|
|
|
|
self._hooks.remove(cb)
|
2020-01-14 23:53:57 +01:00
|
|
|
|
2020-06-04 10:20:03 +02:00
|
|
|
def count(self) -> int:
|
|
|
|
return len(self._hooks)
|
|
|
|
|
2020-08-11 23:01:30 +02:00
|
|
|
def __call__(self, notetype: NoteType) -> None:
|
2020-01-14 23:53:57 +01:00
|
|
|
for hook in self._hooks:
|
|
|
|
try:
|
|
|
|
hook(notetype)
|
|
|
|
except:
|
|
|
|
# if the hook fails, remove it
|
|
|
|
self._hooks.remove(hook)
|
|
|
|
raise
|
|
|
|
# legacy support
|
|
|
|
runHook("currentModelChanged")
|
|
|
|
|
|
|
|
|
2020-01-15 07:53:24 +01:00
|
|
|
current_note_type_did_change = _CurrentNoteTypeDidChangeHook()
|
2020-01-15 03:16:54 +01:00
|
|
|
|
|
|
|
|
2020-03-04 18:20:02 +01:00
|
|
|
class _DebugConsoleDidEvaluatePythonFilter:
|
|
|
|
"""Allows processing the debug result. E.g. logging queries and
|
|
|
|
result, saving last query to display it later..."""
|
|
|
|
|
|
|
|
_hooks: List[Callable[[str, str, QDialog], str]] = []
|
|
|
|
|
|
|
|
def append(self, cb: Callable[[str, str, QDialog], str]) -> None:
|
|
|
|
"""(output: str, query: str, debug_window: QDialog)"""
|
|
|
|
self._hooks.append(cb)
|
|
|
|
|
|
|
|
def remove(self, cb: Callable[[str, str, QDialog], str]) -> None:
|
|
|
|
if cb in self._hooks:
|
|
|
|
self._hooks.remove(cb)
|
|
|
|
|
2020-06-04 10:20:03 +02:00
|
|
|
def count(self) -> int:
|
|
|
|
return len(self._hooks)
|
|
|
|
|
2020-03-04 18:20:02 +01:00
|
|
|
def __call__(self, output: str, query: str, debug_window: QDialog) -> str:
|
|
|
|
for filter in self._hooks:
|
|
|
|
try:
|
|
|
|
output = filter(output, query, debug_window)
|
|
|
|
except:
|
|
|
|
# if the hook fails, remove it
|
|
|
|
self._hooks.remove(filter)
|
|
|
|
raise
|
|
|
|
return output
|
|
|
|
|
|
|
|
|
|
|
|
debug_console_did_evaluate_python = _DebugConsoleDidEvaluatePythonFilter()
|
|
|
|
|
|
|
|
|
2020-03-04 18:11:13 +01:00
|
|
|
class _DebugConsoleWillShowHook:
|
|
|
|
"""Allows editing the debug window. E.g. setting a default code, or
|
|
|
|
previous code."""
|
|
|
|
|
|
|
|
_hooks: List[Callable[[QDialog], None]] = []
|
|
|
|
|
|
|
|
def append(self, cb: Callable[[QDialog], None]) -> None:
|
|
|
|
"""(debug_window: QDialog)"""
|
|
|
|
self._hooks.append(cb)
|
|
|
|
|
|
|
|
def remove(self, cb: Callable[[QDialog], None]) -> None:
|
|
|
|
if cb in self._hooks:
|
|
|
|
self._hooks.remove(cb)
|
|
|
|
|
2020-06-04 10:20:03 +02:00
|
|
|
def count(self) -> int:
|
|
|
|
return len(self._hooks)
|
|
|
|
|
2020-03-04 18:11:13 +01:00
|
|
|
def __call__(self, debug_window: QDialog) -> None:
|
|
|
|
for hook in self._hooks:
|
|
|
|
try:
|
|
|
|
hook(debug_window)
|
|
|
|
except:
|
|
|
|
# if the hook fails, remove it
|
|
|
|
self._hooks.remove(hook)
|
|
|
|
raise
|
|
|
|
|
|
|
|
|
|
|
|
debug_console_will_show = _DebugConsoleWillShowHook()
|
|
|
|
|
|
|
|
|
2020-02-08 06:31:41 +01:00
|
|
|
class _DeckBrowserDidRenderHook:
|
|
|
|
"""Allow to update the deck browser window. E.g. change its title."""
|
|
|
|
|
|
|
|
_hooks: List[Callable[["aqt.deckbrowser.DeckBrowser"], None]] = []
|
|
|
|
|
|
|
|
def append(self, cb: Callable[["aqt.deckbrowser.DeckBrowser"], None]) -> None:
|
|
|
|
"""(deck_browser: aqt.deckbrowser.DeckBrowser)"""
|
|
|
|
self._hooks.append(cb)
|
|
|
|
|
|
|
|
def remove(self, cb: Callable[["aqt.deckbrowser.DeckBrowser"], None]) -> None:
|
|
|
|
if cb in self._hooks:
|
|
|
|
self._hooks.remove(cb)
|
|
|
|
|
2020-06-04 10:20:03 +02:00
|
|
|
def count(self) -> int:
|
|
|
|
return len(self._hooks)
|
|
|
|
|
2020-02-08 06:31:41 +01:00
|
|
|
def __call__(self, deck_browser: aqt.deckbrowser.DeckBrowser) -> None:
|
|
|
|
for hook in self._hooks:
|
|
|
|
try:
|
|
|
|
hook(deck_browser)
|
|
|
|
except:
|
|
|
|
# if the hook fails, remove it
|
|
|
|
self._hooks.remove(hook)
|
|
|
|
raise
|
|
|
|
|
|
|
|
|
|
|
|
deck_browser_did_render = _DeckBrowserDidRenderHook()
|
|
|
|
|
|
|
|
|
2020-02-17 16:26:21 +01:00
|
|
|
class _DeckBrowserWillRenderContentHook:
|
2020-02-16 19:29:01 +01:00
|
|
|
"""Used to modify HTML content sections in the deck browser body
|
|
|
|
|
2020-02-17 16:26:21 +01:00
|
|
|
'content' contains the sections of HTML content the deck browser body
|
|
|
|
will be updated with.
|
2020-02-16 19:29:01 +01:00
|
|
|
|
2020-02-17 16:26:21 +01:00
|
|
|
When modifying the content of a particular section, please make sure your
|
|
|
|
changes only perform the minimum required edits to make your add-on work.
|
|
|
|
You should avoid overwriting or interfering with existing data as much
|
|
|
|
as possible, instead opting to append your own changes, e.g.:
|
2020-02-16 19:29:01 +01:00
|
|
|
|
2020-02-17 16:26:21 +01:00
|
|
|
def on_deck_browser_will_render_content(deck_browser, content):
|
|
|
|
content.stats += "
|
|
|
|
<div>my html</div>"
|
2020-02-16 19:29:01 +01:00
|
|
|
"""
|
|
|
|
|
|
|
|
_hooks: List[
|
|
|
|
Callable[
|
2020-02-17 16:26:21 +01:00
|
|
|
["aqt.deckbrowser.DeckBrowser", "aqt.deckbrowser.DeckBrowserContent"], None
|
2020-02-16 19:29:01 +01:00
|
|
|
]
|
|
|
|
] = []
|
|
|
|
|
|
|
|
def append(
|
|
|
|
self,
|
|
|
|
cb: Callable[
|
2020-02-17 16:26:21 +01:00
|
|
|
["aqt.deckbrowser.DeckBrowser", "aqt.deckbrowser.DeckBrowserContent"], None
|
2020-02-16 19:29:01 +01:00
|
|
|
],
|
|
|
|
) -> None:
|
2020-02-17 16:26:21 +01:00
|
|
|
"""(deck_browser: aqt.deckbrowser.DeckBrowser, content: aqt.deckbrowser.DeckBrowserContent)"""
|
2020-02-16 19:29:01 +01:00
|
|
|
self._hooks.append(cb)
|
|
|
|
|
|
|
|
def remove(
|
|
|
|
self,
|
|
|
|
cb: Callable[
|
2020-02-17 16:26:21 +01:00
|
|
|
["aqt.deckbrowser.DeckBrowser", "aqt.deckbrowser.DeckBrowserContent"], None
|
2020-02-16 19:29:01 +01:00
|
|
|
],
|
|
|
|
) -> None:
|
|
|
|
if cb in self._hooks:
|
|
|
|
self._hooks.remove(cb)
|
|
|
|
|
2020-06-04 10:20:03 +02:00
|
|
|
def count(self) -> int:
|
|
|
|
return len(self._hooks)
|
|
|
|
|
2020-02-16 19:29:01 +01:00
|
|
|
def __call__(
|
|
|
|
self,
|
|
|
|
deck_browser: aqt.deckbrowser.DeckBrowser,
|
2020-02-17 16:26:21 +01:00
|
|
|
content: aqt.deckbrowser.DeckBrowserContent,
|
|
|
|
) -> None:
|
|
|
|
for hook in self._hooks:
|
2020-02-16 19:29:01 +01:00
|
|
|
try:
|
2020-02-17 16:26:21 +01:00
|
|
|
hook(deck_browser, content)
|
2020-02-16 19:29:01 +01:00
|
|
|
except:
|
|
|
|
# if the hook fails, remove it
|
2020-02-17 16:26:21 +01:00
|
|
|
self._hooks.remove(hook)
|
2020-02-16 19:29:01 +01:00
|
|
|
raise
|
|
|
|
|
|
|
|
|
2020-02-17 16:26:21 +01:00
|
|
|
deck_browser_will_render_content = _DeckBrowserWillRenderContentHook()
|
2020-02-16 19:29:01 +01:00
|
|
|
|
|
|
|
|
2020-01-15 08:45:35 +01:00
|
|
|
class _DeckBrowserWillShowOptionsMenuHook:
|
2020-01-15 03:16:54 +01:00
|
|
|
_hooks: List[Callable[[QMenu, int], None]] = []
|
|
|
|
|
|
|
|
def append(self, cb: Callable[[QMenu, int], None]) -> None:
|
|
|
|
"""(menu: QMenu, deck_id: int)"""
|
|
|
|
self._hooks.append(cb)
|
|
|
|
|
|
|
|
def remove(self, cb: Callable[[QMenu, int], None]) -> None:
|
2020-01-15 04:07:05 +01:00
|
|
|
if cb in self._hooks:
|
|
|
|
self._hooks.remove(cb)
|
2020-01-15 03:16:54 +01:00
|
|
|
|
2020-06-04 10:20:03 +02:00
|
|
|
def count(self) -> int:
|
|
|
|
return len(self._hooks)
|
|
|
|
|
2020-01-15 03:16:54 +01:00
|
|
|
def __call__(self, menu: QMenu, deck_id: int) -> None:
|
|
|
|
for hook in self._hooks:
|
|
|
|
try:
|
|
|
|
hook(menu, deck_id)
|
|
|
|
except:
|
|
|
|
# if the hook fails, remove it
|
|
|
|
self._hooks.remove(hook)
|
|
|
|
raise
|
|
|
|
# legacy support
|
|
|
|
runHook("showDeckOptions", menu, deck_id)
|
|
|
|
|
|
|
|
|
2020-01-15 08:45:35 +01:00
|
|
|
deck_browser_will_show_options_menu = _DeckBrowserWillShowOptionsMenuHook()
|
2020-01-15 03:16:54 +01:00
|
|
|
|
|
|
|
|
2020-05-22 21:24:05 +02:00
|
|
|
class _DeckConfDidAddConfigHook:
|
2020-05-23 11:14:52 +02:00
|
|
|
"""Allows modification of a newly created config group
|
|
|
|
|
|
|
|
This hook is called after the config group was created, but
|
|
|
|
before initializing the widget state.
|
|
|
|
|
|
|
|
`deck_conf` will point to the old config group, `new_conf_id` will
|
|
|
|
point to the newly created config group.
|
|
|
|
|
|
|
|
Config groups are created as clones of the current one.
|
|
|
|
"""
|
2020-05-22 21:24:05 +02:00
|
|
|
|
2020-08-11 22:56:58 +02:00
|
|
|
_hooks: List[
|
|
|
|
Callable[["aqt.deckconf.DeckConf", Deck, DeckConfig, str, int], None]
|
|
|
|
] = []
|
2020-05-22 21:24:05 +02:00
|
|
|
|
|
|
|
def append(
|
2020-08-11 22:56:58 +02:00
|
|
|
self, cb: Callable[["aqt.deckconf.DeckConf", Deck, DeckConfig, str, int], None]
|
2020-05-22 21:24:05 +02:00
|
|
|
) -> None:
|
2020-08-11 22:56:58 +02:00
|
|
|
"""(deck_conf: aqt.deckconf.DeckConf, deck: Deck, config: DeckConfig, new_name: str, new_conf_id: int)"""
|
2020-05-22 21:24:05 +02:00
|
|
|
self._hooks.append(cb)
|
|
|
|
|
|
|
|
def remove(
|
2020-08-11 22:56:58 +02:00
|
|
|
self, cb: Callable[["aqt.deckconf.DeckConf", Deck, DeckConfig, str, int], None]
|
2020-05-22 21:24:05 +02:00
|
|
|
) -> None:
|
|
|
|
if cb in self._hooks:
|
|
|
|
self._hooks.remove(cb)
|
|
|
|
|
2020-06-04 10:20:03 +02:00
|
|
|
def count(self) -> int:
|
|
|
|
return len(self._hooks)
|
|
|
|
|
2020-05-22 21:24:05 +02:00
|
|
|
def __call__(
|
|
|
|
self,
|
|
|
|
deck_conf: aqt.deckconf.DeckConf,
|
2020-08-11 22:56:58 +02:00
|
|
|
deck: Deck,
|
|
|
|
config: DeckConfig,
|
2020-05-22 21:24:05 +02:00
|
|
|
new_name: str,
|
2020-05-23 11:14:52 +02:00
|
|
|
new_conf_id: int,
|
2020-05-22 21:24:05 +02:00
|
|
|
) -> None:
|
|
|
|
for hook in self._hooks:
|
|
|
|
try:
|
2020-05-23 11:14:52 +02:00
|
|
|
hook(deck_conf, deck, config, new_name, new_conf_id)
|
2020-05-22 21:24:05 +02:00
|
|
|
except:
|
|
|
|
# if the hook fails, remove it
|
|
|
|
self._hooks.remove(hook)
|
|
|
|
raise
|
|
|
|
|
|
|
|
|
|
|
|
deck_conf_did_add_config = _DeckConfDidAddConfigHook()
|
|
|
|
|
|
|
|
|
2020-02-24 13:42:30 +01:00
|
|
|
class _DeckConfDidLoadConfigHook:
|
|
|
|
"""Called once widget state has been set from deck config"""
|
|
|
|
|
2020-08-11 22:56:58 +02:00
|
|
|
_hooks: List[Callable[["aqt.deckconf.DeckConf", Deck, DeckConfig], None]] = []
|
2020-02-24 13:42:30 +01:00
|
|
|
|
2020-08-11 22:56:58 +02:00
|
|
|
def append(
|
|
|
|
self, cb: Callable[["aqt.deckconf.DeckConf", Deck, DeckConfig], None]
|
|
|
|
) -> None:
|
|
|
|
"""(deck_conf: aqt.deckconf.DeckConf, deck: Deck, config: DeckConfig)"""
|
2020-02-24 13:42:30 +01:00
|
|
|
self._hooks.append(cb)
|
|
|
|
|
2020-08-11 22:56:58 +02:00
|
|
|
def remove(
|
|
|
|
self, cb: Callable[["aqt.deckconf.DeckConf", Deck, DeckConfig], None]
|
|
|
|
) -> None:
|
2020-02-24 13:42:30 +01:00
|
|
|
if cb in self._hooks:
|
|
|
|
self._hooks.remove(cb)
|
|
|
|
|
2020-06-04 10:20:03 +02:00
|
|
|
def count(self) -> int:
|
|
|
|
return len(self._hooks)
|
|
|
|
|
2020-02-24 15:47:48 +01:00
|
|
|
def __call__(
|
2020-08-11 22:56:58 +02:00
|
|
|
self, deck_conf: aqt.deckconf.DeckConf, deck: Deck, config: DeckConfig
|
2020-02-24 15:47:48 +01:00
|
|
|
) -> None:
|
2020-02-24 13:42:30 +01:00
|
|
|
for hook in self._hooks:
|
|
|
|
try:
|
2020-02-24 15:47:48 +01:00
|
|
|
hook(deck_conf, deck, config)
|
2020-02-24 13:42:30 +01:00
|
|
|
except:
|
|
|
|
# if the hook fails, remove it
|
|
|
|
self._hooks.remove(hook)
|
|
|
|
raise
|
|
|
|
|
|
|
|
|
|
|
|
deck_conf_did_load_config = _DeckConfDidLoadConfigHook()
|
|
|
|
|
|
|
|
|
2020-02-24 15:29:23 +01:00
|
|
|
class _DeckConfDidSetupUiFormHook:
|
|
|
|
"""Allows modifying or adding widgets in the deck options UI form"""
|
|
|
|
|
|
|
|
_hooks: List[Callable[["aqt.deckconf.DeckConf"], None]] = []
|
|
|
|
|
|
|
|
def append(self, cb: Callable[["aqt.deckconf.DeckConf"], None]) -> None:
|
|
|
|
"""(deck_conf: aqt.deckconf.DeckConf)"""
|
|
|
|
self._hooks.append(cb)
|
|
|
|
|
|
|
|
def remove(self, cb: Callable[["aqt.deckconf.DeckConf"], None]) -> None:
|
|
|
|
if cb in self._hooks:
|
|
|
|
self._hooks.remove(cb)
|
|
|
|
|
2020-06-04 10:20:03 +02:00
|
|
|
def count(self) -> int:
|
|
|
|
return len(self._hooks)
|
|
|
|
|
2020-02-24 15:29:23 +01:00
|
|
|
def __call__(self, deck_conf: aqt.deckconf.DeckConf) -> None:
|
|
|
|
for hook in self._hooks:
|
|
|
|
try:
|
|
|
|
hook(deck_conf)
|
|
|
|
except:
|
|
|
|
# if the hook fails, remove it
|
|
|
|
self._hooks.remove(hook)
|
|
|
|
raise
|
|
|
|
|
|
|
|
|
|
|
|
deck_conf_did_setup_ui_form = _DeckConfDidSetupUiFormHook()
|
|
|
|
|
|
|
|
|
2020-05-22 21:24:05 +02:00
|
|
|
class _DeckConfWillRemoveConfigHook:
|
|
|
|
"""Called before current config group is removed"""
|
|
|
|
|
2020-08-11 22:56:58 +02:00
|
|
|
_hooks: List[Callable[["aqt.deckconf.DeckConf", Deck, DeckConfig], None]] = []
|
2020-05-22 21:24:05 +02:00
|
|
|
|
2020-08-11 22:56:58 +02:00
|
|
|
def append(
|
|
|
|
self, cb: Callable[["aqt.deckconf.DeckConf", Deck, DeckConfig], None]
|
|
|
|
) -> None:
|
|
|
|
"""(deck_conf: aqt.deckconf.DeckConf, deck: Deck, config: DeckConfig)"""
|
2020-05-22 21:24:05 +02:00
|
|
|
self._hooks.append(cb)
|
|
|
|
|
2020-08-11 22:56:58 +02:00
|
|
|
def remove(
|
|
|
|
self, cb: Callable[["aqt.deckconf.DeckConf", Deck, DeckConfig], None]
|
|
|
|
) -> None:
|
2020-05-22 21:24:05 +02:00
|
|
|
if cb in self._hooks:
|
|
|
|
self._hooks.remove(cb)
|
|
|
|
|
2020-06-04 10:20:03 +02:00
|
|
|
def count(self) -> int:
|
|
|
|
return len(self._hooks)
|
|
|
|
|
2020-05-22 21:24:05 +02:00
|
|
|
def __call__(
|
2020-08-11 22:56:58 +02:00
|
|
|
self, deck_conf: aqt.deckconf.DeckConf, deck: Deck, config: DeckConfig
|
2020-05-22 21:24:05 +02:00
|
|
|
) -> None:
|
|
|
|
for hook in self._hooks:
|
|
|
|
try:
|
|
|
|
hook(deck_conf, deck, config)
|
|
|
|
except:
|
|
|
|
# if the hook fails, remove it
|
|
|
|
self._hooks.remove(hook)
|
|
|
|
raise
|
|
|
|
|
|
|
|
|
|
|
|
deck_conf_will_remove_config = _DeckConfWillRemoveConfigHook()
|
|
|
|
|
|
|
|
|
|
|
|
class _DeckConfWillRenameConfigHook:
|
|
|
|
"""Called before config group is renamed"""
|
|
|
|
|
2020-08-11 22:56:58 +02:00
|
|
|
_hooks: List[Callable[["aqt.deckconf.DeckConf", Deck, DeckConfig, str], None]] = []
|
2020-05-22 21:24:05 +02:00
|
|
|
|
|
|
|
def append(
|
2020-08-11 22:56:58 +02:00
|
|
|
self, cb: Callable[["aqt.deckconf.DeckConf", Deck, DeckConfig, str], None]
|
2020-05-22 21:24:05 +02:00
|
|
|
) -> None:
|
2020-08-11 22:56:58 +02:00
|
|
|
"""(deck_conf: aqt.deckconf.DeckConf, deck: Deck, config: DeckConfig, new_name: str)"""
|
2020-05-22 21:24:05 +02:00
|
|
|
self._hooks.append(cb)
|
|
|
|
|
|
|
|
def remove(
|
2020-08-11 22:56:58 +02:00
|
|
|
self, cb: Callable[["aqt.deckconf.DeckConf", Deck, DeckConfig, str], None]
|
2020-05-22 21:24:05 +02:00
|
|
|
) -> None:
|
|
|
|
if cb in self._hooks:
|
|
|
|
self._hooks.remove(cb)
|
|
|
|
|
2020-06-04 10:20:03 +02:00
|
|
|
def count(self) -> int:
|
|
|
|
return len(self._hooks)
|
|
|
|
|
2020-05-22 21:24:05 +02:00
|
|
|
def __call__(
|
2020-08-11 22:56:58 +02:00
|
|
|
self,
|
|
|
|
deck_conf: aqt.deckconf.DeckConf,
|
|
|
|
deck: Deck,
|
|
|
|
config: DeckConfig,
|
|
|
|
new_name: str,
|
2020-05-22 21:24:05 +02:00
|
|
|
) -> None:
|
|
|
|
for hook in self._hooks:
|
|
|
|
try:
|
|
|
|
hook(deck_conf, deck, config, new_name)
|
|
|
|
except:
|
|
|
|
# if the hook fails, remove it
|
|
|
|
self._hooks.remove(hook)
|
|
|
|
raise
|
|
|
|
|
|
|
|
|
|
|
|
deck_conf_will_rename_config = _DeckConfWillRenameConfigHook()
|
|
|
|
|
|
|
|
|
2020-02-24 13:42:30 +01:00
|
|
|
class _DeckConfWillSaveConfigHook:
|
|
|
|
"""Called before widget state is saved to config"""
|
|
|
|
|
2020-08-11 22:56:58 +02:00
|
|
|
_hooks: List[Callable[["aqt.deckconf.DeckConf", Deck, DeckConfig], None]] = []
|
2020-02-24 13:42:30 +01:00
|
|
|
|
2020-08-11 22:56:58 +02:00
|
|
|
def append(
|
|
|
|
self, cb: Callable[["aqt.deckconf.DeckConf", Deck, DeckConfig], None]
|
|
|
|
) -> None:
|
|
|
|
"""(deck_conf: aqt.deckconf.DeckConf, deck: Deck, config: DeckConfig)"""
|
2020-02-24 13:42:30 +01:00
|
|
|
self._hooks.append(cb)
|
|
|
|
|
2020-08-11 22:56:58 +02:00
|
|
|
def remove(
|
|
|
|
self, cb: Callable[["aqt.deckconf.DeckConf", Deck, DeckConfig], None]
|
|
|
|
) -> None:
|
2020-02-24 13:42:30 +01:00
|
|
|
if cb in self._hooks:
|
|
|
|
self._hooks.remove(cb)
|
|
|
|
|
2020-06-04 10:20:03 +02:00
|
|
|
def count(self) -> int:
|
|
|
|
return len(self._hooks)
|
|
|
|
|
2020-02-24 13:42:30 +01:00
|
|
|
def __call__(
|
2020-08-11 22:56:58 +02:00
|
|
|
self, deck_conf: aqt.deckconf.DeckConf, deck: Deck, config: DeckConfig
|
2020-02-24 13:42:30 +01:00
|
|
|
) -> None:
|
|
|
|
for hook in self._hooks:
|
|
|
|
try:
|
2020-02-24 15:47:48 +01:00
|
|
|
hook(deck_conf, deck, config)
|
2020-02-24 13:42:30 +01:00
|
|
|
except:
|
|
|
|
# if the hook fails, remove it
|
|
|
|
self._hooks.remove(hook)
|
|
|
|
raise
|
|
|
|
|
|
|
|
|
|
|
|
deck_conf_will_save_config = _DeckConfWillSaveConfigHook()
|
|
|
|
|
|
|
|
|
|
|
|
class _DeckConfWillShowHook:
|
|
|
|
"""Allows modifying the deck options dialog before it is shown"""
|
|
|
|
|
|
|
|
_hooks: List[Callable[["aqt.deckconf.DeckConf"], None]] = []
|
|
|
|
|
|
|
|
def append(self, cb: Callable[["aqt.deckconf.DeckConf"], None]) -> None:
|
|
|
|
"""(deck_conf: aqt.deckconf.DeckConf)"""
|
|
|
|
self._hooks.append(cb)
|
|
|
|
|
|
|
|
def remove(self, cb: Callable[["aqt.deckconf.DeckConf"], None]) -> None:
|
|
|
|
if cb in self._hooks:
|
|
|
|
self._hooks.remove(cb)
|
|
|
|
|
2020-06-04 10:20:03 +02:00
|
|
|
def count(self) -> int:
|
|
|
|
return len(self._hooks)
|
|
|
|
|
2020-02-24 13:42:30 +01:00
|
|
|
def __call__(self, deck_conf: aqt.deckconf.DeckConf) -> None:
|
|
|
|
for hook in self._hooks:
|
|
|
|
try:
|
|
|
|
hook(deck_conf)
|
|
|
|
except:
|
|
|
|
# if the hook fails, remove it
|
|
|
|
self._hooks.remove(hook)
|
|
|
|
raise
|
|
|
|
|
|
|
|
|
|
|
|
deck_conf_will_show = _DeckConfWillShowHook()
|
|
|
|
|
|
|
|
|
2020-01-15 08:45:35 +01:00
|
|
|
class _EditorDidFireTypingTimerHook:
|
|
|
|
_hooks: List[Callable[["anki.notes.Note"], None]] = []
|
2020-01-15 03:16:54 +01:00
|
|
|
|
2020-01-15 08:45:35 +01:00
|
|
|
def append(self, cb: Callable[["anki.notes.Note"], None]) -> None:
|
|
|
|
"""(note: anki.notes.Note)"""
|
2020-01-15 03:16:54 +01:00
|
|
|
self._hooks.append(cb)
|
|
|
|
|
2020-01-15 08:45:35 +01:00
|
|
|
def remove(self, cb: Callable[["anki.notes.Note"], None]) -> None:
|
2020-01-15 04:07:05 +01:00
|
|
|
if cb in self._hooks:
|
|
|
|
self._hooks.remove(cb)
|
2020-01-15 03:16:54 +01:00
|
|
|
|
2020-06-04 10:20:03 +02:00
|
|
|
def count(self) -> int:
|
|
|
|
return len(self._hooks)
|
|
|
|
|
2020-01-15 08:45:35 +01:00
|
|
|
def __call__(self, note: anki.notes.Note) -> None:
|
2020-01-15 03:16:54 +01:00
|
|
|
for hook in self._hooks:
|
|
|
|
try:
|
2020-01-15 08:45:35 +01:00
|
|
|
hook(note)
|
2020-01-15 03:16:54 +01:00
|
|
|
except:
|
|
|
|
# if the hook fails, remove it
|
|
|
|
self._hooks.remove(hook)
|
|
|
|
raise
|
|
|
|
# legacy support
|
2020-01-15 08:45:35 +01:00
|
|
|
runHook("editTimer", note)
|
2020-01-15 03:16:54 +01:00
|
|
|
|
|
|
|
|
2020-01-15 08:45:35 +01:00
|
|
|
editor_did_fire_typing_timer = _EditorDidFireTypingTimerHook()
|
2020-01-15 03:16:54 +01:00
|
|
|
|
|
|
|
|
2020-01-15 08:45:35 +01:00
|
|
|
class _EditorDidFocusFieldHook:
|
2020-01-15 03:16:54 +01:00
|
|
|
_hooks: List[Callable[["anki.notes.Note", int], None]] = []
|
|
|
|
|
|
|
|
def append(self, cb: Callable[["anki.notes.Note", int], None]) -> None:
|
|
|
|
"""(note: anki.notes.Note, current_field_idx: int)"""
|
|
|
|
self._hooks.append(cb)
|
|
|
|
|
|
|
|
def remove(self, cb: Callable[["anki.notes.Note", int], None]) -> None:
|
2020-01-15 04:07:05 +01:00
|
|
|
if cb in self._hooks:
|
|
|
|
self._hooks.remove(cb)
|
2020-01-15 03:16:54 +01:00
|
|
|
|
2020-06-04 10:20:03 +02:00
|
|
|
def count(self) -> int:
|
|
|
|
return len(self._hooks)
|
|
|
|
|
2020-01-15 03:16:54 +01:00
|
|
|
def __call__(self, note: anki.notes.Note, current_field_idx: int) -> None:
|
|
|
|
for hook in self._hooks:
|
|
|
|
try:
|
|
|
|
hook(note, current_field_idx)
|
|
|
|
except:
|
|
|
|
# if the hook fails, remove it
|
|
|
|
self._hooks.remove(hook)
|
|
|
|
raise
|
|
|
|
# legacy support
|
|
|
|
runHook("editFocusGained", note, current_field_idx)
|
|
|
|
|
|
|
|
|
2020-01-15 08:45:35 +01:00
|
|
|
editor_did_focus_field = _EditorDidFocusFieldHook()
|
2020-01-15 03:16:54 +01:00
|
|
|
|
|
|
|
|
2020-03-22 17:15:47 +01:00
|
|
|
class _EditorDidInitHook:
|
|
|
|
_hooks: List[Callable[["aqt.editor.Editor"], None]] = []
|
|
|
|
|
|
|
|
def append(self, cb: Callable[["aqt.editor.Editor"], None]) -> None:
|
|
|
|
"""(editor: aqt.editor.Editor)"""
|
|
|
|
self._hooks.append(cb)
|
|
|
|
|
|
|
|
def remove(self, cb: Callable[["aqt.editor.Editor"], None]) -> None:
|
|
|
|
if cb in self._hooks:
|
|
|
|
self._hooks.remove(cb)
|
|
|
|
|
2020-06-04 10:20:03 +02:00
|
|
|
def count(self) -> int:
|
|
|
|
return len(self._hooks)
|
|
|
|
|
2020-03-22 17:15:47 +01:00
|
|
|
def __call__(self, editor: aqt.editor.Editor) -> None:
|
|
|
|
for hook in self._hooks:
|
|
|
|
try:
|
|
|
|
hook(editor)
|
|
|
|
except:
|
|
|
|
# if the hook fails, remove it
|
|
|
|
self._hooks.remove(hook)
|
|
|
|
raise
|
|
|
|
|
|
|
|
|
|
|
|
editor_did_init = _EditorDidInitHook()
|
|
|
|
|
|
|
|
|
2020-01-15 08:45:35 +01:00
|
|
|
class _EditorDidInitButtonsHook:
|
2020-08-11 22:56:58 +02:00
|
|
|
_hooks: List[Callable[[List[str], "aqt.editor.Editor"], None]] = []
|
2020-01-15 03:16:54 +01:00
|
|
|
|
2020-08-11 22:56:58 +02:00
|
|
|
def append(self, cb: Callable[[List[str], "aqt.editor.Editor"], None]) -> None:
|
|
|
|
"""(buttons: List[str], editor: aqt.editor.Editor)"""
|
2020-01-15 03:16:54 +01:00
|
|
|
self._hooks.append(cb)
|
|
|
|
|
2020-08-11 22:56:58 +02:00
|
|
|
def remove(self, cb: Callable[[List[str], "aqt.editor.Editor"], None]) -> None:
|
2020-01-15 04:07:05 +01:00
|
|
|
if cb in self._hooks:
|
|
|
|
self._hooks.remove(cb)
|
2020-01-15 03:16:54 +01:00
|
|
|
|
2020-06-04 10:20:03 +02:00
|
|
|
def count(self) -> int:
|
|
|
|
return len(self._hooks)
|
|
|
|
|
2020-08-11 22:56:58 +02:00
|
|
|
def __call__(self, buttons: List[str], editor: aqt.editor.Editor) -> None:
|
2020-01-15 08:45:35 +01:00
|
|
|
for hook in self._hooks:
|
2020-01-15 03:16:54 +01:00
|
|
|
try:
|
2020-01-15 08:45:35 +01:00
|
|
|
hook(buttons, editor)
|
2020-01-15 03:16:54 +01:00
|
|
|
except:
|
|
|
|
# if the hook fails, remove it
|
2020-01-15 08:45:35 +01:00
|
|
|
self._hooks.remove(hook)
|
2020-01-15 03:16:54 +01:00
|
|
|
raise
|
|
|
|
|
|
|
|
|
2020-01-15 08:45:35 +01:00
|
|
|
editor_did_init_buttons = _EditorDidInitButtonsHook()
|
2020-01-15 03:16:54 +01:00
|
|
|
|
|
|
|
|
2020-01-15 08:45:35 +01:00
|
|
|
class _EditorDidInitShortcutsHook:
|
|
|
|
_hooks: List[Callable[[List[Tuple], "aqt.editor.Editor"], None]] = []
|
2020-01-15 03:16:54 +01:00
|
|
|
|
2020-01-15 08:45:35 +01:00
|
|
|
def append(self, cb: Callable[[List[Tuple], "aqt.editor.Editor"], None]) -> None:
|
|
|
|
"""(shortcuts: List[Tuple], editor: aqt.editor.Editor)"""
|
2020-01-15 03:16:54 +01:00
|
|
|
self._hooks.append(cb)
|
|
|
|
|
2020-01-15 08:45:35 +01:00
|
|
|
def remove(self, cb: Callable[[List[Tuple], "aqt.editor.Editor"], None]) -> None:
|
2020-01-15 04:07:05 +01:00
|
|
|
if cb in self._hooks:
|
|
|
|
self._hooks.remove(cb)
|
2020-01-15 03:16:54 +01:00
|
|
|
|
2020-06-04 10:20:03 +02:00
|
|
|
def count(self) -> int:
|
|
|
|
return len(self._hooks)
|
|
|
|
|
2020-01-15 08:45:35 +01:00
|
|
|
def __call__(self, shortcuts: List[Tuple], editor: aqt.editor.Editor) -> None:
|
|
|
|
for hook in self._hooks:
|
2020-01-15 03:16:54 +01:00
|
|
|
try:
|
2020-01-15 08:45:35 +01:00
|
|
|
hook(shortcuts, editor)
|
2020-01-15 03:16:54 +01:00
|
|
|
except:
|
|
|
|
# if the hook fails, remove it
|
2020-01-15 08:45:35 +01:00
|
|
|
self._hooks.remove(hook)
|
2020-01-15 03:16:54 +01:00
|
|
|
raise
|
|
|
|
# legacy support
|
2020-01-15 08:45:35 +01:00
|
|
|
runHook("setupEditorShortcuts", shortcuts, editor)
|
2020-01-15 03:16:54 +01:00
|
|
|
|
|
|
|
|
2020-01-15 08:45:35 +01:00
|
|
|
editor_did_init_shortcuts = _EditorDidInitShortcutsHook()
|
2020-01-15 03:16:54 +01:00
|
|
|
|
|
|
|
|
2020-01-15 08:45:35 +01:00
|
|
|
class _EditorDidLoadNoteHook:
|
2020-01-15 03:16:54 +01:00
|
|
|
_hooks: List[Callable[["aqt.editor.Editor"], None]] = []
|
|
|
|
|
|
|
|
def append(self, cb: Callable[["aqt.editor.Editor"], None]) -> None:
|
|
|
|
"""(editor: aqt.editor.Editor)"""
|
|
|
|
self._hooks.append(cb)
|
|
|
|
|
|
|
|
def remove(self, cb: Callable[["aqt.editor.Editor"], None]) -> None:
|
2020-01-15 04:07:05 +01:00
|
|
|
if cb in self._hooks:
|
|
|
|
self._hooks.remove(cb)
|
2020-01-15 03:16:54 +01:00
|
|
|
|
2020-06-04 10:20:03 +02:00
|
|
|
def count(self) -> int:
|
|
|
|
return len(self._hooks)
|
|
|
|
|
2020-01-15 03:16:54 +01:00
|
|
|
def __call__(self, editor: aqt.editor.Editor) -> None:
|
|
|
|
for hook in self._hooks:
|
|
|
|
try:
|
|
|
|
hook(editor)
|
|
|
|
except:
|
|
|
|
# if the hook fails, remove it
|
|
|
|
self._hooks.remove(hook)
|
|
|
|
raise
|
|
|
|
# legacy support
|
|
|
|
runHook("loadNote", editor)
|
|
|
|
|
|
|
|
|
2020-01-15 08:45:35 +01:00
|
|
|
editor_did_load_note = _EditorDidLoadNoteHook()
|
2020-01-15 03:16:54 +01:00
|
|
|
|
|
|
|
|
2020-01-15 08:45:35 +01:00
|
|
|
class _EditorDidUnfocusFieldFilter:
|
|
|
|
_hooks: List[Callable[[bool, "anki.notes.Note", int], bool]] = []
|
2020-01-15 03:16:54 +01:00
|
|
|
|
2020-01-15 08:45:35 +01:00
|
|
|
def append(self, cb: Callable[[bool, "anki.notes.Note", int], bool]) -> None:
|
|
|
|
"""(changed: bool, note: anki.notes.Note, current_field_idx: int)"""
|
2020-01-15 03:16:54 +01:00
|
|
|
self._hooks.append(cb)
|
|
|
|
|
2020-01-15 08:45:35 +01:00
|
|
|
def remove(self, cb: Callable[[bool, "anki.notes.Note", int], bool]) -> None:
|
2020-01-15 04:07:05 +01:00
|
|
|
if cb in self._hooks:
|
|
|
|
self._hooks.remove(cb)
|
2020-01-15 03:16:54 +01:00
|
|
|
|
2020-06-04 10:20:03 +02:00
|
|
|
def count(self) -> int:
|
|
|
|
return len(self._hooks)
|
|
|
|
|
2020-01-15 08:45:35 +01:00
|
|
|
def __call__(
|
|
|
|
self, changed: bool, note: anki.notes.Note, current_field_idx: int
|
|
|
|
) -> bool:
|
|
|
|
for filter in self._hooks:
|
2020-01-15 03:16:54 +01:00
|
|
|
try:
|
2020-01-15 08:45:35 +01:00
|
|
|
changed = filter(changed, note, current_field_idx)
|
2020-01-15 03:16:54 +01:00
|
|
|
except:
|
|
|
|
# if the hook fails, remove it
|
2020-01-15 08:45:35 +01:00
|
|
|
self._hooks.remove(filter)
|
2020-01-15 03:16:54 +01:00
|
|
|
raise
|
|
|
|
# legacy support
|
2020-02-20 17:05:27 +01:00
|
|
|
changed = runFilter("editFocusLost", changed, note, current_field_idx)
|
2020-01-15 08:45:35 +01:00
|
|
|
return changed
|
2020-01-15 03:16:54 +01:00
|
|
|
|
|
|
|
|
2020-01-15 08:45:35 +01:00
|
|
|
editor_did_unfocus_field = _EditorDidUnfocusFieldFilter()
|
2020-01-15 03:16:54 +01:00
|
|
|
|
|
|
|
|
2020-01-15 08:45:35 +01:00
|
|
|
class _EditorDidUpdateTagsHook:
|
2020-01-15 03:16:54 +01:00
|
|
|
_hooks: List[Callable[["anki.notes.Note"], None]] = []
|
|
|
|
|
|
|
|
def append(self, cb: Callable[["anki.notes.Note"], None]) -> None:
|
|
|
|
"""(note: anki.notes.Note)"""
|
|
|
|
self._hooks.append(cb)
|
|
|
|
|
|
|
|
def remove(self, cb: Callable[["anki.notes.Note"], None]) -> None:
|
2020-01-15 04:07:05 +01:00
|
|
|
if cb in self._hooks:
|
|
|
|
self._hooks.remove(cb)
|
2020-01-15 03:16:54 +01:00
|
|
|
|
2020-06-04 10:20:03 +02:00
|
|
|
def count(self) -> int:
|
|
|
|
return len(self._hooks)
|
|
|
|
|
2020-01-15 03:16:54 +01:00
|
|
|
def __call__(self, note: anki.notes.Note) -> None:
|
|
|
|
for hook in self._hooks:
|
|
|
|
try:
|
|
|
|
hook(note)
|
|
|
|
except:
|
|
|
|
# if the hook fails, remove it
|
|
|
|
self._hooks.remove(hook)
|
|
|
|
raise
|
|
|
|
# legacy support
|
|
|
|
runHook("tagsUpdated", note)
|
|
|
|
|
|
|
|
|
2020-01-15 08:45:35 +01:00
|
|
|
editor_did_update_tags = _EditorDidUpdateTagsHook()
|
2020-01-15 03:16:54 +01:00
|
|
|
|
|
|
|
|
2020-03-16 04:34:42 +01:00
|
|
|
class _EditorWebViewDidInitHook:
|
|
|
|
_hooks: List[Callable[["aqt.editor.EditorWebView"], None]] = []
|
|
|
|
|
|
|
|
def append(self, cb: Callable[["aqt.editor.EditorWebView"], None]) -> None:
|
|
|
|
"""(editor_web_view: aqt.editor.EditorWebView)"""
|
|
|
|
self._hooks.append(cb)
|
|
|
|
|
|
|
|
def remove(self, cb: Callable[["aqt.editor.EditorWebView"], None]) -> None:
|
|
|
|
if cb in self._hooks:
|
|
|
|
self._hooks.remove(cb)
|
|
|
|
|
2020-06-04 10:20:03 +02:00
|
|
|
def count(self) -> int:
|
|
|
|
return len(self._hooks)
|
|
|
|
|
2020-03-16 04:34:42 +01:00
|
|
|
def __call__(self, editor_web_view: aqt.editor.EditorWebView) -> None:
|
|
|
|
for hook in self._hooks:
|
|
|
|
try:
|
|
|
|
hook(editor_web_view)
|
|
|
|
except:
|
|
|
|
# if the hook fails, remove it
|
|
|
|
self._hooks.remove(hook)
|
|
|
|
raise
|
|
|
|
|
|
|
|
|
|
|
|
editor_web_view_did_init = _EditorWebViewDidInitHook()
|
|
|
|
|
|
|
|
|
2020-03-24 10:17:01 +01:00
|
|
|
class _EditorWillLoadNoteFilter:
|
|
|
|
"""Allows changing the javascript commands to load note before
|
|
|
|
executing it and do change in the QT editor."""
|
|
|
|
|
|
|
|
_hooks: List[Callable[[str, "anki.notes.Note", "aqt.editor.Editor"], str]] = []
|
|
|
|
|
|
|
|
def append(
|
|
|
|
self, cb: Callable[[str, "anki.notes.Note", "aqt.editor.Editor"], str]
|
|
|
|
) -> None:
|
|
|
|
"""(js: str, note: anki.notes.Note, editor: aqt.editor.Editor)"""
|
|
|
|
self._hooks.append(cb)
|
|
|
|
|
|
|
|
def remove(
|
|
|
|
self, cb: Callable[[str, "anki.notes.Note", "aqt.editor.Editor"], str]
|
|
|
|
) -> None:
|
|
|
|
if cb in self._hooks:
|
|
|
|
self._hooks.remove(cb)
|
|
|
|
|
2020-06-04 10:20:03 +02:00
|
|
|
def count(self) -> int:
|
|
|
|
return len(self._hooks)
|
|
|
|
|
2020-03-24 10:17:01 +01:00
|
|
|
def __call__(
|
|
|
|
self, js: str, note: anki.notes.Note, editor: aqt.editor.Editor
|
|
|
|
) -> str:
|
|
|
|
for filter in self._hooks:
|
|
|
|
try:
|
|
|
|
js = filter(js, note, editor)
|
|
|
|
except:
|
|
|
|
# if the hook fails, remove it
|
|
|
|
self._hooks.remove(filter)
|
|
|
|
raise
|
|
|
|
return js
|
|
|
|
|
|
|
|
|
|
|
|
editor_will_load_note = _EditorWillLoadNoteFilter()
|
|
|
|
|
|
|
|
|
2020-08-08 23:14:55 +02:00
|
|
|
class _EditorWillMungeHtmlFilter:
|
|
|
|
"""Allows manipulating the text that will be saved by the editor"""
|
|
|
|
|
|
|
|
_hooks: List[Callable[[str, "aqt.editor.Editor"], str]] = []
|
|
|
|
|
|
|
|
def append(self, cb: Callable[[str, "aqt.editor.Editor"], str]) -> None:
|
|
|
|
"""(txt: str, editor: aqt.editor.Editor)"""
|
|
|
|
self._hooks.append(cb)
|
|
|
|
|
|
|
|
def remove(self, cb: Callable[[str, "aqt.editor.Editor"], str]) -> None:
|
|
|
|
if cb in self._hooks:
|
|
|
|
self._hooks.remove(cb)
|
|
|
|
|
|
|
|
def count(self) -> int:
|
|
|
|
return len(self._hooks)
|
|
|
|
|
|
|
|
def __call__(self, txt: str, editor: aqt.editor.Editor) -> str:
|
|
|
|
for filter in self._hooks:
|
|
|
|
try:
|
|
|
|
txt = filter(txt, editor)
|
|
|
|
except:
|
|
|
|
# if the hook fails, remove it
|
|
|
|
self._hooks.remove(filter)
|
|
|
|
raise
|
|
|
|
return txt
|
|
|
|
|
|
|
|
|
|
|
|
editor_will_munge_html = _EditorWillMungeHtmlFilter()
|
|
|
|
|
|
|
|
|
2020-01-15 08:45:35 +01:00
|
|
|
class _EditorWillShowContextMenuHook:
|
|
|
|
_hooks: List[Callable[["aqt.editor.EditorWebView", QMenu], None]] = []
|
2020-01-15 03:16:54 +01:00
|
|
|
|
2020-01-15 08:45:35 +01:00
|
|
|
def append(self, cb: Callable[["aqt.editor.EditorWebView", QMenu], None]) -> None:
|
|
|
|
"""(editor_webview: aqt.editor.EditorWebView, menu: QMenu)"""
|
2020-01-15 03:16:54 +01:00
|
|
|
self._hooks.append(cb)
|
|
|
|
|
2020-01-15 08:45:35 +01:00
|
|
|
def remove(self, cb: Callable[["aqt.editor.EditorWebView", QMenu], None]) -> None:
|
2020-01-15 04:07:05 +01:00
|
|
|
if cb in self._hooks:
|
|
|
|
self._hooks.remove(cb)
|
2020-01-15 03:16:54 +01:00
|
|
|
|
2020-06-04 10:20:03 +02:00
|
|
|
def count(self) -> int:
|
|
|
|
return len(self._hooks)
|
|
|
|
|
2020-01-15 08:45:35 +01:00
|
|
|
def __call__(self, editor_webview: aqt.editor.EditorWebView, menu: QMenu) -> None:
|
2020-01-15 03:16:54 +01:00
|
|
|
for hook in self._hooks:
|
|
|
|
try:
|
2020-01-15 08:45:35 +01:00
|
|
|
hook(editor_webview, menu)
|
2020-01-15 03:16:54 +01:00
|
|
|
except:
|
|
|
|
# if the hook fails, remove it
|
|
|
|
self._hooks.remove(hook)
|
|
|
|
raise
|
|
|
|
# legacy support
|
2020-01-15 08:45:35 +01:00
|
|
|
runHook("EditorWebView.contextMenuEvent", editor_webview, menu)
|
|
|
|
|
|
|
|
|
|
|
|
editor_will_show_context_menu = _EditorWillShowContextMenuHook()
|
|
|
|
|
|
|
|
|
|
|
|
class _EditorWillUseFontForFieldFilter:
|
|
|
|
_hooks: List[Callable[[str], str]] = []
|
|
|
|
|
|
|
|
def append(self, cb: Callable[[str], str]) -> None:
|
|
|
|
"""(font: str)"""
|
|
|
|
self._hooks.append(cb)
|
|
|
|
|
|
|
|
def remove(self, cb: Callable[[str], str]) -> None:
|
|
|
|
if cb in self._hooks:
|
|
|
|
self._hooks.remove(cb)
|
|
|
|
|
2020-06-04 10:20:03 +02:00
|
|
|
def count(self) -> int:
|
|
|
|
return len(self._hooks)
|
|
|
|
|
2020-01-15 08:45:35 +01:00
|
|
|
def __call__(self, font: str) -> str:
|
|
|
|
for filter in self._hooks:
|
|
|
|
try:
|
|
|
|
font = filter(font)
|
|
|
|
except:
|
|
|
|
# if the hook fails, remove it
|
|
|
|
self._hooks.remove(filter)
|
|
|
|
raise
|
|
|
|
# legacy support
|
2020-02-20 17:05:27 +01:00
|
|
|
font = runFilter("mungeEditingFontName", font)
|
2020-01-15 08:45:35 +01:00
|
|
|
return font
|
2020-01-15 03:16:54 +01:00
|
|
|
|
|
|
|
|
2020-01-15 08:45:35 +01:00
|
|
|
editor_will_use_font_for_field = _EditorWillUseFontForFieldFilter()
|
2020-01-14 23:53:57 +01:00
|
|
|
|
|
|
|
|
2020-05-20 05:39:21 +02:00
|
|
|
class _EmptyCardsWillShowHook:
|
|
|
|
"""Allows changing the list of cards to delete."""
|
|
|
|
|
|
|
|
_hooks: List[Callable[["aqt.emptycards.EmptyCardsDialog"], None]] = []
|
|
|
|
|
|
|
|
def append(self, cb: Callable[["aqt.emptycards.EmptyCardsDialog"], None]) -> None:
|
|
|
|
"""(diag: aqt.emptycards.EmptyCardsDialog)"""
|
2020-02-24 10:46:36 +01:00
|
|
|
self._hooks.append(cb)
|
|
|
|
|
2020-05-20 05:39:21 +02:00
|
|
|
def remove(self, cb: Callable[["aqt.emptycards.EmptyCardsDialog"], None]) -> None:
|
2020-02-24 10:46:36 +01:00
|
|
|
if cb in self._hooks:
|
|
|
|
self._hooks.remove(cb)
|
|
|
|
|
2020-06-04 10:20:03 +02:00
|
|
|
def count(self) -> int:
|
|
|
|
return len(self._hooks)
|
|
|
|
|
2020-05-20 05:39:21 +02:00
|
|
|
def __call__(self, diag: aqt.emptycards.EmptyCardsDialog) -> None:
|
|
|
|
for hook in self._hooks:
|
2020-02-24 10:46:36 +01:00
|
|
|
try:
|
2020-05-20 05:39:21 +02:00
|
|
|
hook(diag)
|
2020-02-24 10:46:36 +01:00
|
|
|
except:
|
|
|
|
# if the hook fails, remove it
|
2020-05-20 05:39:21 +02:00
|
|
|
self._hooks.remove(hook)
|
2020-02-24 10:46:36 +01:00
|
|
|
raise
|
|
|
|
|
|
|
|
|
2020-05-20 05:39:21 +02:00
|
|
|
empty_cards_will_show = _EmptyCardsWillShowHook()
|
2020-02-24 10:46:36 +01:00
|
|
|
|
|
|
|
|
2020-05-28 13:30:22 +02:00
|
|
|
class _MainWindowDidInitHook:
|
|
|
|
"""Executed after the main window is fully initialized
|
|
|
|
|
|
|
|
A sample use case for this hook would be to delay actions until Anki objects
|
|
|
|
like the profile or collection are fully initialized. In contrast to
|
|
|
|
`profile_did_open`, this hook will only fire once per Anki session and
|
|
|
|
is thus suitable for single-shot subscribers.
|
|
|
|
"""
|
|
|
|
|
|
|
|
_hooks: List[Callable[[], None]] = []
|
|
|
|
|
|
|
|
def append(self, cb: Callable[[], None]) -> None:
|
|
|
|
"""()"""
|
|
|
|
self._hooks.append(cb)
|
|
|
|
|
|
|
|
def remove(self, cb: Callable[[], None]) -> None:
|
|
|
|
if cb in self._hooks:
|
|
|
|
self._hooks.remove(cb)
|
|
|
|
|
2020-06-04 10:20:03 +02:00
|
|
|
def count(self) -> int:
|
|
|
|
return len(self._hooks)
|
|
|
|
|
2020-05-28 13:30:22 +02:00
|
|
|
def __call__(self) -> None:
|
|
|
|
for hook in self._hooks:
|
|
|
|
try:
|
|
|
|
hook()
|
|
|
|
except:
|
|
|
|
# if the hook fails, remove it
|
|
|
|
self._hooks.remove(hook)
|
|
|
|
raise
|
|
|
|
|
|
|
|
|
|
|
|
main_window_did_init = _MainWindowDidInitHook()
|
|
|
|
|
|
|
|
|
2020-08-16 18:33:33 +02:00
|
|
|
class _MainWindowShouldRequireResetFilter:
|
2020-08-08 14:59:13 +02:00
|
|
|
"""Executed before the main window will require a reset
|
2020-08-16 18:33:33 +02:00
|
|
|
|
2020-08-08 14:59:13 +02:00
|
|
|
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.
|
2020-08-16 18:33:33 +02:00
|
|
|
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).
|
2020-08-08 14:59:13 +02:00
|
|
|
"""
|
|
|
|
|
2020-08-16 18:33:33 +02:00
|
|
|
_hooks: List[
|
|
|
|
Callable[[bool, "Union[aqt.main.ResetReason, str]", Optional[Any]], bool]
|
|
|
|
] = []
|
2020-08-08 14:59:13 +02:00
|
|
|
|
2020-08-16 18:33:33 +02:00
|
|
|
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])"""
|
2020-08-08 14:59:13 +02:00
|
|
|
self._hooks.append(cb)
|
|
|
|
|
2020-08-16 18:33:33 +02:00
|
|
|
def remove(
|
|
|
|
self,
|
|
|
|
cb: Callable[[bool, "Union[aqt.main.ResetReason, str]", Optional[Any]], bool],
|
|
|
|
) -> None:
|
2020-08-08 14:59:13 +02:00
|
|
|
if cb in self._hooks:
|
|
|
|
self._hooks.remove(cb)
|
|
|
|
|
|
|
|
def count(self) -> int:
|
|
|
|
return len(self._hooks)
|
|
|
|
|
2020-08-16 18:33:33 +02:00
|
|
|
def __call__(
|
|
|
|
self,
|
|
|
|
will_reset: bool,
|
|
|
|
reason: Union[aqt.main.ResetReason, str],
|
|
|
|
context: Optional[Any],
|
|
|
|
) -> bool:
|
2020-08-08 14:59:13 +02:00
|
|
|
for filter in self._hooks:
|
|
|
|
try:
|
2020-08-09 13:22:23 +02:00
|
|
|
will_reset = filter(will_reset, reason, context)
|
2020-08-08 14:59:13 +02:00
|
|
|
except:
|
|
|
|
# if the hook fails, remove it
|
|
|
|
self._hooks.remove(filter)
|
|
|
|
raise
|
|
|
|
return will_reset
|
|
|
|
|
|
|
|
|
2020-08-16 18:33:33 +02:00
|
|
|
main_window_should_require_reset = _MainWindowShouldRequireResetFilter()
|
2020-08-08 14:59:13 +02:00
|
|
|
|
|
|
|
|
2020-02-04 00:07:15 +01:00
|
|
|
class _MediaSyncDidProgressHook:
|
|
|
|
_hooks: List[Callable[["aqt.mediasync.LogEntryWithTime"], None]] = []
|
|
|
|
|
|
|
|
def append(self, cb: Callable[["aqt.mediasync.LogEntryWithTime"], None]) -> None:
|
|
|
|
"""(entry: aqt.mediasync.LogEntryWithTime)"""
|
|
|
|
self._hooks.append(cb)
|
|
|
|
|
|
|
|
def remove(self, cb: Callable[["aqt.mediasync.LogEntryWithTime"], None]) -> None:
|
|
|
|
if cb in self._hooks:
|
|
|
|
self._hooks.remove(cb)
|
|
|
|
|
2020-06-04 10:20:03 +02:00
|
|
|
def count(self) -> int:
|
|
|
|
return len(self._hooks)
|
|
|
|
|
2020-02-04 00:07:15 +01:00
|
|
|
def __call__(self, entry: aqt.mediasync.LogEntryWithTime) -> None:
|
|
|
|
for hook in self._hooks:
|
|
|
|
try:
|
|
|
|
hook(entry)
|
|
|
|
except:
|
|
|
|
# if the hook fails, remove it
|
|
|
|
self._hooks.remove(hook)
|
|
|
|
raise
|
|
|
|
|
|
|
|
|
|
|
|
media_sync_did_progress = _MediaSyncDidProgressHook()
|
|
|
|
|
|
|
|
|
2020-02-05 02:55:14 +01:00
|
|
|
class _MediaSyncDidStartOrStopHook:
|
|
|
|
_hooks: List[Callable[[bool], None]] = []
|
|
|
|
|
|
|
|
def append(self, cb: Callable[[bool], None]) -> None:
|
|
|
|
"""(running: bool)"""
|
|
|
|
self._hooks.append(cb)
|
|
|
|
|
|
|
|
def remove(self, cb: Callable[[bool], None]) -> None:
|
|
|
|
if cb in self._hooks:
|
|
|
|
self._hooks.remove(cb)
|
|
|
|
|
2020-06-04 10:20:03 +02:00
|
|
|
def count(self) -> int:
|
|
|
|
return len(self._hooks)
|
|
|
|
|
2020-02-05 02:55:14 +01:00
|
|
|
def __call__(self, running: bool) -> None:
|
|
|
|
for hook in self._hooks:
|
|
|
|
try:
|
|
|
|
hook(running)
|
|
|
|
except:
|
|
|
|
# if the hook fails, remove it
|
|
|
|
self._hooks.remove(hook)
|
|
|
|
raise
|
|
|
|
|
|
|
|
|
|
|
|
media_sync_did_start_or_stop = _MediaSyncDidStartOrStopHook()
|
|
|
|
|
|
|
|
|
2020-03-19 12:03:09 +01:00
|
|
|
class _ModelsAdvancedWillShowHook:
|
|
|
|
_hooks: List[Callable[[QDialog], None]] = []
|
|
|
|
|
|
|
|
def append(self, cb: Callable[[QDialog], None]) -> None:
|
|
|
|
"""(advanced: QDialog)"""
|
|
|
|
self._hooks.append(cb)
|
|
|
|
|
|
|
|
def remove(self, cb: Callable[[QDialog], None]) -> None:
|
|
|
|
if cb in self._hooks:
|
|
|
|
self._hooks.remove(cb)
|
|
|
|
|
2020-06-04 10:20:03 +02:00
|
|
|
def count(self) -> int:
|
|
|
|
return len(self._hooks)
|
|
|
|
|
2020-03-19 12:03:09 +01:00
|
|
|
def __call__(self, advanced: QDialog) -> None:
|
|
|
|
for hook in self._hooks:
|
|
|
|
try:
|
|
|
|
hook(advanced)
|
|
|
|
except:
|
|
|
|
# if the hook fails, remove it
|
|
|
|
self._hooks.remove(hook)
|
|
|
|
raise
|
|
|
|
|
|
|
|
|
|
|
|
models_advanced_will_show = _ModelsAdvancedWillShowHook()
|
|
|
|
|
|
|
|
|
2020-02-08 06:31:41 +01:00
|
|
|
class _OverviewDidRefreshHook:
|
|
|
|
"""Allow to update the overview window. E.g. add the deck name in the
|
|
|
|
title."""
|
|
|
|
|
|
|
|
_hooks: List[Callable[["aqt.overview.Overview"], None]] = []
|
|
|
|
|
|
|
|
def append(self, cb: Callable[["aqt.overview.Overview"], None]) -> None:
|
|
|
|
"""(overview: aqt.overview.Overview)"""
|
|
|
|
self._hooks.append(cb)
|
|
|
|
|
|
|
|
def remove(self, cb: Callable[["aqt.overview.Overview"], None]) -> None:
|
|
|
|
if cb in self._hooks:
|
|
|
|
self._hooks.remove(cb)
|
|
|
|
|
2020-06-04 10:20:03 +02:00
|
|
|
def count(self) -> int:
|
|
|
|
return len(self._hooks)
|
|
|
|
|
2020-02-08 06:31:41 +01:00
|
|
|
def __call__(self, overview: aqt.overview.Overview) -> None:
|
|
|
|
for hook in self._hooks:
|
|
|
|
try:
|
|
|
|
hook(overview)
|
|
|
|
except:
|
|
|
|
# if the hook fails, remove it
|
|
|
|
self._hooks.remove(hook)
|
|
|
|
raise
|
|
|
|
|
|
|
|
|
|
|
|
overview_did_refresh = _OverviewDidRefreshHook()
|
|
|
|
|
|
|
|
|
2020-02-17 16:49:21 +01:00
|
|
|
class _OverviewWillRenderContentHook:
|
|
|
|
"""Used to modify HTML content sections in the overview body
|
|
|
|
|
|
|
|
'content' contains the sections of HTML content the overview body
|
|
|
|
will be updated with.
|
|
|
|
|
|
|
|
When modifying the content of a particular section, please make sure your
|
|
|
|
changes only perform the minimum required edits to make your add-on work.
|
|
|
|
You should avoid overwriting or interfering with existing data as much
|
|
|
|
as possible, instead opting to append your own changes, e.g.:
|
|
|
|
|
|
|
|
def on_overview_will_render_content(overview, content):
|
|
|
|
content.table += "
|
|
|
|
<div>my html</div>"
|
|
|
|
"""
|
|
|
|
|
|
|
|
_hooks: List[
|
|
|
|
Callable[["aqt.overview.Overview", "aqt.overview.OverviewContent"], None]
|
|
|
|
] = []
|
|
|
|
|
|
|
|
def append(
|
|
|
|
self,
|
|
|
|
cb: Callable[["aqt.overview.Overview", "aqt.overview.OverviewContent"], None],
|
|
|
|
) -> None:
|
|
|
|
"""(overview: aqt.overview.Overview, content: aqt.overview.OverviewContent)"""
|
|
|
|
self._hooks.append(cb)
|
|
|
|
|
|
|
|
def remove(
|
|
|
|
self,
|
|
|
|
cb: Callable[["aqt.overview.Overview", "aqt.overview.OverviewContent"], None],
|
|
|
|
) -> None:
|
|
|
|
if cb in self._hooks:
|
|
|
|
self._hooks.remove(cb)
|
|
|
|
|
2020-06-04 10:20:03 +02:00
|
|
|
def count(self) -> int:
|
|
|
|
return len(self._hooks)
|
|
|
|
|
2020-02-17 16:49:21 +01:00
|
|
|
def __call__(
|
|
|
|
self, overview: aqt.overview.Overview, content: aqt.overview.OverviewContent
|
|
|
|
) -> None:
|
|
|
|
for hook in self._hooks:
|
|
|
|
try:
|
|
|
|
hook(overview, content)
|
|
|
|
except:
|
|
|
|
# if the hook fails, remove it
|
|
|
|
self._hooks.remove(hook)
|
|
|
|
raise
|
|
|
|
|
|
|
|
|
|
|
|
overview_will_render_content = _OverviewWillRenderContentHook()
|
|
|
|
|
|
|
|
|
2020-01-15 03:16:54 +01:00
|
|
|
class _ProfileDidOpenHook:
|
2020-05-28 13:30:22 +02:00
|
|
|
"""Executed whenever a user profile has been opened
|
|
|
|
|
|
|
|
Please note that this hook will also be called on profile switches, so if you
|
|
|
|
are looking to simply delay an add-on action in a single-shot manner,
|
|
|
|
`main_window_did_init` is likely the more suitable choice.
|
|
|
|
"""
|
|
|
|
|
2020-01-15 03:16:54 +01:00
|
|
|
_hooks: List[Callable[[], None]] = []
|
|
|
|
|
|
|
|
def append(self, cb: Callable[[], None]) -> None:
|
|
|
|
"""()"""
|
|
|
|
self._hooks.append(cb)
|
|
|
|
|
|
|
|
def remove(self, cb: Callable[[], None]) -> None:
|
2020-01-15 04:07:05 +01:00
|
|
|
if cb in self._hooks:
|
|
|
|
self._hooks.remove(cb)
|
2020-01-15 03:16:54 +01:00
|
|
|
|
2020-06-04 10:20:03 +02:00
|
|
|
def count(self) -> int:
|
|
|
|
return len(self._hooks)
|
|
|
|
|
2020-01-15 03:16:54 +01:00
|
|
|
def __call__(self) -> None:
|
|
|
|
for hook in self._hooks:
|
|
|
|
try:
|
|
|
|
hook()
|
|
|
|
except:
|
|
|
|
# if the hook fails, remove it
|
|
|
|
self._hooks.remove(hook)
|
|
|
|
raise
|
|
|
|
# legacy support
|
|
|
|
runHook("profileLoaded")
|
|
|
|
|
|
|
|
|
2020-01-15 07:53:24 +01:00
|
|
|
profile_did_open = _ProfileDidOpenHook()
|
2020-01-15 03:16:54 +01:00
|
|
|
|
|
|
|
|
|
|
|
class _ProfileWillCloseHook:
|
|
|
|
_hooks: List[Callable[[], None]] = []
|
|
|
|
|
|
|
|
def append(self, cb: Callable[[], None]) -> None:
|
|
|
|
"""()"""
|
|
|
|
self._hooks.append(cb)
|
|
|
|
|
|
|
|
def remove(self, cb: Callable[[], None]) -> None:
|
2020-01-15 04:07:05 +01:00
|
|
|
if cb in self._hooks:
|
|
|
|
self._hooks.remove(cb)
|
2020-01-15 03:16:54 +01:00
|
|
|
|
2020-06-04 10:20:03 +02:00
|
|
|
def count(self) -> int:
|
|
|
|
return len(self._hooks)
|
|
|
|
|
2020-01-15 03:16:54 +01:00
|
|
|
def __call__(self) -> None:
|
|
|
|
for hook in self._hooks:
|
|
|
|
try:
|
|
|
|
hook()
|
|
|
|
except:
|
|
|
|
# if the hook fails, remove it
|
|
|
|
self._hooks.remove(hook)
|
|
|
|
raise
|
|
|
|
# legacy support
|
|
|
|
runHook("unloadProfile")
|
|
|
|
|
|
|
|
|
2020-01-15 07:53:24 +01:00
|
|
|
profile_will_close = _ProfileWillCloseHook()
|
2020-01-15 03:16:54 +01:00
|
|
|
|
|
|
|
|
|
|
|
class _ReviewDidUndoHook:
|
|
|
|
_hooks: List[Callable[[int], None]] = []
|
|
|
|
|
|
|
|
def append(self, cb: Callable[[int], None]) -> None:
|
|
|
|
"""(card_id: int)"""
|
|
|
|
self._hooks.append(cb)
|
|
|
|
|
|
|
|
def remove(self, cb: Callable[[int], None]) -> None:
|
2020-01-15 04:07:05 +01:00
|
|
|
if cb in self._hooks:
|
|
|
|
self._hooks.remove(cb)
|
2020-01-15 03:16:54 +01:00
|
|
|
|
2020-06-04 10:20:03 +02:00
|
|
|
def count(self) -> int:
|
|
|
|
return len(self._hooks)
|
|
|
|
|
2020-01-15 03:16:54 +01:00
|
|
|
def __call__(self, card_id: int) -> None:
|
|
|
|
for hook in self._hooks:
|
|
|
|
try:
|
|
|
|
hook(card_id)
|
|
|
|
except:
|
|
|
|
# if the hook fails, remove it
|
|
|
|
self._hooks.remove(hook)
|
|
|
|
raise
|
|
|
|
# legacy support
|
|
|
|
runHook("revertedCard", card_id)
|
|
|
|
|
|
|
|
|
2020-01-15 07:53:24 +01:00
|
|
|
review_did_undo = _ReviewDidUndoHook()
|
2020-01-15 03:16:54 +01:00
|
|
|
|
|
|
|
|
2020-01-24 15:36:05 +01:00
|
|
|
class _ReviewerDidAnswerCardHook:
|
|
|
|
_hooks: List[Callable[["aqt.reviewer.Reviewer", Card, int], None]] = []
|
|
|
|
|
|
|
|
def append(self, cb: Callable[["aqt.reviewer.Reviewer", Card, int], None]) -> None:
|
|
|
|
"""(reviewer: aqt.reviewer.Reviewer, card: Card, ease: int)"""
|
|
|
|
self._hooks.append(cb)
|
|
|
|
|
|
|
|
def remove(self, cb: Callable[["aqt.reviewer.Reviewer", Card, int], None]) -> None:
|
|
|
|
if cb in self._hooks:
|
|
|
|
self._hooks.remove(cb)
|
|
|
|
|
2020-06-04 10:20:03 +02:00
|
|
|
def count(self) -> int:
|
|
|
|
return len(self._hooks)
|
|
|
|
|
2020-01-24 15:36:05 +01:00
|
|
|
def __call__(self, reviewer: aqt.reviewer.Reviewer, card: Card, ease: int) -> None:
|
|
|
|
for hook in self._hooks:
|
|
|
|
try:
|
|
|
|
hook(reviewer, card, ease)
|
|
|
|
except:
|
|
|
|
# if the hook fails, remove it
|
|
|
|
self._hooks.remove(hook)
|
|
|
|
raise
|
|
|
|
|
|
|
|
|
|
|
|
reviewer_did_answer_card = _ReviewerDidAnswerCardHook()
|
|
|
|
|
|
|
|
|
2020-01-15 08:45:35 +01:00
|
|
|
class _ReviewerDidShowAnswerHook:
|
2020-01-13 23:54:07 +01:00
|
|
|
_hooks: List[Callable[[Card], None]] = []
|
|
|
|
|
|
|
|
def append(self, cb: Callable[[Card], None]) -> None:
|
|
|
|
"""(card: Card)"""
|
|
|
|
self._hooks.append(cb)
|
|
|
|
|
|
|
|
def remove(self, cb: Callable[[Card], None]) -> None:
|
2020-01-15 04:07:05 +01:00
|
|
|
if cb in self._hooks:
|
|
|
|
self._hooks.remove(cb)
|
2020-01-13 23:54:07 +01:00
|
|
|
|
2020-06-04 10:20:03 +02:00
|
|
|
def count(self) -> int:
|
|
|
|
return len(self._hooks)
|
|
|
|
|
2020-01-13 23:54:07 +01:00
|
|
|
def __call__(self, card: Card) -> None:
|
|
|
|
for hook in self._hooks:
|
|
|
|
try:
|
|
|
|
hook(card)
|
|
|
|
except:
|
|
|
|
# if the hook fails, remove it
|
|
|
|
self._hooks.remove(hook)
|
|
|
|
raise
|
|
|
|
# legacy support
|
|
|
|
runHook("showAnswer")
|
|
|
|
|
|
|
|
|
2020-01-15 08:45:35 +01:00
|
|
|
reviewer_did_show_answer = _ReviewerDidShowAnswerHook()
|
2020-01-15 03:16:54 +01:00
|
|
|
|
|
|
|
|
2020-01-15 08:45:35 +01:00
|
|
|
class _ReviewerDidShowQuestionHook:
|
2020-01-13 23:54:07 +01:00
|
|
|
_hooks: List[Callable[[Card], None]] = []
|
|
|
|
|
|
|
|
def append(self, cb: Callable[[Card], None]) -> None:
|
|
|
|
"""(card: Card)"""
|
|
|
|
self._hooks.append(cb)
|
|
|
|
|
|
|
|
def remove(self, cb: Callable[[Card], None]) -> None:
|
2020-01-15 04:07:05 +01:00
|
|
|
if cb in self._hooks:
|
|
|
|
self._hooks.remove(cb)
|
2020-01-13 23:54:07 +01:00
|
|
|
|
2020-06-04 10:20:03 +02:00
|
|
|
def count(self) -> int:
|
|
|
|
return len(self._hooks)
|
|
|
|
|
2020-01-13 23:54:07 +01:00
|
|
|
def __call__(self, card: Card) -> None:
|
|
|
|
for hook in self._hooks:
|
|
|
|
try:
|
|
|
|
hook(card)
|
|
|
|
except:
|
|
|
|
# if the hook fails, remove it
|
|
|
|
self._hooks.remove(hook)
|
|
|
|
raise
|
|
|
|
# legacy support
|
|
|
|
runHook("showQuestion")
|
|
|
|
|
|
|
|
|
2020-01-15 08:45:35 +01:00
|
|
|
reviewer_did_show_question = _ReviewerDidShowQuestionHook()
|
2020-01-15 03:16:54 +01:00
|
|
|
|
|
|
|
|
2020-01-24 15:36:05 +01:00
|
|
|
class _ReviewerWillAnswerCardFilter:
|
|
|
|
"""Used to modify the ease at which a card is rated or to bypass
|
|
|
|
rating the card completely.
|
|
|
|
|
|
|
|
ease_tuple is a tuple consisting of a boolean expressing whether the reviewer
|
|
|
|
should continue with rating the card, and an integer expressing the ease at
|
|
|
|
which the card should be rated.
|
|
|
|
|
|
|
|
If your code just needs to be notified of the card rating event, you should use
|
|
|
|
the reviewer_did_answer_card hook instead."""
|
|
|
|
|
|
|
|
_hooks: List[
|
|
|
|
Callable[[Tuple[bool, int], "aqt.reviewer.Reviewer", Card], Tuple[bool, int]]
|
|
|
|
] = []
|
|
|
|
|
|
|
|
def append(
|
|
|
|
self,
|
|
|
|
cb: Callable[
|
|
|
|
[Tuple[bool, int], "aqt.reviewer.Reviewer", Card], Tuple[bool, int]
|
|
|
|
],
|
|
|
|
) -> None:
|
|
|
|
"""(ease_tuple: Tuple[bool, int], reviewer: aqt.reviewer.Reviewer, card: Card)"""
|
|
|
|
self._hooks.append(cb)
|
|
|
|
|
|
|
|
def remove(
|
|
|
|
self,
|
|
|
|
cb: Callable[
|
|
|
|
[Tuple[bool, int], "aqt.reviewer.Reviewer", Card], Tuple[bool, int]
|
|
|
|
],
|
|
|
|
) -> None:
|
|
|
|
if cb in self._hooks:
|
|
|
|
self._hooks.remove(cb)
|
|
|
|
|
2020-06-04 10:20:03 +02:00
|
|
|
def count(self) -> int:
|
|
|
|
return len(self._hooks)
|
|
|
|
|
2020-01-24 15:36:05 +01:00
|
|
|
def __call__(
|
|
|
|
self, ease_tuple: Tuple[bool, int], reviewer: aqt.reviewer.Reviewer, card: Card
|
|
|
|
) -> Tuple[bool, int]:
|
|
|
|
for filter in self._hooks:
|
|
|
|
try:
|
|
|
|
ease_tuple = filter(ease_tuple, reviewer, card)
|
|
|
|
except:
|
|
|
|
# if the hook fails, remove it
|
|
|
|
self._hooks.remove(filter)
|
|
|
|
raise
|
|
|
|
return ease_tuple
|
|
|
|
|
|
|
|
|
|
|
|
reviewer_will_answer_card = _ReviewerWillAnswerCardFilter()
|
|
|
|
|
|
|
|
|
2020-01-15 04:03:11 +01:00
|
|
|
class _ReviewerWillEndHook:
|
|
|
|
"""Called before Anki transitions from the review screen to another screen."""
|
|
|
|
|
|
|
|
_hooks: List[Callable[[], None]] = []
|
|
|
|
|
|
|
|
def append(self, cb: Callable[[], None]) -> None:
|
|
|
|
"""()"""
|
|
|
|
self._hooks.append(cb)
|
|
|
|
|
|
|
|
def remove(self, cb: Callable[[], None]) -> None:
|
2020-01-15 04:07:05 +01:00
|
|
|
if cb in self._hooks:
|
|
|
|
self._hooks.remove(cb)
|
2020-01-15 04:03:11 +01:00
|
|
|
|
2020-06-04 10:20:03 +02:00
|
|
|
def count(self) -> int:
|
|
|
|
return len(self._hooks)
|
|
|
|
|
2020-01-15 04:03:11 +01:00
|
|
|
def __call__(self) -> None:
|
|
|
|
for hook in self._hooks:
|
|
|
|
try:
|
|
|
|
hook()
|
|
|
|
except:
|
|
|
|
# if the hook fails, remove it
|
|
|
|
self._hooks.remove(hook)
|
|
|
|
raise
|
|
|
|
# legacy support
|
|
|
|
runHook("reviewCleanup")
|
|
|
|
|
|
|
|
|
2020-01-15 07:53:24 +01:00
|
|
|
reviewer_will_end = _ReviewerWillEndHook()
|
2020-01-15 04:03:11 +01:00
|
|
|
|
|
|
|
|
2020-08-18 16:37:45 +02:00
|
|
|
class _ReviewerWillInitAnswerButtonsFilter:
|
|
|
|
"""Used to modify list of answer buttons
|
|
|
|
|
2020-08-20 16:30:31 +02:00
|
|
|
buttons_tuple is a tuple of buttons, with each button represented by a
|
|
|
|
tuple containing an int for the button's ease and a string for the
|
|
|
|
button's label.
|
2020-08-18 16:37:45 +02:00
|
|
|
|
2020-08-20 16:30:31 +02:00
|
|
|
Return a tuple of the form ((int, str), ...), e.g.:
|
|
|
|
((1, "Label1"), (2, "Label2"), ...)
|
2020-08-18 16:37:45 +02:00
|
|
|
|
2020-08-20 16:30:31 +02:00
|
|
|
Note: import _ from anki.lang to support translation, using, e.g.,
|
2020-08-18 16:37:45 +02:00
|
|
|
((1, _("Label1")), ...)
|
|
|
|
"""
|
|
|
|
|
|
|
|
_hooks: List[
|
|
|
|
Callable[
|
2020-08-19 22:15:49 +02:00
|
|
|
["Tuple[Tuple[int, str], ...]", "aqt.reviewer.Reviewer", Card],
|
2020-08-18 16:37:45 +02:00
|
|
|
Tuple[Tuple[int, str], ...],
|
|
|
|
]
|
|
|
|
] = []
|
|
|
|
|
|
|
|
def append(
|
|
|
|
self,
|
|
|
|
cb: Callable[
|
2020-08-19 22:15:49 +02:00
|
|
|
["Tuple[Tuple[int, str], ...]", "aqt.reviewer.Reviewer", Card],
|
2020-08-18 16:37:45 +02:00
|
|
|
Tuple[Tuple[int, str], ...],
|
|
|
|
],
|
|
|
|
) -> None:
|
2020-08-19 22:15:49 +02:00
|
|
|
"""(buttons_tuple: Tuple[Tuple[int, str], ...], reviewer: aqt.reviewer.Reviewer, card: Card)"""
|
2020-08-18 16:37:45 +02:00
|
|
|
self._hooks.append(cb)
|
|
|
|
|
|
|
|
def remove(
|
|
|
|
self,
|
|
|
|
cb: Callable[
|
2020-08-19 22:15:49 +02:00
|
|
|
["Tuple[Tuple[int, str], ...]", "aqt.reviewer.Reviewer", Card],
|
2020-08-18 16:37:45 +02:00
|
|
|
Tuple[Tuple[int, str], ...],
|
|
|
|
],
|
|
|
|
) -> None:
|
|
|
|
if cb in self._hooks:
|
|
|
|
self._hooks.remove(cb)
|
|
|
|
|
|
|
|
def count(self) -> int:
|
|
|
|
return len(self._hooks)
|
|
|
|
|
|
|
|
def __call__(
|
|
|
|
self,
|
2020-08-19 22:15:49 +02:00
|
|
|
buttons_tuple: Tuple[Tuple[int, str], ...],
|
2020-08-18 16:37:45 +02:00
|
|
|
reviewer: aqt.reviewer.Reviewer,
|
|
|
|
card: Card,
|
|
|
|
) -> Tuple[Tuple[int, str], ...]:
|
|
|
|
for filter in self._hooks:
|
|
|
|
try:
|
|
|
|
buttons_tuple = filter(buttons_tuple, reviewer, card)
|
|
|
|
except:
|
|
|
|
# if the hook fails, remove it
|
|
|
|
self._hooks.remove(filter)
|
|
|
|
raise
|
|
|
|
return buttons_tuple
|
|
|
|
|
|
|
|
|
|
|
|
reviewer_will_init_answer_buttons = _ReviewerWillInitAnswerButtonsFilter()
|
|
|
|
|
|
|
|
|
2020-07-30 20:06:16 +02:00
|
|
|
class _ReviewerWillPlayAnswerSoundsHook:
|
2020-07-31 02:06:13 +02:00
|
|
|
"""Called before showing the answer/back side.
|
|
|
|
|
|
|
|
`tags` can be used to inspect and manipulate the sounds
|
|
|
|
that will be played (if any).
|
|
|
|
|
|
|
|
This won't be called when the user manually plays sounds
|
|
|
|
using `Replay Audio`.
|
|
|
|
|
2020-07-31 03:46:39 +02:00
|
|
|
Note that this hook is called even when the `Automatically play audio`
|
2020-07-31 02:06:13 +02:00
|
|
|
option is unchecked; This is so as to allow playing custom
|
|
|
|
sounds regardless of that option."""
|
|
|
|
|
2020-07-30 20:06:16 +02:00
|
|
|
_hooks: List[Callable[[Card, "List[anki.sound.AVTag]"], None]] = []
|
|
|
|
|
|
|
|
def append(self, cb: Callable[[Card, "List[anki.sound.AVTag]"], None]) -> None:
|
|
|
|
"""(card: Card, tags: List[anki.sound.AVTag])"""
|
|
|
|
self._hooks.append(cb)
|
|
|
|
|
|
|
|
def remove(self, cb: Callable[[Card, "List[anki.sound.AVTag]"], None]) -> None:
|
|
|
|
if cb in self._hooks:
|
|
|
|
self._hooks.remove(cb)
|
|
|
|
|
|
|
|
def count(self) -> int:
|
|
|
|
return len(self._hooks)
|
|
|
|
|
|
|
|
def __call__(self, card: Card, tags: List[anki.sound.AVTag]) -> None:
|
|
|
|
for hook in self._hooks:
|
|
|
|
try:
|
|
|
|
hook(card, tags)
|
|
|
|
except:
|
|
|
|
# if the hook fails, remove it
|
|
|
|
self._hooks.remove(hook)
|
|
|
|
raise
|
|
|
|
|
|
|
|
|
|
|
|
reviewer_will_play_answer_sounds = _ReviewerWillPlayAnswerSoundsHook()
|
|
|
|
|
|
|
|
|
|
|
|
class _ReviewerWillPlayQuestionSoundsHook:
|
2020-07-31 02:06:13 +02:00
|
|
|
"""Called before showing the question/front side.
|
|
|
|
|
|
|
|
`tags` can be used to inspect and manipulate the sounds
|
|
|
|
that will be played (if any).
|
|
|
|
|
|
|
|
This won't be called when the user manually plays sounds
|
|
|
|
using `Replay Audio`.
|
|
|
|
|
2020-07-31 03:46:39 +02:00
|
|
|
Note that this hook is called even when the `Automatically play audio`
|
2020-07-31 02:06:13 +02:00
|
|
|
option is unchecked; This is so as to allow playing custom
|
|
|
|
sounds regardless of that option."""
|
|
|
|
|
2020-07-30 20:06:16 +02:00
|
|
|
_hooks: List[Callable[[Card, "List[anki.sound.AVTag]"], None]] = []
|
|
|
|
|
|
|
|
def append(self, cb: Callable[[Card, "List[anki.sound.AVTag]"], None]) -> None:
|
|
|
|
"""(card: Card, tags: List[anki.sound.AVTag])"""
|
|
|
|
self._hooks.append(cb)
|
|
|
|
|
|
|
|
def remove(self, cb: Callable[[Card, "List[anki.sound.AVTag]"], None]) -> None:
|
|
|
|
if cb in self._hooks:
|
|
|
|
self._hooks.remove(cb)
|
|
|
|
|
|
|
|
def count(self) -> int:
|
|
|
|
return len(self._hooks)
|
|
|
|
|
|
|
|
def __call__(self, card: Card, tags: List[anki.sound.AVTag]) -> None:
|
|
|
|
for hook in self._hooks:
|
|
|
|
try:
|
|
|
|
hook(card, tags)
|
|
|
|
except:
|
|
|
|
# if the hook fails, remove it
|
|
|
|
self._hooks.remove(hook)
|
|
|
|
raise
|
|
|
|
|
|
|
|
|
|
|
|
reviewer_will_play_question_sounds = _ReviewerWillPlayQuestionSoundsHook()
|
|
|
|
|
|
|
|
|
2020-01-15 08:45:35 +01:00
|
|
|
class _ReviewerWillShowContextMenuHook:
|
|
|
|
_hooks: List[Callable[["aqt.reviewer.Reviewer", QMenu], None]] = []
|
|
|
|
|
|
|
|
def append(self, cb: Callable[["aqt.reviewer.Reviewer", QMenu], None]) -> None:
|
|
|
|
"""(reviewer: aqt.reviewer.Reviewer, menu: QMenu)"""
|
|
|
|
self._hooks.append(cb)
|
|
|
|
|
|
|
|
def remove(self, cb: Callable[["aqt.reviewer.Reviewer", QMenu], None]) -> None:
|
|
|
|
if cb in self._hooks:
|
|
|
|
self._hooks.remove(cb)
|
|
|
|
|
2020-06-04 10:20:03 +02:00
|
|
|
def count(self) -> int:
|
|
|
|
return len(self._hooks)
|
|
|
|
|
2020-01-15 08:45:35 +01:00
|
|
|
def __call__(self, reviewer: aqt.reviewer.Reviewer, menu: QMenu) -> None:
|
|
|
|
for hook in self._hooks:
|
|
|
|
try:
|
|
|
|
hook(reviewer, menu)
|
|
|
|
except:
|
|
|
|
# if the hook fails, remove it
|
|
|
|
self._hooks.remove(hook)
|
|
|
|
raise
|
|
|
|
# legacy support
|
|
|
|
runHook("Reviewer.contextMenuEvent", reviewer, menu)
|
|
|
|
|
|
|
|
|
|
|
|
reviewer_will_show_context_menu = _ReviewerWillShowContextMenuHook()
|
|
|
|
|
|
|
|
|
2020-05-22 02:47:14 +02:00
|
|
|
class _SidebarShouldRefreshDecksHook:
|
|
|
|
_hooks: List[Callable[[], None]] = []
|
|
|
|
|
|
|
|
def append(self, cb: Callable[[], None]) -> None:
|
|
|
|
"""()"""
|
|
|
|
self._hooks.append(cb)
|
|
|
|
|
|
|
|
def remove(self, cb: Callable[[], None]) -> None:
|
|
|
|
if cb in self._hooks:
|
|
|
|
self._hooks.remove(cb)
|
|
|
|
|
2020-06-04 10:20:03 +02:00
|
|
|
def count(self) -> int:
|
|
|
|
return len(self._hooks)
|
|
|
|
|
2020-05-22 02:47:14 +02:00
|
|
|
def __call__(self) -> None:
|
|
|
|
for hook in self._hooks:
|
|
|
|
try:
|
|
|
|
hook()
|
|
|
|
except:
|
|
|
|
# if the hook fails, remove it
|
|
|
|
self._hooks.remove(hook)
|
|
|
|
raise
|
|
|
|
|
|
|
|
|
|
|
|
sidebar_should_refresh_decks = _SidebarShouldRefreshDecksHook()
|
|
|
|
|
|
|
|
|
|
|
|
class _SidebarShouldRefreshNotetypesHook:
|
|
|
|
_hooks: List[Callable[[], None]] = []
|
|
|
|
|
|
|
|
def append(self, cb: Callable[[], None]) -> None:
|
|
|
|
"""()"""
|
|
|
|
self._hooks.append(cb)
|
|
|
|
|
|
|
|
def remove(self, cb: Callable[[], None]) -> None:
|
|
|
|
if cb in self._hooks:
|
|
|
|
self._hooks.remove(cb)
|
|
|
|
|
2020-06-04 10:20:03 +02:00
|
|
|
def count(self) -> int:
|
|
|
|
return len(self._hooks)
|
|
|
|
|
2020-05-22 02:47:14 +02:00
|
|
|
def __call__(self) -> None:
|
|
|
|
for hook in self._hooks:
|
|
|
|
try:
|
|
|
|
hook()
|
|
|
|
except:
|
|
|
|
# if the hook fails, remove it
|
|
|
|
self._hooks.remove(hook)
|
|
|
|
raise
|
|
|
|
|
|
|
|
|
|
|
|
sidebar_should_refresh_notetypes = _SidebarShouldRefreshNotetypesHook()
|
|
|
|
|
|
|
|
|
2020-01-15 03:16:54 +01:00
|
|
|
class _StateDidChangeHook:
|
|
|
|
_hooks: List[Callable[[str, str], None]] = []
|
|
|
|
|
|
|
|
def append(self, cb: Callable[[str, str], None]) -> None:
|
|
|
|
"""(new_state: str, old_state: str)"""
|
|
|
|
self._hooks.append(cb)
|
|
|
|
|
|
|
|
def remove(self, cb: Callable[[str, str], None]) -> None:
|
2020-01-15 04:07:05 +01:00
|
|
|
if cb in self._hooks:
|
|
|
|
self._hooks.remove(cb)
|
2020-01-15 03:16:54 +01:00
|
|
|
|
2020-06-04 10:20:03 +02:00
|
|
|
def count(self) -> int:
|
|
|
|
return len(self._hooks)
|
|
|
|
|
2020-01-15 03:16:54 +01:00
|
|
|
def __call__(self, new_state: str, old_state: str) -> None:
|
|
|
|
for hook in self._hooks:
|
|
|
|
try:
|
|
|
|
hook(new_state, old_state)
|
|
|
|
except:
|
|
|
|
# if the hook fails, remove it
|
|
|
|
self._hooks.remove(hook)
|
|
|
|
raise
|
|
|
|
# legacy support
|
|
|
|
runHook("afterStateChange", new_state, old_state)
|
|
|
|
|
|
|
|
|
2020-01-15 07:53:24 +01:00
|
|
|
state_did_change = _StateDidChangeHook()
|
2020-01-15 03:16:54 +01:00
|
|
|
|
|
|
|
|
|
|
|
class _StateDidResetHook:
|
|
|
|
"""Called when the interface needs to be redisplayed after non-trivial changes have been made."""
|
|
|
|
|
|
|
|
_hooks: List[Callable[[], None]] = []
|
|
|
|
|
|
|
|
def append(self, cb: Callable[[], None]) -> None:
|
|
|
|
"""()"""
|
|
|
|
self._hooks.append(cb)
|
|
|
|
|
|
|
|
def remove(self, cb: Callable[[], None]) -> None:
|
2020-01-15 04:07:05 +01:00
|
|
|
if cb in self._hooks:
|
|
|
|
self._hooks.remove(cb)
|
2020-01-15 03:16:54 +01:00
|
|
|
|
2020-06-04 10:20:03 +02:00
|
|
|
def count(self) -> int:
|
|
|
|
return len(self._hooks)
|
|
|
|
|
2020-01-15 03:16:54 +01:00
|
|
|
def __call__(self) -> None:
|
|
|
|
for hook in self._hooks:
|
|
|
|
try:
|
|
|
|
hook()
|
|
|
|
except:
|
|
|
|
# if the hook fails, remove it
|
|
|
|
self._hooks.remove(hook)
|
|
|
|
raise
|
|
|
|
# legacy support
|
|
|
|
runHook("reset")
|
|
|
|
|
|
|
|
|
2020-01-15 07:53:24 +01:00
|
|
|
state_did_reset = _StateDidResetHook()
|
2020-01-15 03:16:54 +01:00
|
|
|
|
|
|
|
|
|
|
|
class _StateDidRevertHook:
|
2020-01-15 03:46:53 +01:00
|
|
|
"""Called when user used the undo option to restore to an earlier database state."""
|
|
|
|
|
2020-01-15 03:16:54 +01:00
|
|
|
_hooks: List[Callable[[str], None]] = []
|
|
|
|
|
|
|
|
def append(self, cb: Callable[[str], None]) -> None:
|
|
|
|
"""(action: str)"""
|
|
|
|
self._hooks.append(cb)
|
|
|
|
|
|
|
|
def remove(self, cb: Callable[[str], None]) -> None:
|
2020-01-15 04:07:05 +01:00
|
|
|
if cb in self._hooks:
|
|
|
|
self._hooks.remove(cb)
|
2020-01-15 03:16:54 +01:00
|
|
|
|
2020-06-04 10:20:03 +02:00
|
|
|
def count(self) -> int:
|
|
|
|
return len(self._hooks)
|
|
|
|
|
2020-01-15 03:16:54 +01:00
|
|
|
def __call__(self, action: str) -> None:
|
|
|
|
for hook in self._hooks:
|
|
|
|
try:
|
|
|
|
hook(action)
|
|
|
|
except:
|
|
|
|
# if the hook fails, remove it
|
|
|
|
self._hooks.remove(hook)
|
|
|
|
raise
|
|
|
|
# legacy support
|
|
|
|
runHook("revertedState", action)
|
|
|
|
|
|
|
|
|
2020-01-15 07:53:24 +01:00
|
|
|
state_did_revert = _StateDidRevertHook()
|
2020-01-15 03:16:54 +01:00
|
|
|
|
|
|
|
|
|
|
|
class _StateShortcutsWillChangeHook:
|
2020-01-15 03:46:53 +01:00
|
|
|
_hooks: List[Callable[[str, List[Tuple[str, Callable]]], None]] = []
|
2020-01-15 03:16:54 +01:00
|
|
|
|
2020-01-15 03:46:53 +01:00
|
|
|
def append(self, cb: Callable[[str, List[Tuple[str, Callable]]], None]) -> None:
|
|
|
|
"""(state: str, shortcuts: List[Tuple[str, Callable]])"""
|
2020-01-15 03:16:54 +01:00
|
|
|
self._hooks.append(cb)
|
|
|
|
|
2020-01-15 03:46:53 +01:00
|
|
|
def remove(self, cb: Callable[[str, List[Tuple[str, Callable]]], None]) -> None:
|
2020-01-15 04:07:05 +01:00
|
|
|
if cb in self._hooks:
|
|
|
|
self._hooks.remove(cb)
|
2020-01-15 03:16:54 +01:00
|
|
|
|
2020-06-04 10:20:03 +02:00
|
|
|
def count(self) -> int:
|
|
|
|
return len(self._hooks)
|
|
|
|
|
2020-01-15 03:46:53 +01:00
|
|
|
def __call__(self, state: str, shortcuts: List[Tuple[str, Callable]]) -> None:
|
2020-01-15 03:16:54 +01:00
|
|
|
for hook in self._hooks:
|
|
|
|
try:
|
|
|
|
hook(state, shortcuts)
|
|
|
|
except:
|
|
|
|
# if the hook fails, remove it
|
|
|
|
self._hooks.remove(hook)
|
|
|
|
raise
|
|
|
|
|
|
|
|
|
2020-01-15 07:53:24 +01:00
|
|
|
state_shortcuts_will_change = _StateShortcutsWillChangeHook()
|
2020-01-15 03:16:54 +01:00
|
|
|
|
|
|
|
|
|
|
|
class _StateWillChangeHook:
|
|
|
|
_hooks: List[Callable[[str, str], None]] = []
|
|
|
|
|
|
|
|
def append(self, cb: Callable[[str, str], None]) -> None:
|
|
|
|
"""(new_state: str, old_state: str)"""
|
|
|
|
self._hooks.append(cb)
|
|
|
|
|
|
|
|
def remove(self, cb: Callable[[str, str], None]) -> None:
|
2020-01-15 04:07:05 +01:00
|
|
|
if cb in self._hooks:
|
|
|
|
self._hooks.remove(cb)
|
2020-01-15 03:16:54 +01:00
|
|
|
|
2020-06-04 10:20:03 +02:00
|
|
|
def count(self) -> int:
|
|
|
|
return len(self._hooks)
|
|
|
|
|
2020-01-15 03:16:54 +01:00
|
|
|
def __call__(self, new_state: str, old_state: str) -> None:
|
|
|
|
for hook in self._hooks:
|
|
|
|
try:
|
|
|
|
hook(new_state, old_state)
|
|
|
|
except:
|
|
|
|
# if the hook fails, remove it
|
|
|
|
self._hooks.remove(hook)
|
|
|
|
raise
|
|
|
|
# legacy support
|
|
|
|
runHook("beforeStateChange", new_state, old_state)
|
|
|
|
|
|
|
|
|
2020-01-15 07:53:24 +01:00
|
|
|
state_will_change = _StateWillChangeHook()
|
2020-01-15 03:16:54 +01:00
|
|
|
|
|
|
|
|
2020-07-16 21:48:46 +02:00
|
|
|
class _StatsDialogOldWillShowHook:
|
|
|
|
"""Allows changing the old stats dialog before it is shown."""
|
|
|
|
|
2020-07-17 03:08:09 +02:00
|
|
|
_hooks: List[Callable[["aqt.stats.DeckStats"], None]] = []
|
2020-07-16 21:48:46 +02:00
|
|
|
|
2020-07-17 03:08:09 +02:00
|
|
|
def append(self, cb: Callable[["aqt.stats.DeckStats"], None]) -> None:
|
|
|
|
"""(dialog: aqt.stats.DeckStats)"""
|
2020-07-16 21:48:46 +02:00
|
|
|
self._hooks.append(cb)
|
|
|
|
|
2020-07-17 03:08:09 +02:00
|
|
|
def remove(self, cb: Callable[["aqt.stats.DeckStats"], None]) -> None:
|
2020-07-16 21:48:46 +02:00
|
|
|
if cb in self._hooks:
|
|
|
|
self._hooks.remove(cb)
|
|
|
|
|
|
|
|
def count(self) -> int:
|
|
|
|
return len(self._hooks)
|
|
|
|
|
2020-07-17 03:08:09 +02:00
|
|
|
def __call__(self, dialog: aqt.stats.DeckStats) -> None:
|
2020-07-16 21:48:46 +02:00
|
|
|
for hook in self._hooks:
|
|
|
|
try:
|
|
|
|
hook(dialog)
|
|
|
|
except:
|
|
|
|
# if the hook fails, remove it
|
|
|
|
self._hooks.remove(hook)
|
|
|
|
raise
|
|
|
|
|
|
|
|
|
|
|
|
stats_dialog_old_will_show = _StatsDialogOldWillShowHook()
|
|
|
|
|
|
|
|
|
|
|
|
class _StatsDialogWillShowHook:
|
|
|
|
"""Allows changing the stats dialog before it is shown."""
|
|
|
|
|
|
|
|
_hooks: List[Callable[["aqt.stats.NewDeckStats"], None]] = []
|
|
|
|
|
|
|
|
def append(self, cb: Callable[["aqt.stats.NewDeckStats"], None]) -> None:
|
|
|
|
"""(dialog: aqt.stats.NewDeckStats)"""
|
|
|
|
self._hooks.append(cb)
|
|
|
|
|
|
|
|
def remove(self, cb: Callable[["aqt.stats.NewDeckStats"], None]) -> None:
|
|
|
|
if cb in self._hooks:
|
|
|
|
self._hooks.remove(cb)
|
|
|
|
|
|
|
|
def count(self) -> int:
|
|
|
|
return len(self._hooks)
|
|
|
|
|
|
|
|
def __call__(self, dialog: aqt.stats.NewDeckStats) -> None:
|
|
|
|
for hook in self._hooks:
|
|
|
|
try:
|
|
|
|
hook(dialog)
|
|
|
|
except:
|
|
|
|
# if the hook fails, remove it
|
|
|
|
self._hooks.remove(hook)
|
|
|
|
raise
|
|
|
|
|
|
|
|
|
|
|
|
stats_dialog_will_show = _StatsDialogWillShowHook()
|
|
|
|
|
|
|
|
|
2020-01-15 08:18:11 +01:00
|
|
|
class _StyleDidInitFilter:
|
2020-01-15 03:46:53 +01:00
|
|
|
_hooks: List[Callable[[str], str]] = []
|
|
|
|
|
|
|
|
def append(self, cb: Callable[[str], str]) -> None:
|
|
|
|
"""(style: str)"""
|
|
|
|
self._hooks.append(cb)
|
|
|
|
|
|
|
|
def remove(self, cb: Callable[[str], str]) -> None:
|
2020-01-15 04:07:05 +01:00
|
|
|
if cb in self._hooks:
|
|
|
|
self._hooks.remove(cb)
|
2020-01-15 03:46:53 +01:00
|
|
|
|
2020-06-04 10:20:03 +02:00
|
|
|
def count(self) -> int:
|
|
|
|
return len(self._hooks)
|
|
|
|
|
2020-01-15 03:46:53 +01:00
|
|
|
def __call__(self, style: str) -> str:
|
|
|
|
for filter in self._hooks:
|
|
|
|
try:
|
|
|
|
style = filter(style)
|
|
|
|
except:
|
|
|
|
# if the hook fails, remove it
|
|
|
|
self._hooks.remove(filter)
|
|
|
|
raise
|
|
|
|
# legacy support
|
2020-02-20 17:05:27 +01:00
|
|
|
style = runFilter("setupStyle", style)
|
2020-01-15 03:46:53 +01:00
|
|
|
return style
|
|
|
|
|
|
|
|
|
2020-01-15 08:18:11 +01:00
|
|
|
style_did_init = _StyleDidInitFilter()
|
2020-01-15 03:46:53 +01:00
|
|
|
|
|
|
|
|
2020-04-01 09:13:08 +02:00
|
|
|
class _TagEditorDidProcessKeyHook:
|
2020-03-31 15:00:26 +02:00
|
|
|
_hooks: List[Callable[[TagEdit, QEvent], None]] = []
|
|
|
|
|
|
|
|
def append(self, cb: Callable[[TagEdit, QEvent], None]) -> None:
|
|
|
|
"""(tag_edit: TagEdit, evt: QEvent)"""
|
|
|
|
self._hooks.append(cb)
|
|
|
|
|
|
|
|
def remove(self, cb: Callable[[TagEdit, QEvent], None]) -> None:
|
|
|
|
if cb in self._hooks:
|
|
|
|
self._hooks.remove(cb)
|
|
|
|
|
2020-06-04 10:20:03 +02:00
|
|
|
def count(self) -> int:
|
|
|
|
return len(self._hooks)
|
|
|
|
|
2020-03-31 15:00:26 +02:00
|
|
|
def __call__(self, tag_edit: TagEdit, evt: QEvent) -> None:
|
|
|
|
for hook in self._hooks:
|
|
|
|
try:
|
|
|
|
hook(tag_edit, evt)
|
|
|
|
except:
|
|
|
|
# if the hook fails, remove it
|
|
|
|
self._hooks.remove(hook)
|
|
|
|
raise
|
|
|
|
|
|
|
|
|
2020-04-01 09:13:08 +02:00
|
|
|
tag_editor_did_process_key = _TagEditorDidProcessKeyHook()
|
2020-03-31 15:00:26 +02:00
|
|
|
|
|
|
|
|
2020-02-15 23:21:23 +01:00
|
|
|
class _TopToolbarDidInitLinksHook:
|
2020-02-20 16:23:33 +01:00
|
|
|
"""Used to modify or add links in the top toolbar of Anki's main window
|
|
|
|
|
|
|
|
'links' is a list of HTML link elements. Add-ons can generate their own links
|
|
|
|
by using aqt.toolbar.Toolbar.create_link. Links created in that way can then be
|
|
|
|
appended to the link list, e.g.:
|
2020-02-15 23:21:23 +01:00
|
|
|
|
2020-02-20 16:23:33 +01:00
|
|
|
def on_top_toolbar_did_init_links(links, toolbar):
|
|
|
|
my_link = toolbar.create_link(...)
|
|
|
|
links.append(my_link)
|
|
|
|
"""
|
|
|
|
|
|
|
|
_hooks: List[Callable[[List[str], "aqt.toolbar.Toolbar"], None]] = []
|
|
|
|
|
|
|
|
def append(self, cb: Callable[[List[str], "aqt.toolbar.Toolbar"], None]) -> None:
|
|
|
|
"""(links: List[str], top_toolbar: aqt.toolbar.Toolbar)"""
|
2020-02-15 23:21:23 +01:00
|
|
|
self._hooks.append(cb)
|
|
|
|
|
2020-02-20 16:23:33 +01:00
|
|
|
def remove(self, cb: Callable[[List[str], "aqt.toolbar.Toolbar"], None]) -> None:
|
2020-02-15 23:21:23 +01:00
|
|
|
if cb in self._hooks:
|
|
|
|
self._hooks.remove(cb)
|
|
|
|
|
2020-06-04 10:20:03 +02:00
|
|
|
def count(self) -> int:
|
|
|
|
return len(self._hooks)
|
|
|
|
|
2020-02-20 16:23:33 +01:00
|
|
|
def __call__(self, links: List[str], top_toolbar: aqt.toolbar.Toolbar) -> None:
|
2020-02-15 23:21:23 +01:00
|
|
|
for hook in self._hooks:
|
|
|
|
try:
|
|
|
|
hook(links, top_toolbar)
|
|
|
|
except:
|
|
|
|
# if the hook fails, remove it
|
|
|
|
self._hooks.remove(hook)
|
|
|
|
raise
|
|
|
|
|
|
|
|
|
|
|
|
top_toolbar_did_init_links = _TopToolbarDidInitLinksHook()
|
|
|
|
|
|
|
|
|
2020-07-10 17:38:40 +02:00
|
|
|
class _TopToolbarDidRedrawHook:
|
|
|
|
"""Executed when the top toolbar is redrawn"""
|
|
|
|
|
|
|
|
_hooks: List[Callable[["aqt.toolbar.Toolbar"], None]] = []
|
|
|
|
|
|
|
|
def append(self, cb: Callable[["aqt.toolbar.Toolbar"], None]) -> None:
|
|
|
|
"""(top_toolbar: aqt.toolbar.Toolbar)"""
|
|
|
|
self._hooks.append(cb)
|
|
|
|
|
|
|
|
def remove(self, cb: Callable[["aqt.toolbar.Toolbar"], None]) -> None:
|
|
|
|
if cb in self._hooks:
|
|
|
|
self._hooks.remove(cb)
|
|
|
|
|
|
|
|
def count(self) -> int:
|
|
|
|
return len(self._hooks)
|
|
|
|
|
|
|
|
def __call__(self, top_toolbar: aqt.toolbar.Toolbar) -> None:
|
|
|
|
for hook in self._hooks:
|
|
|
|
try:
|
|
|
|
hook(top_toolbar)
|
|
|
|
except:
|
|
|
|
# if the hook fails, remove it
|
|
|
|
self._hooks.remove(hook)
|
|
|
|
raise
|
|
|
|
|
|
|
|
|
|
|
|
top_toolbar_did_redraw = _TopToolbarDidRedrawHook()
|
|
|
|
|
|
|
|
|
2020-01-15 03:16:54 +01:00
|
|
|
class _UndoStateDidChangeHook:
|
|
|
|
_hooks: List[Callable[[bool], None]] = []
|
|
|
|
|
|
|
|
def append(self, cb: Callable[[bool], None]) -> None:
|
|
|
|
"""(can_undo: bool)"""
|
|
|
|
self._hooks.append(cb)
|
|
|
|
|
|
|
|
def remove(self, cb: Callable[[bool], None]) -> None:
|
2020-01-15 04:07:05 +01:00
|
|
|
if cb in self._hooks:
|
|
|
|
self._hooks.remove(cb)
|
2020-01-15 03:16:54 +01:00
|
|
|
|
2020-06-04 10:20:03 +02:00
|
|
|
def count(self) -> int:
|
|
|
|
return len(self._hooks)
|
|
|
|
|
2020-01-15 03:16:54 +01:00
|
|
|
def __call__(self, can_undo: bool) -> None:
|
|
|
|
for hook in self._hooks:
|
|
|
|
try:
|
|
|
|
hook(can_undo)
|
|
|
|
except:
|
|
|
|
# if the hook fails, remove it
|
|
|
|
self._hooks.remove(hook)
|
|
|
|
raise
|
|
|
|
# legacy support
|
|
|
|
runHook("undoState", can_undo)
|
|
|
|
|
|
|
|
|
2020-01-15 07:53:24 +01:00
|
|
|
undo_state_did_change = _UndoStateDidChangeHook()
|
2020-01-14 23:53:57 +01:00
|
|
|
|
|
|
|
|
2020-01-22 01:46:35 +01:00
|
|
|
class _WebviewDidReceiveJsMessageFilter:
|
|
|
|
"""Used to handle pycmd() messages sent from Javascript.
|
|
|
|
|
2020-02-08 23:59:29 +01:00
|
|
|
Message is the string passed to pycmd().
|
|
|
|
|
|
|
|
For messages you don't want to handle, return 'handled' unchanged.
|
2020-01-22 01:46:35 +01:00
|
|
|
|
|
|
|
If you handle a message and don't want it passed to the original
|
|
|
|
bridge command handler, return (True, None).
|
2020-02-08 23:59:29 +01:00
|
|
|
|
2020-01-22 01:46:35 +01:00
|
|
|
If you want to pass a value to pycmd's result callback, you can
|
2020-02-08 23:59:29 +01:00
|
|
|
return it with (True, some_value).
|
|
|
|
|
|
|
|
Context is the instance that was passed to set_bridge_command().
|
|
|
|
It can be inspected to check which screen this hook is firing
|
|
|
|
in, and to get a reference to the screen. For example, if your
|
|
|
|
code wishes to function only in the review screen, you could do:
|
|
|
|
|
|
|
|
if not isinstance(context, aqt.reviewer.Reviewer):
|
|
|
|
# not reviewer, pass on message
|
|
|
|
return handled
|
|
|
|
|
|
|
|
if message == "my-mark-action":
|
|
|
|
# our message, call onMark() on the reviewer instance
|
|
|
|
context.onMark()
|
|
|
|
# and don't pass message to other handlers
|
|
|
|
return (True, None)
|
|
|
|
else:
|
|
|
|
# some other command, pass it on
|
|
|
|
return handled
|
|
|
|
"""
|
|
|
|
|
|
|
|
_hooks: List[Callable[[Tuple[bool, Any], str, Any], Tuple[bool, Any]]] = []
|
2020-01-22 01:46:35 +01:00
|
|
|
|
|
|
|
def append(
|
2020-02-08 23:59:29 +01:00
|
|
|
self, cb: Callable[[Tuple[bool, Any], str, Any], Tuple[bool, Any]]
|
2020-01-22 01:46:35 +01:00
|
|
|
) -> None:
|
2020-02-08 23:59:29 +01:00
|
|
|
"""(handled: Tuple[bool, Any], message: str, context: Any)"""
|
2020-01-22 01:46:35 +01:00
|
|
|
self._hooks.append(cb)
|
|
|
|
|
|
|
|
def remove(
|
2020-02-08 23:59:29 +01:00
|
|
|
self, cb: Callable[[Tuple[bool, Any], str, Any], Tuple[bool, Any]]
|
2020-01-22 01:46:35 +01:00
|
|
|
) -> None:
|
|
|
|
if cb in self._hooks:
|
|
|
|
self._hooks.remove(cb)
|
|
|
|
|
2020-06-04 10:20:03 +02:00
|
|
|
def count(self) -> int:
|
|
|
|
return len(self._hooks)
|
|
|
|
|
2020-01-22 01:46:35 +01:00
|
|
|
def __call__(
|
2020-02-08 23:59:29 +01:00
|
|
|
self, handled: Tuple[bool, Any], message: str, context: Any
|
2020-01-22 01:46:35 +01:00
|
|
|
) -> Tuple[bool, Any]:
|
|
|
|
for filter in self._hooks:
|
|
|
|
try:
|
|
|
|
handled = filter(handled, message, context)
|
|
|
|
except:
|
|
|
|
# if the hook fails, remove it
|
|
|
|
self._hooks.remove(filter)
|
|
|
|
raise
|
|
|
|
return handled
|
|
|
|
|
|
|
|
|
|
|
|
webview_did_receive_js_message = _WebviewDidReceiveJsMessageFilter()
|
|
|
|
|
|
|
|
|
2020-02-12 22:00:13 +01:00
|
|
|
class _WebviewWillSetContentHook:
|
|
|
|
"""Used to modify web content before it is rendered.
|
|
|
|
|
|
|
|
Web_content contains the HTML, JS, and CSS the web view will be
|
|
|
|
populated with.
|
|
|
|
|
|
|
|
Context is the instance that was passed to stdHtml().
|
|
|
|
It can be inspected to check which screen this hook is firing
|
|
|
|
in, and to get a reference to the screen. For example, if your
|
|
|
|
code wishes to function only in the review screen, you could do:
|
|
|
|
|
2020-02-15 15:03:58 +01:00
|
|
|
def on_webview_will_set_content(web_content: WebContent, context):
|
|
|
|
|
|
|
|
if not isinstance(context, aqt.reviewer.Reviewer):
|
|
|
|
# not reviewer, do not modify content
|
|
|
|
return
|
|
|
|
|
|
|
|
# reviewer, perform changes to content
|
|
|
|
|
|
|
|
context: aqt.reviewer.Reviewer
|
|
|
|
|
|
|
|
addon_package = mw.addonManager.addonFromModule(__name__)
|
|
|
|
|
|
|
|
web_content.css.append(
|
|
|
|
f"/_addons/{addon_package}/web/my-addon.css")
|
|
|
|
web_content.js.append(
|
|
|
|
f"/_addons/{addon_package}/web/my-addon.js")
|
2020-02-12 22:00:13 +01:00
|
|
|
|
2020-02-15 15:03:58 +01:00
|
|
|
web_content.head += "<script>console.log('my-addon')</script>"
|
|
|
|
web_content.body += "<div id='my-addon'></div>"
|
2020-02-12 22:00:13 +01:00
|
|
|
"""
|
|
|
|
|
|
|
|
_hooks: List[Callable[["aqt.webview.WebContent", Optional[Any]], None]] = []
|
|
|
|
|
|
|
|
def append(
|
|
|
|
self, cb: Callable[["aqt.webview.WebContent", Optional[Any]], None]
|
|
|
|
) -> None:
|
|
|
|
"""(web_content: aqt.webview.WebContent, context: Optional[Any])"""
|
|
|
|
self._hooks.append(cb)
|
|
|
|
|
|
|
|
def remove(
|
|
|
|
self, cb: Callable[["aqt.webview.WebContent", Optional[Any]], None]
|
|
|
|
) -> None:
|
|
|
|
if cb in self._hooks:
|
|
|
|
self._hooks.remove(cb)
|
|
|
|
|
2020-06-04 10:20:03 +02:00
|
|
|
def count(self) -> int:
|
|
|
|
return len(self._hooks)
|
|
|
|
|
2020-02-12 22:00:13 +01:00
|
|
|
def __call__(
|
|
|
|
self, web_content: aqt.webview.WebContent, context: Optional[Any]
|
|
|
|
) -> None:
|
|
|
|
for hook in self._hooks:
|
|
|
|
try:
|
|
|
|
hook(web_content, context)
|
|
|
|
except:
|
|
|
|
# if the hook fails, remove it
|
|
|
|
self._hooks.remove(hook)
|
|
|
|
raise
|
|
|
|
|
|
|
|
|
|
|
|
webview_will_set_content = _WebviewWillSetContentHook()
|
|
|
|
|
|
|
|
|
2020-01-15 08:45:35 +01:00
|
|
|
class _WebviewWillShowContextMenuHook:
|
2020-01-14 23:53:57 +01:00
|
|
|
_hooks: List[Callable[["aqt.webview.AnkiWebView", QMenu], None]] = []
|
|
|
|
|
|
|
|
def append(self, cb: Callable[["aqt.webview.AnkiWebView", QMenu], None]) -> None:
|
|
|
|
"""(webview: aqt.webview.AnkiWebView, menu: QMenu)"""
|
|
|
|
self._hooks.append(cb)
|
|
|
|
|
|
|
|
def remove(self, cb: Callable[["aqt.webview.AnkiWebView", QMenu], None]) -> None:
|
2020-01-15 04:07:05 +01:00
|
|
|
if cb in self._hooks:
|
|
|
|
self._hooks.remove(cb)
|
2020-01-14 23:53:57 +01:00
|
|
|
|
2020-06-04 10:20:03 +02:00
|
|
|
def count(self) -> int:
|
|
|
|
return len(self._hooks)
|
|
|
|
|
2020-01-14 23:53:57 +01:00
|
|
|
def __call__(self, webview: aqt.webview.AnkiWebView, menu: QMenu) -> None:
|
|
|
|
for hook in self._hooks:
|
|
|
|
try:
|
|
|
|
hook(webview, menu)
|
|
|
|
except:
|
|
|
|
# if the hook fails, remove it
|
|
|
|
self._hooks.remove(hook)
|
|
|
|
raise
|
|
|
|
# legacy support
|
|
|
|
runHook("AnkiWebView.contextMenuEvent", webview, menu)
|
|
|
|
|
|
|
|
|
2020-01-15 08:45:35 +01:00
|
|
|
webview_will_show_context_menu = _WebviewWillShowContextMenuHook()
|
2020-01-13 05:38:05 +01:00
|
|
|
# @@AUTOGEN@@
|