def remove_tags_for_all_notes(*, mw: AnkiQt, parent: QWidget, space_separated_tags: str) -> None: mw.perform_op( lambda: mw.col.tags.remove(space_separated_tags=space_separated_tags), success=lambda out: tooltip( tr(TR.BROWSING_NOTES_UPDATED, count=out.count), parent=parent), )
def remove_notes( *, mw: AnkiQt, note_ids: Sequence[NoteID], success: PerformOpOptionalSuccessCallback = None, ) -> None: mw.perform_op(lambda: mw.col.remove_notes(note_ids), success=success)
def clear_unused_tags(*, mw: AnkiQt, parent: QWidget) -> None: mw.perform_op( mw.col.tags.clear_unused_tags, success=lambda out: tooltip( tr(TR.BROWSING_REMOVED_UNUSED_TAGS_COUNT, count=out.count), parent=parent ), )
def add_deck( *, mw: AnkiQt, name: str, success: PerformOpOptionalSuccessCallback = None ) -> None: mw.perform_op( lambda: mw.col.decks.add_normal_deck_with_name(name), success=success, )
def __init__( self, mw: AnkiQt, deck_id: DeckID = DeckID(0), search: Optional[str] = None, search_2: Optional[str] = None, ) -> None: """If 'deck_id' is non-zero, load and modify its settings. Otherwise, build a new deck and derive settings from the current deck. If search or search_2 are provided, they will be used as the default search text. """ QDialog.__init__(self, mw) self.mw = mw self.col = self.mw.col self._desired_search_1 = search self._desired_search_2 = search_2 self._initial_dialog_setup() # set on successful query self.deck: FilteredDeckForUpdate mw.query_op( lambda: mw.col.sched.get_or_create_filtered_deck(deck_id=deck_id), success=self.load_deck_and_show, failure=self.on_fetch_error, )
def set_due_date_dialog( *, mw: aqt.AnkiQt, parent: QWidget, card_ids: List[int], config_key: Optional[Config.String.Key.V], ) -> None: if not card_ids: return default_text = (mw.col.get_config_string(config_key) if config_key is not None else "") prompt = "\n".join([ tr(TR.SCHEDULING_SET_DUE_DATE_PROMPT, cards=len(card_ids)), tr(TR.SCHEDULING_SET_DUE_DATE_PROMPT_HINT), ]) (days, success) = getText( prompt=prompt, parent=parent, default=default_text, title=tr(TR.ACTIONS_SET_DUE_DATE), ) if not success or not days.strip(): return mw.perform_op( lambda: mw.col.sched.set_due_date(card_ids, days, config_key), success=lambda _: tooltip( tr(TR.SCHEDULING_SET_DUE_DATE_DONE, cards=len(card_ids)), parent=parent, ), )
def bury_cards( *, mw: AnkiQt, card_ids: Sequence[int], success: PerformOpOptionalSuccessCallback = None, ) -> None: mw.perform_op(lambda: mw.col.sched.bury_cards(card_ids), success=success)
def __init__( self, mw: AnkiQt, deck_id: DeckId = DeckId(0), search: str | None = None, search_2: str | None = None, ) -> None: """If 'deck_id' is non-zero, load and modify its settings. Otherwise, build a new deck and derive settings from the current deck. If search or search_2 are provided, they will be used as the default search text. """ QDialog.__init__(self, mw) self.mw = mw mw.garbage_collect_on_dialog_finish(self) self.col = self.mw.col self._desired_search_1 = search self._desired_search_2 = search_2 self._initial_dialog_setup() # set on successful query self.deck: FilteredDeckForUpdate QueryOp( parent=self.mw, op=lambda col: col.sched.get_or_create_filtered_deck(deck_id= deck_id), success=self.load_deck_and_show, ).failure(self.on_fetch_error).run_in_background()
def reparent_tags(*, mw: AnkiQt, parent: QWidget, tags: Sequence[str], new_parent: str) -> None: mw.perform_op( lambda: mw.col.tags.reparent(tags=tags, new_parent=new_parent), success=lambda out: tooltip( tr(TR.BROWSING_NOTES_UPDATED, count=out.count), parent=parent), )
def find_and_replace( *, mw: AnkiQt, parent: QWidget, note_ids: Sequence[int], search: str, replacement: str, regex: bool, field_name: Optional[str], match_case: bool, ) -> None: mw.perform_op( lambda: mw.col.find_and_replace( note_ids=note_ids, search=search, replacement=replacement, regex=regex, field_name=field_name, match_case=match_case, ), success=lambda out: tooltip( tr(TR.FINDREPLACE_NOTES_UPDATED, changed=out.count, total=len(note_ids)), parent=parent, ), )
def suspend_cards( *, mw: AnkiQt, card_ids: Sequence[CardID], success: PerformOpOptionalSuccessCallback = None, ) -> None: mw.perform_op(lambda: mw.col.sched.suspend_cards(card_ids), success=success)
def reparent_decks( *, mw: AnkiQt, parent: QWidget, deck_ids: Sequence[DeckID], new_parent: DeckID ) -> None: mw.perform_op( lambda: mw.col.decks.reparent(deck_ids=deck_ids, new_parent=new_parent), success=lambda out: tooltip( tr(TR.BROWSING_REPARENTED_DECKS, count=out.count), parent=parent ), )
def add_note( *, mw: AnkiQt, note: Note, target_deck_id: DeckID, success: PerformOpOptionalSuccessCallback = None, ) -> None: mw.perform_op(lambda: mw.col.add_note(note, target_deck_id), success=success)
def add_tags( *, mw: AnkiQt, note_ids: Sequence[NoteID], space_separated_tags: str, success: PerformOpOptionalSuccessCallback = None, ) -> None: mw.perform_op(lambda: mw.col.tags.bulk_add(note_ids, space_separated_tags), success=success)
def remove_tags_for_notes( *, mw: AnkiQt, note_ids: Sequence[int], space_separated_tags: str, success: PerformOpOptionalSuccessCallback = None, ) -> None: mw.perform_op( lambda: mw.col.tags.bulk_remove(note_ids, space_separated_tags), success=success )
def __init__(self, parent: QWidget, mw: AnkiQt, on_close: Callable[[], None]) -> None: super().__init__(None, Qt.WindowType.Window) mw.garbage_collect_on_dialog_finish(self) self._open = True self._parent = parent self._close_callback = on_close self.mw = mw disable_help_button(self) setWindowIcon(self)
def rename_deck( *, mw: AnkiQt, deck_id: DeckID, new_name: str, after_rename: Callable[[], None] = None, ) -> None: mw.perform_op( lambda: mw.col.decks.rename(deck_id, new_name), after_hooks=after_rename )
def add_or_update_filtered_deck( *, mw: AnkiQt, deck: FilteredDeckForUpdate, success: PerformOpOptionalSuccessCallback, ) -> None: mw.perform_op( lambda: mw.col.sched.add_or_update_filtered_deck(deck), success=success, )
def __init__(self, parent: QWidget, *, mw: AnkiQt, note_ids: Sequence[int]) -> None: super().__init__(parent) self.mw = mw self.note_ids = note_ids self.field_names: List[str] = [] # fetch field names and then show mw.query_op( lambda: mw.col.field_names_for_note_ids(note_ids), success=self._show, )
def forget_cards(*, mw: aqt.AnkiQt, parent: QWidget, card_ids: List[int]) -> None: if not card_ids: return mw.perform_op( lambda: mw.col.sched.schedule_cards_as_new(card_ids), success=lambda _: tooltip(tr(TR.SCHEDULING_FORGOT_CARDS, cards=len(card_ids)), parent=parent), )
def remove_decks( *, mw: AnkiQt, parent: QWidget, deck_ids: Sequence[DeckID], ) -> None: mw.perform_op( lambda: mw.col.decks.remove(deck_ids), success=lambda out: tooltip( tr(TR.BROWSING_CARDS_DELETED, count=out.count), parent=parent ), )
def __init__(self, parent: QWidget, mw: AnkiQt, on_close: Callable[[], None]) -> None: super().__init__(None, Qt.Window) mw.garbage_collect_on_dialog_finish(self) self._open = True self._parent = parent self._close_callback = on_close self.mw = mw icon = QIcon() icon.addPixmap(QPixmap(":/icons/anki.png"), QIcon.Normal, QIcon.Off) disable_help_button(self) self.setWindowIcon(icon)
def __init__( self, mw: AnkiQt, nt: NotetypeDict, parent: Optional[QWidget] = None, open_at: int = 0, ) -> None: QDialog.__init__(self, parent or mw) mw.garbage_collect_on_dialog_finish(self) self.mw = mw self.col = self.mw.col self.mm = self.mw.col.models self.model = nt self.mm._remove_from_cache(self.model["id"]) self.change_tracker = ChangeTracker(self.mw) self.setWindowTitle( without_unicode_isolation( tr.fields_fields_for(val=self.model["name"]))) if os.getenv("ANKI_EXPERIMENTAL_FIELDS_WEB"): form = aqt.forms.fields_web.Ui_Dialog() form.setupUi(self) self.webview = form.webview self.webview.set_title("fields") self.show() self.refresh() self.webview.set_bridge_command(self._on_bridge_cmd, self) self.activateWindow() return self.form = aqt.forms.fields.Ui_Dialog() self.form.setupUi(self) self.webview = None disable_help_button(self) self.form.buttonBox.button( QDialogButtonBox.StandardButton.Help).setAutoDefault(False) self.form.buttonBox.button( QDialogButtonBox.StandardButton.Cancel).setAutoDefault(False) self.form.buttonBox.button( QDialogButtonBox.StandardButton.Save).setAutoDefault(False) self.currentIdx: Optional[int] = None self.fillFields() self.setupSignals() self.form.fieldList.setDragDropMode( QAbstractItemView.DragDropMode.InternalMove) self.form.fieldList.dropEvent = self.onDrop # type: ignore[assignment] self.form.fieldList.setCurrentRow(open_at) self.exec()
def __init__( self, mw: AnkiQt, note: Note, ord=0, parent: Optional[QWidget] = None, fill_empty: bool = False, ): QDialog.__init__(self, parent or mw, Qt.Window) mw.setupDialogGC(self) self.mw = aqt.mw self.note = note self.ord = ord self.col = self.mw.col.weakref() self.mm = self.mw.col.models self.model = note.model() self.templates = self.model["tmpls"] self.fill_empty_action_toggled = fill_empty self.night_mode_is_enabled = self.mw.pm.night_mode() self.mobile_emulation_enabled = False self.have_autoplayed = False self.mm._remove_from_cache(self.model["id"]) self.mw.checkpoint(tr(TR.CARD_TEMPLATES_CARD_TYPES)) self.change_tracker = ChangeTracker(self.mw) self.setupTopArea() self.setupMainArea() self.setupButtons() self.setupShortcuts() self.setWindowTitle( without_unicode_isolation( tr(TR.CARD_TEMPLATES_CARD_TYPES_FOR, val=self.model["name"]) ) ) disable_help_button(self) v1 = QVBoxLayout() v1.addWidget(self.topArea) v1.addWidget(self.mainArea) v1.addLayout(self.buttons) v1.setContentsMargins(12, 12, 12, 12) self.setLayout(v1) gui_hooks.card_layout_will_show(self) self.redraw_everything() restoreGeom(self, "CardLayout") restoreSplitter(self.mainArea, "CardLayoutMainArea") self.setWindowModality(Qt.ApplicationModal) self.show() # take the focus away from the first input area when starting up, # as users tend to accidentally type into the template self.setFocus()
def set_due_date_dialog( *, mw: aqt.AnkiQt, parent: QDialog, card_ids: List[int], default_key: Config.String.Key.V, on_done: Callable[[], None], ) -> None: if not card_ids: return default = mw.col.get_config_string(default_key) prompt = "\n".join([ tr(TR.SCHEDULING_SET_DUE_DATE_PROMPT, cards=len(card_ids)), tr(TR.SCHEDULING_SET_DUE_DATE_PROMPT_HINT), ]) (days, success) = getText( prompt=prompt, parent=parent, default=default, title=tr(TR.ACTIONS_SET_DUE_DATE), ) if not success or not days.strip(): return def set_due() -> None: mw.col.sched.set_due_date(card_ids, days) if days != default: mw.col.set_config_string(default_key, days) def after_set(fut: Future) -> None: try: fut.result() except Exception as e: showWarning(str(e)) on_done() return tooltip( tr(TR.SCHEDULING_SET_DUE_DATE_DONE, cards=len(card_ids)), parent=parent, ) on_done() mw.checkpoint(tr(TR.ACTIONS_SET_DUE_DATE)) mw.taskman.with_progress(set_due, after_set)
def __init__( self, mw: AnkiQt, card: Optional[Card] = None, search: Optional[Tuple[Union[str, SearchNode]]] = None, ) -> None: """ card : try to search for its note and select it search: set and perform search; caller must ensure validity """ QMainWindow.__init__(self, None, Qt.Window) self.mw = mw self.col = self.mw.col self.lastFilter = "" self.focusTo: Optional[int] = None self._previewer: Optional[Previewer] = None self._closeEventHasCleanedUp = False self.form = aqt.forms.browser.Ui_Dialog() self.form.setupUi(self) self.setupSidebar() restoreGeom(self, "editor", 0) restoreState(self, "editor") restoreSplitter(self.form.splitter, "editor3") self.form.splitter.setChildrenCollapsible(False) self.card: Optional[Card] = None self.setup_table() self.setupMenus() self.setupHooks() self.setupEditor() # disable undo/redo self.on_undo_state_change(mw.undo_actions_info()) self.setupSearch(card, search) gui_hooks.browser_will_show(self) self.show()
def __init__(self, mw: aqt.AnkiQt) -> None: QObject.__init__(self) self.mw = mw.weakref() self._executor = ThreadPoolExecutor() self._closures: list[Closure] = [] self._closures_lock = Lock() qconnect(self._closures_pending, self._on_closures_pending)
def forget_cards(*, mw: aqt.AnkiQt, parent: QDialog, card_ids: List[int], on_done: Callable[[], None]) -> None: if not card_ids: return def on_done_wrapper(fut: Future) -> None: try: fut.result() except Exception as e: showWarning(str(e)) else: tooltip(tr(TR.SCHEDULING_FORGOT_CARDS, cards=len(card_ids)), parent=parent) on_done() mw.checkpoint(tr(TR.ACTIONS_FORGET)) mw.taskman.with_progress( lambda: mw.col.sched.schedule_cards_as_new(card_ids), on_done_wrapper)
def rename_tag( *, mw: AnkiQt, parent: QWidget, current_name: str, new_name: str, after_rename: Callable[[], None], ) -> None: def success(out: OpChangesWithCount) -> None: if out.count: tooltip(tr(TR.BROWSING_NOTES_UPDATED, count=out.count), parent=parent) else: showInfo(tr(TR.BROWSING_TAG_RENAME_WARNING_EMPTY), parent=parent) mw.perform_op( lambda: mw.col.tags.rename(old=current_name, new=new_name), success=success, after_hooks=after_rename, )
def __init__( self, mw: AnkiQt, note: Note, ord=0, parent: Optional[QWidget] = None, fill_empty: bool = False, ): QDialog.__init__(self, parent or mw, Qt.Window) mw.setupDialogGC(self) self.mw = aqt.mw self.note = note self.ord = ord self.col = self.mw.col.weakref() self.mm = self.mw.col.models self.model = note.model() self.templates = self.model["tmpls"] self._want_fill_empty_on = fill_empty self.have_autoplayed = False self.mm._remove_from_cache(self.model["id"]) self.mw.checkpoint(_("Card Types")) self.change_tracker = ChangeTracker(self.mw) self.setupTopArea() self.setupMainArea() self.setupButtons() self.setupShortcuts() self.setWindowTitle(_("Card Types for %s") % self.model["name"]) v1 = QVBoxLayout() v1.addWidget(self.topArea) v1.addWidget(self.mainArea) v1.addLayout(self.buttons) v1.setContentsMargins(12, 12, 12, 12) self.setLayout(v1) gui_hooks.card_layout_will_show(self) self.redraw_everything() restoreGeom(self, "CardLayout") restoreSplitter(self.mainArea, "CardLayoutMainArea") self.setWindowModality(Qt.ApplicationModal) self.show() # take the focus away from the first input area when starting up, # as users tend to accidentally type into the template self.setFocus()