mirror of
https://github.com/ankitects/anki.git
synced 2025-09-20 06:52:21 -04:00
Merge pull request #447 from glutanimate/browser-sidebar-tree-hooks
Add browser_will_build_tree filter
This commit is contained in:
commit
0ec3bbe1af
3 changed files with 175 additions and 5 deletions
|
@ -11,6 +11,7 @@ import sre_constants
|
|||
import time
|
||||
import unicodedata
|
||||
from dataclasses import dataclass
|
||||
from enum import Enum
|
||||
from operator import itemgetter
|
||||
from typing import Callable, List, Optional, Union
|
||||
|
||||
|
@ -418,6 +419,15 @@ class StatusDelegate(QItemDelegate):
|
|||
######################################################################
|
||||
|
||||
|
||||
class SidebarStage(Enum):
|
||||
ROOT = 0
|
||||
STANDARD = 1
|
||||
FAVORITES = 2
|
||||
DECKS = 3
|
||||
MODELS = 4
|
||||
TAGS = 5
|
||||
|
||||
|
||||
class SidebarItem:
|
||||
def __init__(
|
||||
self,
|
||||
|
@ -1085,11 +1095,27 @@ by clicking on one on the left."""
|
|||
|
||||
def buildTree(self) -> SidebarItem:
|
||||
root = SidebarItem("", "")
|
||||
self._stdTree(root)
|
||||
self._favTree(root)
|
||||
self._decksTree(root)
|
||||
self._modelTree(root)
|
||||
self._userTagTree(root)
|
||||
|
||||
handled = gui_hooks.browser_will_build_tree(
|
||||
False, root, SidebarStage.ROOT, self
|
||||
)
|
||||
if handled:
|
||||
return root
|
||||
|
||||
for stage, builder in zip(
|
||||
list(SidebarStage)[1:],
|
||||
(
|
||||
self._stdTree,
|
||||
self._favTree,
|
||||
self._decksTree,
|
||||
self._modelTree,
|
||||
self._userTagTree,
|
||||
),
|
||||
):
|
||||
handled = gui_hooks.browser_will_build_tree(False, root, stage, self)
|
||||
if not handled and builder:
|
||||
builder(root)
|
||||
|
||||
return root
|
||||
|
||||
def _stdTree(self, root) -> None:
|
||||
|
|
|
@ -203,6 +203,105 @@ class _BrowserMenusDidInitHook:
|
|||
browser_menus_did_init = _BrowserMenusDidInitHook()
|
||||
|
||||
|
||||
class _BrowserWillBuildTreeFilter:
|
||||
"""Used to add or replace items in the browser sidebar tree
|
||||
|
||||
'tree' is the root SidebarItem that all other items are added to.
|
||||
|
||||
'stage' is an enum describing the different construction stages of
|
||||
the sidebar tree at which you can interject your changes.
|
||||
The different values can be inspected by looking at
|
||||
aqt.browser.SidebarStage.
|
||||
|
||||
If you want Anki to proceed with the construction of the tree stage
|
||||
in question after your have performed your changes or additions,
|
||||
return the 'handled' boolean unchanged.
|
||||
|
||||
On the other hand, if you want to prevent Anki from adding its own
|
||||
items at a particular construction stage (e.g. in case your add-on
|
||||
implements its own version of that particular stage), return 'True'.
|
||||
|
||||
If you return 'True' at SidebarStage.ROOT, the sidebar will not be
|
||||
populated by any of the other construction stages. For any other stage
|
||||
the tree construction will just continue as usual.
|
||||
|
||||
For example, if your code wishes to replace the tag tree, you could do:
|
||||
|
||||
def on_browser_will_build_tree(handled, root, stage, browser):
|
||||
if stage != SidebarStage.TAGS:
|
||||
# not at tag tree building stage, pass on
|
||||
return handled
|
||||
|
||||
# your tag tree construction code
|
||||
# root.addChild(...)
|
||||
|
||||
# your code handled tag tree construction, no need for Anki
|
||||
# or other add-ons to build the tag tree
|
||||
return True
|
||||
"""
|
||||
|
||||
_hooks: List[
|
||||
Callable[
|
||||
[
|
||||
bool,
|
||||
"aqt.browser.SidebarItem",
|
||||
"aqt.browser.SidebarStage",
|
||||
"aqt.browser.Browser",
|
||||
],
|
||||
bool,
|
||||
]
|
||||
] = []
|
||||
|
||||
def append(
|
||||
self,
|
||||
cb: Callable[
|
||||
[
|
||||
bool,
|
||||
"aqt.browser.SidebarItem",
|
||||
"aqt.browser.SidebarStage",
|
||||
"aqt.browser.Browser",
|
||||
],
|
||||
bool,
|
||||
],
|
||||
) -> None:
|
||||
"""(handled: bool, tree: aqt.browser.SidebarItem, stage: aqt.browser.SidebarStage, browser: aqt.browser.Browser)"""
|
||||
self._hooks.append(cb)
|
||||
|
||||
def remove(
|
||||
self,
|
||||
cb: Callable[
|
||||
[
|
||||
bool,
|
||||
"aqt.browser.SidebarItem",
|
||||
"aqt.browser.SidebarStage",
|
||||
"aqt.browser.Browser",
|
||||
],
|
||||
bool,
|
||||
],
|
||||
) -> None:
|
||||
if cb in self._hooks:
|
||||
self._hooks.remove(cb)
|
||||
|
||||
def __call__(
|
||||
self,
|
||||
handled: bool,
|
||||
tree: aqt.browser.SidebarItem,
|
||||
stage: aqt.browser.SidebarStage,
|
||||
browser: aqt.browser.Browser,
|
||||
) -> bool:
|
||||
for filter in self._hooks:
|
||||
try:
|
||||
handled = filter(handled, tree, stage, browser)
|
||||
except:
|
||||
# if the hook fails, remove it
|
||||
self._hooks.remove(filter)
|
||||
raise
|
||||
return handled
|
||||
|
||||
|
||||
browser_will_build_tree = _BrowserWillBuildTreeFilter()
|
||||
|
||||
|
||||
class _BrowserWillShowContextMenuHook:
|
||||
_hooks: List[Callable[["aqt.browser.Browser", QMenu], None]] = []
|
||||
|
||||
|
|
|
@ -98,6 +98,51 @@ hooks = [
|
|||
args=["browser: aqt.browser.Browser"],
|
||||
legacy_hook="browser.rowChanged",
|
||||
),
|
||||
Hook(
|
||||
name="browser_will_build_tree",
|
||||
args=[
|
||||
"handled: bool",
|
||||
"tree: aqt.browser.SidebarItem",
|
||||
"stage: aqt.browser.SidebarStage",
|
||||
"browser: aqt.browser.Browser",
|
||||
],
|
||||
return_type="bool",
|
||||
doc="""Used to add or replace items in the browser sidebar tree
|
||||
|
||||
'tree' is the root SidebarItem that all other items are added to.
|
||||
|
||||
'stage' is an enum describing the different construction stages of
|
||||
the sidebar tree at which you can interject your changes.
|
||||
The different values can be inspected by looking at
|
||||
aqt.browser.SidebarStage.
|
||||
|
||||
If you want Anki to proceed with the construction of the tree stage
|
||||
in question after your have performed your changes or additions,
|
||||
return the 'handled' boolean unchanged.
|
||||
|
||||
On the other hand, if you want to prevent Anki from adding its own
|
||||
items at a particular construction stage (e.g. in case your add-on
|
||||
implements its own version of that particular stage), return 'True'.
|
||||
|
||||
If you return 'True' at SidebarStage.ROOT, the sidebar will not be
|
||||
populated by any of the other construction stages. For any other stage
|
||||
the tree construction will just continue as usual.
|
||||
|
||||
For example, if your code wishes to replace the tag tree, you could do:
|
||||
|
||||
def on_browser_will_build_tree(handled, root, stage, browser):
|
||||
if stage != SidebarStage.TAGS:
|
||||
# not at tag tree building stage, pass on
|
||||
return handled
|
||||
|
||||
# your tag tree construction code
|
||||
# root.addChild(...)
|
||||
|
||||
# your code handled tag tree construction, no need for Anki
|
||||
# or other add-ons to build the tag tree
|
||||
return True
|
||||
""",
|
||||
),
|
||||
# States
|
||||
###################
|
||||
Hook(
|
||||
|
|
Loading…
Reference in a new issue