Пример #1
0
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),
    )
Пример #2
0
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)
Пример #3
0
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
        ),
    )
Пример #4
0
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,
    )
Пример #5
0
    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,
        )
Пример #6
0
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,
        ),
    )
Пример #7
0
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)
Пример #8
0
    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()
Пример #9
0
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),
    )
Пример #10
0
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,
        ),
    )
Пример #11
0
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)
Пример #12
0
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
        ),
    )
Пример #13
0
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)
Пример #14
0
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)
Пример #15
0
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
    )
Пример #16
0
 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)
Пример #17
0
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
    )
Пример #18
0
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,
    )
Пример #19
0
    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,
        )
Пример #20
0
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),
    )
Пример #21
0
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
        ),
    )
Пример #22
0
 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)
Пример #23
0
    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()
Пример #24
0
 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()
Пример #25
0
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)
Пример #26
0
    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()
Пример #27
0
 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)
Пример #28
0
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)
Пример #29
0
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,
    )
Пример #30
0
 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()