161 lines
5.5 KiB
Python
161 lines
5.5 KiB
Python
# -*- coding: utf-8 -*-
|
|
# 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 concurrent.futures import Future
|
|
from enum import Enum
|
|
|
|
import aqt
|
|
from anki.errors import DeckRenameError
|
|
from aqt.main import ResetReason
|
|
from aqt.qt import *
|
|
from aqt.utils import TR, getOnlyText, showInfo, showWarning, tr
|
|
|
|
|
|
class SidebarItemType(Enum):
|
|
ROOT = 0
|
|
COLLECTION = 1
|
|
CURRENT_DECK = 2
|
|
FILTER = 3
|
|
DECK = 4
|
|
NOTETYPE = 5
|
|
TAG = 6
|
|
CUSTOM = 7
|
|
|
|
|
|
class SidebarTreeViewBase(QTreeView):
|
|
def __init__(self):
|
|
super().__init__()
|
|
qconnect(self.expanded, self.onExpansion)
|
|
qconnect(self.collapsed, self.onCollapse)
|
|
|
|
def onClickCurrent(self) -> None:
|
|
idx = self.currentIndex()
|
|
if idx.isValid():
|
|
item: "aqt.browser.SidebarItem" = idx.internalPointer()
|
|
if item.onClick:
|
|
item.onClick()
|
|
|
|
def mouseReleaseEvent(self, event: QMouseEvent) -> None:
|
|
super().mouseReleaseEvent(event)
|
|
if event.button() == Qt.LeftButton:
|
|
self.onClickCurrent()
|
|
|
|
def keyPressEvent(self, event: QKeyEvent) -> None:
|
|
if event.key() in (Qt.Key_Return, Qt.Key_Enter):
|
|
self.onClickCurrent()
|
|
else:
|
|
super().keyPressEvent(event)
|
|
|
|
def onExpansion(self, idx: QModelIndex) -> None:
|
|
self._onExpansionChange(idx, True)
|
|
|
|
def onCollapse(self, idx: QModelIndex) -> None:
|
|
self._onExpansionChange(idx, False)
|
|
|
|
def _onExpansionChange(self, idx: QModelIndex, expanded: bool) -> None:
|
|
item: "aqt.browser.SidebarItem" = idx.internalPointer()
|
|
if item.expanded != expanded:
|
|
item.expanded = expanded
|
|
if item.onExpanded:
|
|
item.onExpanded(expanded)
|
|
|
|
|
|
class NewSidebarTreeView(SidebarTreeViewBase):
|
|
def __init__(self, browser: aqt.browser.Browser) -> None:
|
|
super().__init__()
|
|
self.browser = browser
|
|
self.mw = browser.mw
|
|
self.col = self.mw.col
|
|
|
|
self.setContextMenuPolicy(Qt.CustomContextMenu)
|
|
self.customContextMenuRequested.connect(self.onContextMenu) # type: ignore
|
|
self.context_menus = {
|
|
SidebarItemType.DECK: (
|
|
(tr(TR.ACTIONS_RENAME), self.rename_deck),
|
|
(tr(TR.ACTIONS_DELETE), self.delete_deck),
|
|
),
|
|
SidebarItemType.TAG: ((tr(TR.ACTIONS_RENAME), self.rename_tag),),
|
|
}
|
|
|
|
def onContextMenu(self, point: QPoint) -> None:
|
|
idx: QModelIndex = self.indexAt(point)
|
|
item: "aqt.browser.SidebarItem" = idx.internalPointer()
|
|
if not item:
|
|
return
|
|
item_type: SidebarItemType = item.item_type
|
|
if item_type not in self.context_menus:
|
|
return
|
|
|
|
m = QMenu()
|
|
for action in self.context_menus[item_type]:
|
|
act_name = action[0]
|
|
act_func = action[1]
|
|
a = m.addAction(act_name)
|
|
a.triggered.connect(lambda _, func=act_func: func(item)) # type: ignore
|
|
m.exec_(QCursor.pos())
|
|
|
|
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)
|
|
new_name = new_name.replace('"', "")
|
|
if not new_name or new_name == old_name:
|
|
return
|
|
self.mw.checkpoint(tr(TR.ACTIONS_RENAME_DECK))
|
|
try:
|
|
self.mw.col.decks.rename(deck, new_name)
|
|
except DeckRenameError as e:
|
|
return showWarning(e.description)
|
|
self.browser.maybeRefreshSidebar()
|
|
self.mw.deckBrowser.refresh()
|
|
|
|
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:
|
|
old_name = item.name
|
|
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.mw.taskman.run_in_background(do_rename, on_done)
|
|
|
|
def delete_deck(self, item: "aqt.browser.SidebarItem") -> None:
|
|
self.browser.editor.saveNow(lambda: self._delete_deck(item))
|
|
|
|
def _delete_deck(self, item: "aqt.browser.SidebarItem") -> None:
|
|
did = item.id
|
|
if self.mw.deckBrowser.ask_delete_deck(did):
|
|
|
|
def do_delete():
|
|
return self.mw.col.decks.rem(did, True)
|
|
|
|
def on_done(fut: Future):
|
|
self.mw.requireReset(reason=ResetReason.BrowserDeleteDeck, context=self)
|
|
self.browser.search()
|
|
self.browser.model.endReset()
|
|
self.browser.maybeRefreshSidebar()
|
|
res = fut.result() # Required to check for errors
|
|
|
|
self.mw.checkpoint(tr(TR.DECKS_DELETE_DECK))
|
|
self.browser.model.beginReset()
|
|
self.mw.taskman.run_in_background(do_delete, on_done)
|