From 56b6fad7435b418ce5748421e841ebdaef6cb20f Mon Sep 17 00:00:00 2001 From: BlueGreenMagick <50060875+BlueGreenMagick@users.noreply.github.com> Date: Sun, 26 Apr 2020 11:27:25 +0900 Subject: [PATCH 1/7] pass to SidebarItem its type removed 'for in list' as mypy does not correctly infer its types --- qt/aqt/browser.py | 41 +++++++++++++++++++++++++++++++---------- 1 file changed, 31 insertions(+), 10 deletions(-) diff --git a/qt/aqt/browser.py b/qt/aqt/browser.py index 62a3bb380..45c84e99f 100644 --- a/qt/aqt/browser.py +++ b/qt/aqt/browser.py @@ -435,6 +435,17 @@ class SidebarStage(Enum): TAGS = 5 +class SidebarItemType(Enum): + ROOT = 0 + COLLECTION = 1 + CURRENT_DECK = 2 + FILTER = 3 + DECK = 4 + NOTETYPE = 5 + TAG = 6 + CUSTOM = 7 + + class SidebarItem: def __init__( self, @@ -443,9 +454,11 @@ class SidebarItem: onClick: Callable[[], None] = None, onExpanded: Callable[[bool], None] = None, expanded: bool = False, + item_type: SidebarItemType = SidebarItemType.CUSTOM, ) -> None: self.name = name self.icon = icon + self.item_type = item_type self.onClick = onClick self.onExpanded = onExpanded self.expanded = expanded @@ -1091,7 +1104,7 @@ QTableView {{ gridline-color: {grid} }} self.mw.progress.timer(10, deferredDisplay, False) def buildTree(self) -> SidebarItem: - root = SidebarItem("", "") + root = SidebarItem("", "", item_type=SidebarItemType.ROOT) handled = gui_hooks.browser_will_build_tree( False, root, SidebarStage.ROOT, self @@ -1116,14 +1129,20 @@ QTableView {{ gridline-color: {grid} }} return root def _stdTree(self, root) -> None: - for name, filt, icon in [ - [_("Whole Collection"), "", "collection"], - [_("Current Deck"), "deck:current", "deck"], - ]: - item = SidebarItem( - name, ":/icons/{}.svg".format(icon), self._filterFunc(filt) - ) - root.addChild(item) + item = SidebarItem( + _("Whole Collection"), + ":/icons/collection.svg", + self._filterFunc(""), + item_type=SidebarItemType.COLLECTION, + ) + root.addChild(item) + item = SidebarItem( + _("Current Deck"), + ":/icons/deck.svg", + self._filterFunc("deck:current"), + item_type=SidebarItemType.CURRENT_DECK, + ) + root.addChild(item) def _favTree(self, root) -> None: assert self.col @@ -1133,6 +1152,7 @@ QTableView {{ gridline-color: {grid} }} name, ":/icons/heart.svg", lambda s=filt: self.setFilter(s), # type: ignore + item_type=SidebarItemType.DECK, ) root.addChild(item) @@ -1140,7 +1160,7 @@ QTableView {{ gridline-color: {grid} }} assert self.col for t in self.col.tags.all(): item = SidebarItem( - t, ":/icons/tag.svg", lambda t=t: self.setFilter("tag", t) # type: ignore + t, ":/icons/tag.svg", lambda t=t: self.setFilter("tag", t), item_type=SidebarItemType.TAG # type: ignore ) root.addChild(item) @@ -1165,6 +1185,7 @@ QTableView {{ gridline-color: {grid} }} lambda baseName=baseName: self.setFilter("deck", head + baseName), lambda expanded, did=did: self.mw.col.decks.collapseBrowser(did), not self.mw.col.decks.get(did).get("browserCollapsed", False), + item_type=SidebarItemType.DECK, ) root.addChild(item) newhead = head + baseName + "::" From 1e124bf19cf7c6b4e39001a86214ee00265612ba Mon Sep 17 00:00:00 2001 From: BlueGreenMagick <50060875+BlueGreenMagick@users.noreply.github.com> Date: Sun, 26 Apr 2020 11:32:32 +0900 Subject: [PATCH 2/7] Seperate SidebarTreeView class from Browser --- qt/aqt/browser.py | 81 ++++++++++++++++++++++++----------------------- 1 file changed, 41 insertions(+), 40 deletions(-) diff --git a/qt/aqt/browser.py b/qt/aqt/browser.py index 45c84e99f..9d48b0118 100644 --- a/qt/aqt/browser.py +++ b/qt/aqt/browser.py @@ -576,6 +576,46 @@ class SidebarModel(QAbstractItemModel): # then ourselves tree.setExpanded(parent, True) + # Sidebar + ###################################################################### + + +class SidebarTreeView(QTreeView): + def __init__(self): + super().__init__() + self.expanded.connect(self.onExpansion) + self.collapsed.connect(self.onCollapse) + + def onClickCurrent(self) -> None: + idx = self.currentIndex() + if idx.isValid(): + item: SidebarItem = idx.internalPointer() + if item.onClick: + item.onClick() + + def mouseReleaseEvent(self, event: QMouseEvent) -> None: + super().mouseReleaseEvent(event) + 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: SidebarItem = idx.internalPointer() + if item.expanded != expanded: + item.expanded = expanded + if item.onExpanded: + item.onExpanded(expanded) + # Browser window ###################################################################### @@ -1022,51 +1062,12 @@ QTableView {{ gridline-color: {grid} }} def onColumnMoved(self, a, b, c): self.setColumnSizes() - # Sidebar - ###################################################################### - - class SidebarTreeView(QTreeView): - def __init__(self): - super().__init__() - self.expanded.connect(self.onExpansion) - self.collapsed.connect(self.onCollapse) - - def onClickCurrent(self) -> None: - idx = self.currentIndex() - if idx.isValid(): - item: SidebarItem = idx.internalPointer() - if item.onClick: - item.onClick() - - def mouseReleaseEvent(self, event: QMouseEvent) -> None: - super().mouseReleaseEvent(event) - 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: SidebarItem = idx.internalPointer() - if item.expanded != expanded: - item.expanded = expanded - if item.onExpanded: - item.onExpanded(expanded) - def setupSidebar(self) -> None: dw = self.sidebarDockWidget = QDockWidget(_("Sidebar"), self) dw.setFeatures(QDockWidget.DockWidgetClosable) dw.setObjectName("Sidebar") dw.setAllowedAreas(Qt.LeftDockWidgetArea) - self.sidebarTree = self.SidebarTreeView() + self.sidebarTree = SidebarTreeView() self.sidebarTree.mw = self.mw self.sidebarTree.setUniformRowHeights(True) self.sidebarTree.setHeaderHidden(True) From e7e19f8ac830050dcae6f12f29fd3e4f38a21cb8 Mon Sep 17 00:00:00 2001 From: BlueGreenMagick <50060875+BlueGreenMagick@users.noreply.github.com> Date: Sun, 26 Apr 2020 11:34:23 +0900 Subject: [PATCH 3/7] pass Browser to SidebarTreeView --- qt/aqt/browser.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/qt/aqt/browser.py b/qt/aqt/browser.py index 9d48b0118..6ddf8c8c2 100644 --- a/qt/aqt/browser.py +++ b/qt/aqt/browser.py @@ -581,8 +581,11 @@ class SidebarModel(QAbstractItemModel): class SidebarTreeView(QTreeView): - def __init__(self): + def __init__(self, browser: "Browser"): super().__init__() + self.browser = browser + self.mw = browser.mw + self.col = self.mw.col self.expanded.connect(self.onExpansion) self.collapsed.connect(self.onCollapse) @@ -1067,7 +1070,7 @@ QTableView {{ gridline-color: {grid} }} dw.setFeatures(QDockWidget.DockWidgetClosable) dw.setObjectName("Sidebar") dw.setAllowedAreas(Qt.LeftDockWidgetArea) - self.sidebarTree = SidebarTreeView() + self.sidebarTree = SidebarTreeView(self) self.sidebarTree.mw = self.mw self.sidebarTree.setUniformRowHeights(True) self.sidebarTree.setHeaderHidden(True) From 9c2eb8bf001735809b81259aa445dc2c051a96d4 Mon Sep 17 00:00:00 2001 From: BlueGreenMagick <50060875+BlueGreenMagick@users.noreply.github.com> Date: Sun, 26 Apr 2020 11:50:10 +0900 Subject: [PATCH 4/7] add context menu to SidebarTreeView --- qt/aqt/browser.py | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/qt/aqt/browser.py b/qt/aqt/browser.py index 6ddf8c8c2..3e12f017a 100644 --- a/qt/aqt/browser.py +++ b/qt/aqt/browser.py @@ -589,6 +589,10 @@ class SidebarTreeView(QTreeView): self.expanded.connect(self.onExpansion) self.collapsed.connect(self.onCollapse) + self.setContextMenuPolicy(Qt.CustomContextMenu) + self.customContextMenuRequested.connect(self.onContextMenu) + self.context_menus = {SidebarItemType.DECK: ()} + def onClickCurrent(self) -> None: idx = self.currentIndex() if idx.isValid(): @@ -619,6 +623,19 @@ class SidebarTreeView(QTreeView): if item.onExpanded: item.onExpanded(expanded) + def onContextMenu(self, point: QPoint) -> None: + idx: QModelIndex = self.indexAt(point) + item: SidebarItem = idx.internalPointer() + 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]: + a = m.addAction(action[0]) + a.triggered.connect(action[1]) + m.exec_(QCursor.pos()) + # Browser window ###################################################################### @@ -1204,6 +1221,7 @@ QTableView {{ gridline-color: {grid} }} m["name"], ":/icons/notetype.svg", lambda m=m: self.setFilter("note", m["name"]), # type: ignore + item_type=SidebarItemType.NOTETYPE, ) root.addChild(item) From a6cd77ed6e33004b18d26c42af2c52f5220e430f Mon Sep 17 00:00:00 2001 From: BlueGreenMagick <50060875+BlueGreenMagick@users.noreply.github.com> Date: Tue, 28 Apr 2020 07:40:13 +0900 Subject: [PATCH 5/7] add deck rename context menu to sidebar --- qt/aqt/browser.py | 24 +++++++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) diff --git a/qt/aqt/browser.py b/qt/aqt/browser.py index 3e12f017a..58c8046e0 100644 --- a/qt/aqt/browser.py +++ b/qt/aqt/browser.py @@ -21,6 +21,7 @@ from anki.cards import Card from anki.collection import _Collection from anki.consts import * from anki.decks import DeckManager +from anki.errors import DeckRenameError from anki.lang import _, ngettext from anki.models import NoteType from anki.notes import Note @@ -591,7 +592,7 @@ class SidebarTreeView(QTreeView): self.setContextMenuPolicy(Qt.CustomContextMenu) self.customContextMenuRequested.connect(self.onContextMenu) - self.context_menus = {SidebarItemType.DECK: ()} + self.context_menus = {SidebarItemType.DECK: ((_("Rename"), self.rename_deck),)} def onClickCurrent(self) -> None: idx = self.currentIndex() @@ -632,10 +633,27 @@ class SidebarTreeView(QTreeView): m = QMenu() for action in self.context_menus[item_type]: - a = m.addAction(action[0]) - a.triggered.connect(action[1]) + act_name = action[0] + act_func = action[1] + a = m.addAction(act_name) + a.triggered.connect(lambda _, func=act_func: func(item)) m.exec_(QCursor.pos()) + def rename_deck(self, item: SidebarItem) -> None: + self.mw.checkpoint(_("Rename Deck")) + old_name = item.name + deck = self.mw.col.decks.byName(old_name) + new_name = getOnlyText(_("New deck name:"), default=old_name) + new_name = new_name.replace('"', "") + if not new_name or new_name == old_name: + return + try: + self.mw.col.decks.rename(deck, new_name) + self.browser.maybeRefreshSidebar() + except DeckRenameError as e: + return showWarning(e.description) + self.show() + # Browser window ###################################################################### From 48e4396c55e9a945041de2b95c9ad2e2b2890fd3 Mon Sep 17 00:00:00 2001 From: BlueGreenMagick <50060875+BlueGreenMagick@users.noreply.github.com> Date: Tue, 28 Apr 2020 09:06:54 +0900 Subject: [PATCH 6/7] make mypy ignore signal.connect lines --- qt/aqt/browser.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/qt/aqt/browser.py b/qt/aqt/browser.py index 58c8046e0..bf2c48cdc 100644 --- a/qt/aqt/browser.py +++ b/qt/aqt/browser.py @@ -582,16 +582,16 @@ class SidebarModel(QAbstractItemModel): class SidebarTreeView(QTreeView): - def __init__(self, browser: "Browser"): + def __init__(self, browser: "Browser") -> None: super().__init__() self.browser = browser self.mw = browser.mw self.col = self.mw.col - self.expanded.connect(self.onExpansion) - self.collapsed.connect(self.onCollapse) + self.expanded.connect(self.onExpansion) # type: ignore + self.collapsed.connect(self.onCollapse) # type: ignore self.setContextMenuPolicy(Qt.CustomContextMenu) - self.customContextMenuRequested.connect(self.onContextMenu) + self.customContextMenuRequested.connect(self.onContextMenu) # type: ignore self.context_menus = {SidebarItemType.DECK: ((_("Rename"), self.rename_deck),)} def onClickCurrent(self) -> None: @@ -636,7 +636,7 @@ class SidebarTreeView(QTreeView): act_name = action[0] act_func = action[1] a = m.addAction(act_name) - a.triggered.connect(lambda _, func=act_func: func(item)) + a.triggered.connect(lambda _, func=act_func: func(item)) # type: ignore m.exec_(QCursor.pos()) def rename_deck(self, item: SidebarItem) -> None: From 4f5fdc192abbaceeabcf514b794182d05526e1b5 Mon Sep 17 00:00:00 2001 From: abdo Date: Sat, 10 Oct 2020 04:42:49 +0300 Subject: [PATCH 7/7] Move new sidebar code to a separate file - Move the new sidebar code and SidebarTreeView implementation to a new file. Old sidebar can be accessed with the shift key. The "new" sidebar doesn't add much for now. - Make rename_deck work with subdecks - Fix an issue when trying to open context menu over areas not populated with sidebar items --- qt/aqt/browser.py | 116 +++++++++------------------------------------- qt/aqt/main.py | 4 +- qt/aqt/sidebar.py | 107 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 132 insertions(+), 95 deletions(-) create mode 100644 qt/aqt/sidebar.py diff --git a/qt/aqt/browser.py b/qt/aqt/browser.py index 2eceb5c2c..8d35b4d48 100644 --- a/qt/aqt/browser.py +++ b/qt/aqt/browser.py @@ -18,7 +18,6 @@ import aqt.forms from anki.cards import Card from anki.collection import Collection from anki.consts import * -from anki.errors import DeckRenameError from anki.lang import _, ngettext from anki.models import NoteType from anki.notes import Note @@ -32,6 +31,7 @@ from aqt.main import ResetReason from aqt.previewer import BrowserPreviewer as PreviewDialog from aqt.previewer import Previewer from aqt.qt import * +from aqt.sidebar import NewSidebarTreeView, SidebarItemType, SidebarTreeViewBase from aqt.theme import theme_manager from aqt.utils import ( MenuList, @@ -441,17 +441,6 @@ class SidebarStage(Enum): TAGS = 5 -class SidebarItemType(Enum): - ROOT = 0 - COLLECTION = 1 - CURRENT_DECK = 2 - FILTER = 3 - DECK = 4 - NOTETYPE = 5 - TAG = 6 - CUSTOM = 7 - - class SidebarItem: def __init__( self, @@ -461,15 +450,17 @@ class SidebarItem: onExpanded: Callable[[bool], None] = None, expanded: bool = False, item_type: SidebarItemType = SidebarItemType.CUSTOM, + id: int = 0, ) -> None: self.name = name self.icon = icon self.item_type = item_type + self.id = id self.onClick = onClick self.onExpanded = onExpanded self.expanded = expanded self.children: List["SidebarItem"] = [] - self.parentItem: Optional[SidebarItem] = None + self.parentItem: Optional["SidebarItem"] = None self.tooltip: Optional[str] = None def addChild(self, cb: "SidebarItem") -> None: @@ -582,83 +573,6 @@ class SidebarModel(QAbstractItemModel): # then ourselves tree.setExpanded(parent, True) - # Sidebar - ###################################################################### - - -class SidebarTreeView(QTreeView): - def __init__(self, browser: "Browser") -> None: - super().__init__() - self.browser = browser - self.mw = browser.mw - self.col = self.mw.col - self.expanded.connect(self.onExpansion) # type: ignore - self.collapsed.connect(self.onCollapse) # type: ignore - - self.setContextMenuPolicy(Qt.CustomContextMenu) - self.customContextMenuRequested.connect(self.onContextMenu) # type: ignore - self.context_menus = {SidebarItemType.DECK: ((_("Rename"), self.rename_deck),)} - - def onClickCurrent(self) -> None: - idx = self.currentIndex() - if idx.isValid(): - item: SidebarItem = idx.internalPointer() - if item.onClick: - item.onClick() - - def mouseReleaseEvent(self, event: QMouseEvent) -> None: - super().mouseReleaseEvent(event) - 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: SidebarItem = idx.internalPointer() - if item.expanded != expanded: - item.expanded = expanded - if item.onExpanded: - item.onExpanded(expanded) - - def onContextMenu(self, point: QPoint) -> None: - idx: QModelIndex = self.indexAt(point) - item: SidebarItem = idx.internalPointer() - 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: SidebarItem) -> None: - self.mw.checkpoint(_("Rename Deck")) - old_name = item.name - deck = self.mw.col.decks.byName(old_name) - new_name = getOnlyText(_("New deck name:"), default=old_name) - new_name = new_name.replace('"', "") - if not new_name or new_name == old_name: - return - try: - self.mw.col.decks.rename(deck, new_name) - self.browser.maybeRefreshSidebar() - except DeckRenameError as e: - return showWarning(e.description) - self.show() - # Browser window ###################################################################### @@ -672,9 +586,10 @@ class Browser(QMainWindow): col: Collection editor: Optional[Editor] - def __init__(self, mw: AnkiQt) -> None: + def __init__(self, mw: AnkiQt, want_old_sidebar: bool = False) -> None: QMainWindow.__init__(self, None, Qt.Window) self.mw = mw + self.want_old_sidebar = want_old_sidebar self.col = self.mw.col self.lastFilter = "" self.focusTo: Optional[int] = None @@ -1106,13 +1021,22 @@ QTableView {{ gridline-color: {grid} }} def onColumnMoved(self, a, b, c): self.setColumnSizes() + # implementation moved to sidebar.py. this is kept for compatibility + class SidebarTreeView(SidebarTreeViewBase): + pass def setupSidebar(self) -> None: dw = self.sidebarDockWidget = QDockWidget(_("Sidebar"), self) dw.setFeatures(QDockWidget.DockWidgetClosable) dw.setObjectName("Sidebar") dw.setAllowedAreas(Qt.LeftDockWidgetArea) - self.sidebarTree = SidebarTreeView(self) + + self.sidebarTree: SidebarTreeViewBase + if self.want_old_sidebar: + self.sidebarTree = self.SidebarTreeView() + else: + self.sidebarTree = NewSidebarTreeView(self) + self.sidebarTree.mw = self.mw self.sidebarTree.setUniformRowHeights(True) self.sidebarTree.setHeaderHidden(True) @@ -1198,7 +1122,7 @@ QTableView {{ gridline-color: {grid} }} name, ":/icons/heart.svg", lambda s=filt: self.setFilter(s), # type: ignore - item_type=SidebarItemType.DECK, + item_type=SidebarItemType.FILTER, ) root.addChild(item) @@ -1206,7 +1130,10 @@ QTableView {{ gridline-color: {grid} }} assert self.col for t in self.col.tags.all(): item = SidebarItem( - t, ":/icons/tag.svg", lambda t=t: self.setFilter("tag", t), item_type=SidebarItemType.TAG # type: ignore + t, + ":/icons/tag.svg", + lambda t=t: self.setFilter("tag", t), # type: ignore + item_type=SidebarItemType.TAG, # type: ignore ) root.addChild(item) @@ -1231,6 +1158,7 @@ QTableView {{ gridline-color: {grid} }} toggle_expand(), not node.collapsed, item_type=SidebarItemType.DECK, + id=node.deck_id, ) root.addChild(item) newhead = head + node.name + "::" diff --git a/qt/aqt/main.py b/qt/aqt/main.py index a20ea514e..b5708c672 100644 --- a/qt/aqt/main.py +++ b/qt/aqt/main.py @@ -1062,7 +1062,9 @@ title="%s" %s>%s""" % ( aqt.dialogs.open("AddCards", self) def onBrowse(self) -> None: - aqt.dialogs.open("Browser", self) + aqt.dialogs.open( + "Browser", self, self.app.queryKeyboardModifiers() & Qt.ShiftModifier + ) def onEditCurrent(self): aqt.dialogs.open("EditCurrent", self) diff --git a/qt/aqt/sidebar.py b/qt/aqt/sidebar.py new file mode 100644 index 000000000..8daf31090 --- /dev/null +++ b/qt/aqt/sidebar.py @@ -0,0 +1,107 @@ +# -*- 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 enum import Enum + +import aqt +from anki.errors import DeckRenameError +from anki.lang import _ +from aqt.qt import * +from aqt.utils import getOnlyText, showWarning + + +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) + 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: ((_("Rename"), self.rename_deck),), + } + + 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: + self.mw.checkpoint(_("Rename Deck")) + deck = self.mw.col.decks.get(item.id) + old_name = deck["name"] + new_name = getOnlyText(_("New deck name:"), default=old_name) + new_name = new_name.replace('"', "") + if not new_name or new_name == old_name: + return + try: + self.mw.col.decks.rename(deck, new_name) + self.browser.maybeRefreshSidebar() + except DeckRenameError as e: + return showWarning(e.description) + self.show()