de668441b5
- clear_unused_tags() is now undoable, and returns the number of removed notes - add a new mw.query_op() helper for immutable queries - decouple "freeze/unfreeze ui state" hooks from the "interface update required" hook, so that the former is fired even on error, and can be made re-entrant - use a 'block_updates' flag in Python, instead of setUpdatesEnabled(), as the latter has the side-effect of preventing child windows like tooltips from appearing, and forces a full redrawn when updates are enabled again. The new behaviour leads to the card list blanking out when a long-running op is running, but in the future if we cache the cell values we can just display them from the cache instead. - we were indiscriminately saving the note with saveNow(), due to the call to saveTags(). Changed so that it only saves when the tags field is focused. - drain the "on_done" queue on main before launching a new background task, to lower the chances of something in on_done making a small query to the DB and hanging until a long op finishes - the duplicate check in the editor was executed after the webview loads, leading to it hanging until the sidebar finishes loading. Run it at set_note() time instead, so that the editor loads first. - don't throw an error when a long-running op started with with_progress() finishes after the window it was launched from has closed - don't throw an error when the browser is closed before the sidebar has finished loading
86 lines
2.3 KiB
Python
86 lines
2.3 KiB
Python
# Copyright: Ankitects Pty Ltd and contributors
|
|
# License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
|
|
|
from __future__ import annotations
|
|
|
|
from typing import Callable, Optional, Sequence
|
|
|
|
from anki.lang import TR
|
|
from anki.notes import Note
|
|
from aqt import AnkiQt, QWidget
|
|
from aqt.main import PerformOpOptionalSuccessCallback
|
|
from aqt.utils import show_invalid_search_error, showInfo, tooltip, tr
|
|
|
|
|
|
def add_note(
|
|
*,
|
|
mw: AnkiQt,
|
|
note: Note,
|
|
target_deck_id: int,
|
|
success: PerformOpOptionalSuccessCallback = None,
|
|
) -> None:
|
|
mw.perform_op(lambda: mw.col.add_note(note, target_deck_id), success=success)
|
|
|
|
|
|
def update_note(*, mw: AnkiQt, note: Note, after_hooks: Callable[[], None]) -> None:
|
|
mw.perform_op(
|
|
lambda: mw.col.update_note(note),
|
|
after_hooks=after_hooks,
|
|
)
|
|
|
|
|
|
def remove_notes(
|
|
*,
|
|
mw: AnkiQt,
|
|
note_ids: Sequence[int],
|
|
success: PerformOpOptionalSuccessCallback = None,
|
|
) -> None:
|
|
mw.perform_op(lambda: mw.col.remove_notes(note_ids), success=success)
|
|
|
|
|
|
def add_tags(*, mw: AnkiQt, note_ids: Sequence[int], space_separated_tags: str) -> None:
|
|
mw.perform_op(lambda: mw.col.tags.bulk_add(note_ids, space_separated_tags))
|
|
|
|
|
|
def remove_tags(
|
|
*, mw: AnkiQt, note_ids: Sequence[int], space_separated_tags: str
|
|
) -> None:
|
|
mw.perform_op(lambda: mw.col.tags.bulk_remove(note_ids, space_separated_tags))
|
|
|
|
|
|
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 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: showInfo(
|
|
tr(TR.FINDREPLACE_NOTES_UPDATED, changed=out.count, total=len(note_ids)),
|
|
parent=parent,
|
|
),
|
|
failure=lambda exc: show_invalid_search_error(exc, parent=parent),
|
|
)
|