From 208c713e393ec6d27549977b427d25c743432b31 Mon Sep 17 00:00:00 2001 From: abdo Date: Wed, 27 Jan 2021 01:35:40 +0300 Subject: [PATCH] Add search bar to the sidebar https://github.com/ankitects/help-wanted/issues/6 --- qt/aqt/browser.py | 22 ++++++++++++++++++++-- qt/aqt/sidebar.py | 48 +++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 68 insertions(+), 2 deletions(-) diff --git a/qt/aqt/browser.py b/qt/aqt/browser.py index ee1576108..47c564ede 100644 --- a/qt/aqt/browser.py +++ b/qt/aqt/browser.py @@ -35,7 +35,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 SidebarTreeView +from aqt.sidebar import SidebarSearchBar, SidebarTreeView from aqt.theme import theme_manager from aqt.utils import ( TR, @@ -912,6 +912,17 @@ QTableView {{ gridline-color: {grid} }} self.sidebar = SidebarTreeView(self) self.sidebarTree = self.sidebar # legacy alias dw.setWidget(self.sidebar) + self.sidebar.searchBar = searchBar = SidebarSearchBar(self.sidebar) + qconnect( + QShortcut(QKeySequence("Ctrl+Shift+B"), self).activated, + self.focusSidebarSearchBar, + ) + l = QVBoxLayout() + l.addWidget(searchBar) + l.addWidget(self.sidebar) + w = QWidget() + w.setLayout(l) + dw.setWidget(w) self.sidebarDockWidget.setFloating(False) self.sidebarDockWidget.setTitleBarWidget(QWidget()) @@ -921,12 +932,19 @@ QTableView {{ gridline-color: {grid} }} # UI is more responsive self.mw.progress.timer(10, self.sidebar.refresh, False) - def focusSidebar(self) -> None: + def showSidebar(self) -> None: # workaround for PyQt focus bug self.editor.hideCompleters() self.sidebarDockWidget.setVisible(True) + + def focusSidebar(self) -> None: + self.showSidebar() self.sidebar.setFocus() + def focusSidebarSearchBar(self) -> None: + self.showSidebar() + self.sidebar.searchBar.setFocus() + # legacy def maybeRefreshSidebar(self) -> None: self.sidebar.refresh() diff --git a/qt/aqt/sidebar.py b/qt/aqt/sidebar.py index 0c68570e7..b6064c94a 100644 --- a/qt/aqt/sidebar.py +++ b/qt/aqt/sidebar.py @@ -4,6 +4,8 @@ from __future__ import annotations +import copy +import re from concurrent.futures import Future from enum import Enum from typing import Iterable, List, Optional @@ -177,6 +179,49 @@ class SidebarModel(QAbstractItemModel): # then ourselves tree.setExpanded(parent, True) + def flattened(self) -> SidebarModel: + "Returns a flattened representation of the model." + root = SidebarItem("", "", item_type=SidebarItemType.ROOT) + + def flatten_tree(children: Iterable[SidebarItem]): + for child in children: + child.name = child.full_name + root.addChild(child) + flatten_tree(child.children) + child.children = [] + + flatten_tree(copy.deepcopy(self.root.children)) + + return SidebarModel(root) + + +class SidebarSearchBar(QLineEdit): + def __init__(self, sidebar): + QLineEdit.__init__(self, sidebar) + self.sidebar = sidebar + qconnect(self.textChanged, self.onTextChanged) + + def onTextChanged(self, text: str): + if text == "": + self.sidebar.refresh() + else: + # show matched items in the sidebar + root = SidebarItem("", "", item_type=SidebarItemType.ROOT) + pattern = re.compile("(?i).*{}.*".format(re.escape(text))) + for item in self.sidebar.flattened_model.root.children: + if pattern.match(item.name) or pattern.match(item.full_name): + root.addChild(item) + + self.sidebar.setModel(SidebarModel(root)) + + def keyPressEvent(self, evt): + if evt.key() in (Qt.Key_Up, Qt.Key_Down): + self.sidebar.setFocus() + elif evt.key() in (Qt.Key_Enter, Qt.Key_Return): + self.onTextChanged(self.text()) + else: + QLineEdit.keyPressEvent(self, evt) + class SidebarTreeView(QTreeView): def __init__(self, browser: aqt.browser.Browser) -> None: @@ -222,6 +267,7 @@ class SidebarTreeView(QTreeView): def on_done(fut: Future): root = fut.result() model = SidebarModel(root) + self.flattened_model = model.flattened() self.setModel(model) model.expandWhereNeccessary(self) @@ -359,6 +405,7 @@ class SidebarTreeView(QTreeView): not node.collapsed, item_type=SidebarItemType.DECK, id=node.deck_id, + full_name=head + node.name, ) root.addChild(item) newhead = head + node.name + "::" @@ -384,6 +431,7 @@ class SidebarTreeView(QTreeView): ":/icons/notetype.svg", self._template_filter(nt["name"], c), item_type=SidebarItemType.TEMPLATE, + full_name=nt["name"] + "::" + tmpl["name"], ) item.addChild(child)