From e4ae41340f4bc8b91a479bccc610cc9af81b210b Mon Sep 17 00:00:00 2001 From: Arthur Milchior Date: Fri, 6 Mar 2020 16:25:02 +0100 Subject: [PATCH] Hook to decide whether a note should be added. --- qt/aqt/addcards.py | 6 +++++- qt/aqt/gui_hooks.py | 39 +++++++++++++++++++++++++++++++++++++++ qt/tools/genhooks_gui.py | 12 ++++++++++++ 3 files changed, 56 insertions(+), 1 deletion(-) diff --git a/qt/aqt/addcards.py b/qt/aqt/addcards.py index be6308e30..d2adc2966 100644 --- a/qt/aqt/addcards.py +++ b/qt/aqt/addcards.py @@ -167,8 +167,12 @@ class AddCards(QDialog): def addNote(self, note) -> Optional[Note]: note.model()["did"] = self.deckChooser.selectedId() ret = note.dupeOrEmpty() + rejection = None if ret == 1: - showWarning(_("The first field is empty."), help="AddItems#AddError") + rejection = _("The first field is empty.") + rejection = gui_hooks.add_card_accepts(rejection, note) + if rejection is not None: + showWarning(rejection, help="AddItems#AddError") return None if "{{cloze:" in note.model()["tmpls"][0]["qfmt"]: if not self.mw.col.models._availClozeOrds( diff --git a/qt/aqt/gui_hooks.py b/qt/aqt/gui_hooks.py index eed241f7e..7262d2198 100644 --- a/qt/aqt/gui_hooks.py +++ b/qt/aqt/gui_hooks.py @@ -23,6 +23,45 @@ from aqt.qt import QDialog, QMenu # @@AUTOGEN@@ +class _AddCardAcceptsFilter: + """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: + """(reason_to_already_reject: Optional[str], note: anki.notes.Note)""" + 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) + + def __call__( + self, reason_to_already_reject: Optional[str], note: anki.notes.Note + ) -> Optional[str]: + for filter in self._hooks: + try: + reason_to_already_reject = filter(reason_to_already_reject, note) + except: + # if the hook fails, remove it + self._hooks.remove(filter) + raise + return reason_to_already_reject + + +add_card_accepts = _AddCardAcceptsFilter() + + class _AddCardsDidAddNoteHook: _hooks: List[Callable[["anki.notes.Note"], None]] = [] diff --git a/qt/tools/genhooks_gui.py b/qt/tools/genhooks_gui.py index dcf543979..011ca9ace 100644 --- a/qt/tools/genhooks_gui.py +++ b/qt/tools/genhooks_gui.py @@ -412,6 +412,18 @@ def emptyNewCard(): args=["note: anki.notes.Note"], legacy_hook="AddCards.noteAdded", ), + Hook( + name="add_card_accepts", + args=["reason_to_already_reject: Optional[str]", "note: anki.notes.Note"], + return_type="Optional[str]", + doc="""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.""", + ), # Editing ################### Hook(