mirror of
https://github.com/ankitects/anki.git
synced 2025-09-19 06:22:22 -04:00
hideable sidebar
- rely on restoreGeom() to preserve visibility - case-insensitive sort on tags
This commit is contained in:
parent
ad6dcde531
commit
c8127ee606
7 changed files with 128 additions and 0 deletions
115
aqt/browser.py
115
aqt/browser.py
|
@ -373,6 +373,7 @@ class Browser(QMainWindow):
|
||||||
self._closeEventHasCleanedUp = False
|
self._closeEventHasCleanedUp = False
|
||||||
self.form = aqt.forms.browser.Ui_Dialog()
|
self.form = aqt.forms.browser.Ui_Dialog()
|
||||||
self.form.setupUi(self)
|
self.form.setupUi(self)
|
||||||
|
self.setupSidebar()
|
||||||
restoreGeom(self, "editor", 0)
|
restoreGeom(self, "editor", 0)
|
||||||
restoreState(self, "editor")
|
restoreState(self, "editor")
|
||||||
restoreSplitter(self.form.splitter, "editor3")
|
restoreSplitter(self.form.splitter, "editor3")
|
||||||
|
@ -430,6 +431,7 @@ class Browser(QMainWindow):
|
||||||
f.actionFind.triggered.connect(self.onFind)
|
f.actionFind.triggered.connect(self.onFind)
|
||||||
f.actionNote.triggered.connect(self.onNote)
|
f.actionNote.triggered.connect(self.onNote)
|
||||||
f.actionTags.triggered.connect(self.onFilterButton)
|
f.actionTags.triggered.connect(self.onFilterButton)
|
||||||
|
f.actionSidebar.triggered.connect(self.focusSidebar)
|
||||||
f.actionCardList.triggered.connect(self.onCardList)
|
f.actionCardList.triggered.connect(self.onCardList)
|
||||||
# help
|
# help
|
||||||
f.actionGuide.triggered.connect(self.onHelp)
|
f.actionGuide.triggered.connect(self.onHelp)
|
||||||
|
@ -493,6 +495,8 @@ class Browser(QMainWindow):
|
||||||
"Show answer on RET or register answer."
|
"Show answer on RET or register answer."
|
||||||
if evt.key() == Qt.Key_Escape:
|
if evt.key() == Qt.Key_Escape:
|
||||||
self.close()
|
self.close()
|
||||||
|
else:
|
||||||
|
super().keyPressEvent(evt)
|
||||||
|
|
||||||
def setupColumns(self):
|
def setupColumns(self):
|
||||||
self.columns = [
|
self.columns = [
|
||||||
|
@ -743,6 +747,109 @@ by clicking on one on the left."""))
|
||||||
def onColumnMoved(self, a, b, c):
|
def onColumnMoved(self, a, b, c):
|
||||||
self.setColumnSizes()
|
self.setColumnSizes()
|
||||||
|
|
||||||
|
# Sidebar
|
||||||
|
######################################################################
|
||||||
|
|
||||||
|
class CallbackItem(QTreeWidgetItem):
|
||||||
|
def __init__(self, root, name, onclick, oncollapse=None, expanded=False):
|
||||||
|
QTreeWidgetItem.__init__(self, root, [name])
|
||||||
|
self.setExpanded(expanded)
|
||||||
|
self.onclick = onclick
|
||||||
|
self.oncollapse = oncollapse
|
||||||
|
|
||||||
|
class SidebarTreeWidget(QTreeWidget):
|
||||||
|
def __init__(self):
|
||||||
|
QTreeWidget.__init__(self)
|
||||||
|
self.itemClicked.connect(self.onTreeClick)
|
||||||
|
self.itemExpanded.connect(lambda item: self.onTreeCollapse(item))
|
||||||
|
self.itemCollapsed.connect(lambda item: self.onTreeCollapse(item))
|
||||||
|
|
||||||
|
def keyPressEvent(self, evt):
|
||||||
|
if evt.key() in (Qt.Key_Return, Qt.Key_Enter):
|
||||||
|
item = self.currentItem()
|
||||||
|
self.onTreeClick(item, 0)
|
||||||
|
else:
|
||||||
|
super().keyPressEvent(evt)
|
||||||
|
|
||||||
|
def onTreeClick(self, item, col):
|
||||||
|
if getattr(item, 'onclick', None):
|
||||||
|
item.onclick()
|
||||||
|
|
||||||
|
def onTreeCollapse(self, item):
|
||||||
|
if getattr(item, 'oncollapse', None):
|
||||||
|
item.oncollapse()
|
||||||
|
|
||||||
|
def setupSidebar(self):
|
||||||
|
dw = self.sidebarDockWidget = QDockWidget(_("Sidebar"), self)
|
||||||
|
dw.setFeatures(QDockWidget.DockWidgetClosable)
|
||||||
|
dw.setObjectName("Sidebar")
|
||||||
|
dw.setAllowedAreas(Qt.LeftDockWidgetArea)
|
||||||
|
self.sidebarTree = self.SidebarTreeWidget()
|
||||||
|
self.sidebarTree.mw = self.mw
|
||||||
|
self.sidebarTree.setFrameShape(QFrame.NoFrame)
|
||||||
|
self.sidebarTree.header().setVisible(False)
|
||||||
|
dw.setWidget(self.sidebarTree)
|
||||||
|
p = QPalette()
|
||||||
|
p.setColor(QPalette.Base, p.window().color())
|
||||||
|
self.sidebarTree.setPalette(p)
|
||||||
|
self.sidebarTree.setVisible(True)
|
||||||
|
self.sidebarDockWidget.visibilityChanged.connect(self.onSidebarVisChanged)
|
||||||
|
|
||||||
|
def onSidebarVisChanged(self, visible):
|
||||||
|
if visible:
|
||||||
|
self.buildTree()
|
||||||
|
else:
|
||||||
|
pass
|
||||||
|
|
||||||
|
def focusSidebar(self):
|
||||||
|
self.sidebarDockWidget.setVisible(True)
|
||||||
|
self.sidebarTree.setFocus()
|
||||||
|
|
||||||
|
def maybeRefreshSidebar(self):
|
||||||
|
if self.sidebarDockWidget.isVisible():
|
||||||
|
self.buildTree()
|
||||||
|
|
||||||
|
def buildTree(self):
|
||||||
|
self.sidebarTree.clear()
|
||||||
|
root = self.sidebarTree
|
||||||
|
self._favTree(root)
|
||||||
|
self._decksTree(root)
|
||||||
|
self._modelTree(root)
|
||||||
|
self._userTagTree(root)
|
||||||
|
self.sidebarTree.setIndentation(15)
|
||||||
|
|
||||||
|
def _favTree(self, root):
|
||||||
|
saved = self.col.conf.get('savedFilters', {})
|
||||||
|
for name, filt in sorted(saved.items()):
|
||||||
|
item = self.CallbackItem(root, name, lambda s=filt: self.setFilter(s))
|
||||||
|
item.setIcon(0, QIcon(":/icons/heart.png"))
|
||||||
|
|
||||||
|
def _userTagTree(self, root):
|
||||||
|
for t in sorted(self.col.tags.all(), key=lambda t: t.lower()):
|
||||||
|
item = self.CallbackItem(
|
||||||
|
root, t, lambda t=t: self.setFilter("tag", t))
|
||||||
|
item.setIcon(0, QIcon(":/icons/tag.png"))
|
||||||
|
|
||||||
|
def _decksTree(self, root):
|
||||||
|
grps = self.col.sched.deckDueTree()
|
||||||
|
def fillGroups(root, grps, head=""):
|
||||||
|
for g in grps:
|
||||||
|
item = self.CallbackItem(
|
||||||
|
root, g[0],
|
||||||
|
lambda g=g: self.setFilter("deck", head+g[0]),
|
||||||
|
lambda g=g: self.mw.col.decks.collapseBrowser(g[1]),
|
||||||
|
not self.mw.col.decks.get(g[1]).get('browserCollapsed', False))
|
||||||
|
item.setIcon(0, QIcon(":/icons/deck.png"))
|
||||||
|
newhead = head + g[0]+"::"
|
||||||
|
fillGroups(item, g[5], newhead)
|
||||||
|
fillGroups(root, grps)
|
||||||
|
|
||||||
|
def _modelTree(self, root):
|
||||||
|
for m in sorted(self.col.models.all(), key=itemgetter("name")):
|
||||||
|
mitem = self.CallbackItem(
|
||||||
|
root, m['name'], lambda m=m: self.setFilter("mid", str(m['id'])))
|
||||||
|
mitem.setIcon(0, QIcon(":/icons/notetype.png"))
|
||||||
|
|
||||||
# Filter tree
|
# Filter tree
|
||||||
######################################################################
|
######################################################################
|
||||||
|
|
||||||
|
@ -758,6 +865,10 @@ by clicking on one on the left."""))
|
||||||
self._addNoteTypeFilters(m)
|
self._addNoteTypeFilters(m)
|
||||||
self._addTagFilters(m)
|
self._addTagFilters(m)
|
||||||
|
|
||||||
|
m.addSeparator()
|
||||||
|
m.addAction(self.sidebarDockWidget.toggleViewAction())
|
||||||
|
m.addSeparator()
|
||||||
|
|
||||||
self._addSavedSearches(m)
|
self._addSavedSearches(m)
|
||||||
|
|
||||||
m.exec_(self.form.filter.mapToGlobal(QPoint(0,0)))
|
m.exec_(self.form.filter.mapToGlobal(QPoint(0,0)))
|
||||||
|
@ -1469,12 +1580,16 @@ update cards set usn=?, mod=?, did=? where id in """ + scids,
|
||||||
addHook("reset", self.onReset)
|
addHook("reset", self.onReset)
|
||||||
addHook("editTimer", self.refreshCurrentCard)
|
addHook("editTimer", self.refreshCurrentCard)
|
||||||
addHook("editFocusLost", self.refreshCurrentCardFilter)
|
addHook("editFocusLost", self.refreshCurrentCardFilter)
|
||||||
|
for t in "newTag", "newModel", "newDeck":
|
||||||
|
addHook(t, self.maybeRefreshSidebar)
|
||||||
|
|
||||||
def teardownHooks(self):
|
def teardownHooks(self):
|
||||||
remHook("reset", self.onReset)
|
remHook("reset", self.onReset)
|
||||||
remHook("editTimer", self.refreshCurrentCard)
|
remHook("editTimer", self.refreshCurrentCard)
|
||||||
remHook("editFocusLost", self.refreshCurrentCardFilter)
|
remHook("editFocusLost", self.refreshCurrentCardFilter)
|
||||||
remHook("undoState", self.onUndoState)
|
remHook("undoState", self.onUndoState)
|
||||||
|
for t in "newTag", "newModel", "newDeck":
|
||||||
|
remHook(t, self.maybeRefreshSidebar)
|
||||||
|
|
||||||
def onUndoState(self, on):
|
def onUndoState(self, on):
|
||||||
self.form.actionUndo.setEnabled(on)
|
self.form.actionUndo.setEnabled(on)
|
||||||
|
|
|
@ -250,6 +250,7 @@
|
||||||
</property>
|
</property>
|
||||||
<addaction name="actionFind"/>
|
<addaction name="actionFind"/>
|
||||||
<addaction name="actionTags"/>
|
<addaction name="actionTags"/>
|
||||||
|
<addaction name="actionSidebar"/>
|
||||||
<addaction name="actionNote"/>
|
<addaction name="actionNote"/>
|
||||||
<addaction name="actionCardList"/>
|
<addaction name="actionCardList"/>
|
||||||
<addaction name="separator"/>
|
<addaction name="separator"/>
|
||||||
|
@ -553,6 +554,14 @@
|
||||||
<string>Ctrl+4</string>
|
<string>Ctrl+4</string>
|
||||||
</property>
|
</property>
|
||||||
</action>
|
</action>
|
||||||
|
<action name="actionSidebar">
|
||||||
|
<property name="text">
|
||||||
|
<string>Sidebar</string>
|
||||||
|
</property>
|
||||||
|
<property name="shortcut">
|
||||||
|
<string>Ctrl+Shift+R</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
</widget>
|
</widget>
|
||||||
<resources>
|
<resources>
|
||||||
<include location="icons.qrc"/>
|
<include location="icons.qrc"/>
|
||||||
|
|
|
@ -1,5 +1,9 @@
|
||||||
<RCC>
|
<RCC>
|
||||||
<qresource prefix="/">
|
<qresource prefix="/">
|
||||||
<file>icons/anki.png</file>
|
<file>icons/anki.png</file>
|
||||||
|
<file>icons/tag.png</file>
|
||||||
|
<file>icons/deck.png</file>
|
||||||
|
<file>icons/notetype.png</file>
|
||||||
|
<file>icons/heart.png</file>
|
||||||
</qresource>
|
</qresource>
|
||||||
</RCC>
|
</RCC>
|
||||||
|
|
BIN
designer/icons/deck.png
Normal file
BIN
designer/icons/deck.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.3 KiB |
BIN
designer/icons/heart.png
Normal file
BIN
designer/icons/heart.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.7 KiB |
BIN
designer/icons/notetype.png
Normal file
BIN
designer/icons/notetype.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 922 B |
BIN
designer/icons/tag.png
Normal file
BIN
designer/icons/tag.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1 KiB |
Loading…
Reference in a new issue