From 88c69665f3e2450698658d3ab819c1135ac8d5f8 Mon Sep 17 00:00:00 2001 From: RumovZ Date: Fri, 26 Feb 2021 19:52:34 +0100 Subject: [PATCH] Add support for multi deck deletion in python --- ftl/core/decks.ftl | 1 + pylib/anki/decks.py | 16 ++++++++++++---- qt/aqt/deckbrowser.py | 26 ++++++++++++++++---------- qt/aqt/sidebar.py | 19 +++++++++++++------ 4 files changed, 42 insertions(+), 20 deletions(-) diff --git a/ftl/core/decks.ftl b/ftl/core/decks.ftl index 222a993c2..b4b942b10 100644 --- a/ftl/core/decks.ftl +++ b/ftl/core/decks.ftl @@ -2,6 +2,7 @@ decks-add-new-deck-ctrlandn = Add New Deck (Ctrl+N) decks-are-you-sure-you-wish-to = Are you sure you wish to delete { $val }? decks-build = Build decks-cards-selected-by = cards selected by +decks-confirm-deletion = Are you sure you wish to delete { $deck_count } decks including { $card_count } cards? decks-create-deck = Create Deck decks-custom-steps-in-minutes = Custom steps (in minutes) decks-deck = Deck diff --git a/pylib/anki/decks.py b/pylib/anki/decks.py index 17efb366e..0ca2b6a7c 100644 --- a/pylib/anki/decks.py +++ b/pylib/anki/decks.py @@ -135,7 +135,10 @@ class DeckManager: if isinstance(did, str): did = int(did) assert cardsToo and childrenToo - self.col._backend.remove_deck(did) + self.remove([did]) + + def remove(self, dids: List[int]) -> None: + self.col._backend.remove_decks(dids) def all_names_and_ids( self, skip_empty_default: bool = False, include_filtered: bool = True @@ -212,10 +215,15 @@ class DeckManager: def count(self) -> int: return len(self.all_names_and_ids()) - def card_count(self, did: int, include_subdecks: bool) -> Any: - dids: List[int] = [did] + def card_count( + self, dids: Union[int, Iterable[int]], include_subdecks: bool + ) -> Any: + if isinstance(dids, int): + dids = {dids} + else: + dids = set(dids) if include_subdecks: - dids += [r[1] for r in self.children(did)] + dids.update([child[1] for did in dids for child in self.children(did)]) count = self.col.db.scalar( "select count() from cards where did in {0} or " "odid in {0}".format(ids2str(dids)) diff --git a/qt/aqt/deckbrowser.py b/qt/aqt/deckbrowser.py index cd446fec9..1b9463c07 100644 --- a/qt/aqt/deckbrowser.py +++ b/qt/aqt/deckbrowser.py @@ -5,7 +5,7 @@ from __future__ import annotations from concurrent.futures import Future from copy import deepcopy from dataclasses import dataclass -from typing import Any +from typing import Any, List import aqt from anki.decks import DeckTreeNode @@ -296,20 +296,26 @@ class DeckBrowser: self.show() def ask_delete_deck(self, did: int) -> bool: - deck = self.mw.col.decks.get(did) - if deck["dyn"]: + return self.ask_delete_decks([did]) + + def ask_delete_decks(self, dids: List[int]) -> bool: + decks = [self.mw.col.decks.get(did) for did in dids] + if all([deck["dyn"] for deck in decks]): return True - count = self.mw.col.decks.card_count(did, include_subdecks=True) + count = self.mw.col.decks.card_count(dids, include_subdecks=True) if not count: return True - extra = tr(TR.DECKS_IT_HAS_CARD, count=count) - if askUser( - f"{tr(TR.DECKS_ARE_YOU_SURE_YOU_WISH_TO, val=deck['name'])} {extra}" - ): - return True - return False + if len(dids) == 1: + extra = tr(TR.DECKS_IT_HAS_CARD, count=count) + return askUser( + f"{tr(TR.DECKS_ARE_YOU_SURE_YOU_WISH_TO, val=decks[0]['name'])} {extra}" + ) + + return askUser( + tr(TR.DECKS_CONFIRM_DELETION, deck_count=len(dids), card_count=count) + ) def _delete(self, did: int) -> None: if self.ask_delete_deck(did): diff --git a/qt/aqt/sidebar.py b/qt/aqt/sidebar.py index 52ced70b3..41577534d 100644 --- a/qt/aqt/sidebar.py +++ b/qt/aqt/sidebar.py @@ -1108,15 +1108,15 @@ class SidebarTreeView(QTreeView): self.browser.model.beginReset() self.mw.taskman.run_in_background(do_rename, on_done) - def delete_deck(self, item: SidebarItem) -> None: - self.browser.editor.saveNow(lambda: self._delete_deck(item)) + def delete_deck(self, _item: SidebarItem) -> None: + self.browser.editor.saveNow(self._delete_decks) - def _delete_deck(self, item: SidebarItem) -> None: - did = item.id - if self.mw.deckBrowser.ask_delete_deck(did): + def _delete_decks(self) -> None: + dids = self._selected_decks() + if self.mw.deckBrowser.ask_delete_decks(dids): def do_delete() -> None: - return self.mw.col.decks.rem(did, True) + return self.mw.col.decks.remove(dids) def on_done(fut: Future) -> None: self.mw.requireReset(reason=ResetReason.BrowserDeleteDeck, context=self) @@ -1190,3 +1190,10 @@ class SidebarTreeView(QTreeView): def _selected_items(self) -> List[SidebarItem]: return [self.model().item_for_index(idx) for idx in self.selectedIndexes()] + + def _selected_decks(self) -> List[int]: + return [ + item.id + for item in self._selected_items() + if item.item_type == SidebarItemType.DECK + ]