From 335047187a7a787dc7816c51dfb0077681abebce Mon Sep 17 00:00:00 2001 From: Glutanimate Date: Mon, 24 Feb 2020 13:42:30 +0100 Subject: [PATCH] Add hooks for extending the deck options dialog Introduces three new hooks: * deck_conf_will_show: Allows adding or modifying widgets * deck_conf_did_load_config: Allows add-on widgets to read from config * deck_conf_will_save_config: Allows add-on widgets to write to config --- qt/aqt/deckconf.py | 4 ++ qt/aqt/gui_hooks.py | 80 ++++++++++++++++++++++++++++++++++++++++ qt/tools/genhooks_gui.py | 17 +++++++++ 3 files changed, 101 insertions(+) diff --git a/qt/aqt/deckconf.py b/qt/aqt/deckconf.py index 629ef354f..bacfd816e 100644 --- a/qt/aqt/deckconf.py +++ b/qt/aqt/deckconf.py @@ -6,6 +6,7 @@ from operator import itemgetter import aqt from anki.consts import NEW_CARDS_RANDOM from anki.lang import _, ngettext +from aqt import gui_hooks from aqt.qt import * from aqt.utils import ( askUser, @@ -40,6 +41,7 @@ class DeckConf(QDialog): self.setWindowTitle(_("Options for %s") % self.deck["name"]) # qt doesn't size properly with altered fonts otherwise restoreGeom(self, "deckconf", adjustSize=True) + gui_hooks.deck_conf_will_show(self) self.show() self.exec_() saveGeom(self, "deckconf") @@ -218,6 +220,7 @@ class DeckConf(QDialog): f.replayQuestion.setChecked(c.get("replayq", True)) # description f.desc.setPlainText(self.deck["desc"]) + gui_hooks.deck_conf_did_load_config(self, self.conf) def onRestore(self): self.mw.progress.start() @@ -301,6 +304,7 @@ class DeckConf(QDialog): c["replayq"] = f.replayQuestion.isChecked() # description self.deck["desc"] = f.desc.toPlainText() + gui_hooks.deck_conf_will_save_config(self, self.deck, self.conf) self.mw.col.decks.save(self.deck) self.mw.col.decks.save(self.conf) diff --git a/qt/aqt/gui_hooks.py b/qt/aqt/gui_hooks.py index bc6dd98e7..80c7b4630 100644 --- a/qt/aqt/gui_hooks.py +++ b/qt/aqt/gui_hooks.py @@ -518,6 +518,86 @@ class _DeckBrowserWillShowOptionsMenuHook: deck_browser_will_show_options_menu = _DeckBrowserWillShowOptionsMenuHook() +class _DeckConfDidLoadConfigHook: + """Called once widget state has been set from deck config""" + + _hooks: List[Callable[["aqt.deckconf.DeckConf", Any], None]] = [] + + def append(self, cb: Callable[["aqt.deckconf.DeckConf", Any], None]) -> None: + """(deck_conf: aqt.deckconf.DeckConf, config: Any)""" + self._hooks.append(cb) + + def remove(self, cb: Callable[["aqt.deckconf.DeckConf", Any], None]) -> None: + if cb in self._hooks: + self._hooks.remove(cb) + + def __call__(self, deck_conf: aqt.deckconf.DeckConf, config: Any) -> None: + for hook in self._hooks: + try: + hook(deck_conf, config) + except: + # if the hook fails, remove it + self._hooks.remove(hook) + raise + + +deck_conf_did_load_config = _DeckConfDidLoadConfigHook() + + +class _DeckConfWillSaveConfigHook: + """Called before widget state is saved to config""" + + _hooks: List[Callable[["aqt.deckconf.DeckConf", Any, Any], None]] = [] + + def append(self, cb: Callable[["aqt.deckconf.DeckConf", Any, Any], None]) -> None: + """(deck_conf: aqt.deckconf.DeckConf, config: Any, deck: Any)""" + self._hooks.append(cb) + + def remove(self, cb: Callable[["aqt.deckconf.DeckConf", Any, Any], None]) -> None: + if cb in self._hooks: + self._hooks.remove(cb) + + def __call__( + self, deck_conf: aqt.deckconf.DeckConf, config: Any, deck: Any + ) -> None: + for hook in self._hooks: + try: + hook(deck_conf, config, deck) + 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) + + 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() + + class _EditorDidFireTypingTimerHook: _hooks: List[Callable[["anki.notes.Note"], None]] = [] diff --git a/qt/tools/genhooks_gui.py b/qt/tools/genhooks_gui.py index 17e55ea25..0d475b53a 100644 --- a/qt/tools/genhooks_gui.py +++ b/qt/tools/genhooks_gui.py @@ -121,6 +121,23 @@ hooks = [ legacy_hook="prepareQA", doc="Can modify card text before review/preview.", ), + # Deck options + ################### + Hook( + name="deck_conf_will_show", + args=["deck_conf: aqt.deckconf.DeckConf"], + doc="Allows modifying the deck options dialog before it is shown", + ), + Hook( + name="deck_conf_did_load_config", + args=["deck_conf: aqt.deckconf.DeckConf", "config: Any"], + doc="Called once widget state has been set from deck config", + ), + Hook( + name="deck_conf_will_save_config", + args=["deck_conf: aqt.deckconf.DeckConf", "config: Any", "deck: Any"], + doc="Called before widget state is saved to config", + ), # Browser ################### Hook(