do tag rename and tag clearing in background; move logic to tags.py

Because the logic is in rename_tag() now, it means we create a
checkpoint even if the tag is orphaned. This is because currently
checkpointing is a GUI responsibility. In the future we need to introduce
multi-level undo, and should move responsibility for managing it
to the backend.
This commit is contained in:
Damien Elmes 2021-01-04 14:13:20 +10:00
parent 35ce1b0d29
commit f3fa9daae2
3 changed files with 37 additions and 18 deletions

View file

@ -13,7 +13,7 @@ from __future__ import annotations
import pprint
import re
from typing import Collection, List, Optional, Tuple
from typing import Collection, List, Optional, Sequence, Tuple
import anki # pylint: disable=unused-import
from anki.utils import ids2str
@ -92,7 +92,7 @@ class TagManager:
return self.col.backend.add_note_tags(nids=nids, tags=tags)
def bulk_update(
self, nids: List[int], tags: str, replacement: str, regex: bool
self, nids: Sequence[int], tags: str, replacement: str, regex: bool
) -> int:
"""Replace space-separated tags, returning changed count.
Tags replaced with an empty string will be removed."""
@ -100,6 +100,15 @@ class TagManager:
nids=nids, tags=tags, replacement=replacement, regex=regex
)
def rename_tag(self, old: str, new: str) -> int:
"Rename provided tag, returning number of changed notes."
escaped_name = re.sub(r"[*_\\]", r"\\\g<0>", old)
escaped_name = '"{}"'.format(escaped_name.replace('"', '\\"'))
nids = self.col.find_notes("tag:" + escaped_name)
if not nids:
return 0
return self.col.tags.bulk_update(nids, old, new, False)
# legacy routines
def bulkAdd(self, ids: List[int], tags: str, add: bool = True) -> None:

View file

@ -6,6 +6,7 @@ from __future__ import annotations
import html
import re
import time
from concurrent.futures import Future
from dataclasses import dataclass
from enum import Enum
from operator import itemgetter
@ -1649,8 +1650,11 @@ where id in %s"""
self.editor.saveNow(self._clearUnusedTags)
def _clearUnusedTags(self):
self.col.tags.registerNotes()
self.on_tag_list_update()
def on_done(fut: Future):
fut.result()
self.on_tag_list_update()
self.mw.taskman.run_in_background(self.col.tags.registerNotes, on_done)
# Suspending
######################################################################

View file

@ -4,6 +4,7 @@
from __future__ import annotations
import re
from concurrent.futures import Future
from enum import Enum
import aqt
@ -92,7 +93,7 @@ class NewSidebarTreeView(SidebarTreeViewBase):
a.triggered.connect(lambda _, func=act_func: func(item)) # type: ignore
m.exec_(QCursor.pos())
def rename_deck(self, item: aqt.browser.SidebarItem) -> None:
def rename_deck(self, item: "aqt.browser.SidebarItem") -> None:
deck = self.mw.col.decks.get(item.id)
old_name = deck["name"]
new_name = getOnlyText(tr(TR.DECKS_NEW_DECK_NAME), default=old_name)
@ -107,24 +108,29 @@ class NewSidebarTreeView(SidebarTreeViewBase):
self.browser.maybeRefreshSidebar()
self.mw.deckBrowser.refresh()
def rename_tag(self, item: aqt.browser.SidebarItem) -> None:
def rename_tag(self, item: "aqt.browser.SidebarItem") -> None:
self.browser.editor.saveNow(lambda: self._rename_tag(item))
def _rename_tag(self, item: aqt.browser.SidebarItem) -> None:
def _rename_tag(self, item: "aqt.browser.SidebarItem") -> None:
old_name = item.name
escaped_name = re.sub(r"[*_\\]", r"\\\g<0>", old_name)
escaped_name = '"{}"'.format(escaped_name.replace('"', '\\"'))
nids = self.col.find_notes("tag:" + escaped_name)
if len(nids) == 0:
showInfo(tr(TR.BROWSING_TAG_RENAME_WARNING_EMPTY))
return
new_name = getOnlyText(tr(TR.ACTIONS_NEW_NAME), default=old_name)
if new_name == old_name or not new_name:
return
def do_rename():
return self.col.tags.rename_tag(old_name, new_name)
def on_done(fut: Future):
self.mw.requireReset(reason=ResetReason.BrowserAddTags, context=self)
self.browser.model.endReset()
count = fut.result()
if not count:
showInfo(tr(TR.BROWSING_TAG_RENAME_WARNING_EMPTY))
return
self.browser.clearUnusedTags()
self.mw.checkpoint(tr(TR.ACTIONS_RENAME_TAG))
self.browser.model.beginReset()
self.col.tags.bulk_update(list(nids), old_name, new_name, False)
self.browser.model.endReset()
self.browser.clearUnusedTags()
self.mw.requireReset(reason=ResetReason.BrowserAddTags, context=self)
self.browser.maybeRefreshSidebar()
self.mw.taskman.run_in_background(do_rename, on_done)