From c96248d67f5984eb0ce2bd5c5089e8dcdbee3f5f Mon Sep 17 00:00:00 2001 From: abdo Date: Mon, 1 Feb 2021 18:29:15 +0300 Subject: [PATCH 01/10] Expand sidebar match trees one level See https://github.com/ankitects/anki/commit/132bb5ff365ccac00b9d4ac8ba7690bddd49c9b6 --- qt/aqt/sidebar.py | 30 +++++++++++++++++++++++++++++- 1 file changed, 29 insertions(+), 1 deletion(-) diff --git a/qt/aqt/sidebar.py b/qt/aqt/sidebar.py index bafc12ed9..85526e7d6 100644 --- a/qt/aqt/sidebar.py +++ b/qt/aqt/sidebar.py @@ -223,6 +223,21 @@ class FilterModel(QSortFilterProxyModel): return None return self.mapToSource(idx).internalPointer() + def _anyParentMatches(self, item: SidebarItem) -> bool: + if not item.parentItem: + return False + if self.parent().current_search.lower() in item.parentItem.name.lower(): + return True + return self._anyParentMatches(item.parentItem) + + def filterAcceptsRow(self, row: int, parent: QModelIndex) -> bool: + current_search = self.parent().current_search + if not current_search: + return False + current_search = current_search.lower() + item = self.sourceModel().index(row, 0, parent).internalPointer() + return current_search in item.name.lower() or self._anyParentMatches(item) + class SidebarSearchBar(QLineEdit): def __init__(self, sidebar: SidebarTreeView) -> None: @@ -339,7 +354,20 @@ class SidebarTreeView(QTreeView): # a better way than this? self.collapseAll() filter_model.setFilterFixedString(text) - self.expandAll() + self.expandMatches(self.rootIndex()) + + def expandMatches(self, parent: QModelIndex) -> bool: + "Expand match trees one level." + expand = False + for i in range(self.model().rowCount(parent)): + idx = self.model().index(i, 0, parent) + item = self.model().item_for_index(idx) + expandChild = self.expandMatches(idx) or ( + bool(item) and self.current_search.lower() in item.name.lower() + ) + expand |= expandChild + self.setExpanded(idx, expandChild) + return expand def drawRow( self, painter: QPainter, options: QStyleOptionViewItem, idx: QModelIndex From 3a8fce69dd36c95746224d8e2dbca6c2e0e71743 Mon Sep 17 00:00:00 2001 From: Damien Elmes Date: Tue, 2 Feb 2021 10:40:50 +1000 Subject: [PATCH 02/10] ditch QSortFilterProxyModel in favour of our own code Simpler and approximately twice as fast in a large collection: old approach search for a: 371ms search for an: 260ms new approach: search for a: 171ms search for an: 149ms Still todo: add enum defs for the other root categories, update the _section_root() calls, and update is_expanded() to use the new extra types --- qt/aqt/sidebar.py | 109 ++++++++++++++++++++-------------------------- 1 file changed, 47 insertions(+), 62 deletions(-) diff --git a/qt/aqt/sidebar.py b/qt/aqt/sidebar.py index 85526e7d6..32060b1fe 100644 --- a/qt/aqt/sidebar.py +++ b/qt/aqt/sidebar.py @@ -93,6 +93,8 @@ class SidebarItem: self.parentItem: Optional["SidebarItem"] = None self.tooltip: Optional[str] = None self.row_in_parent: Optional[int] = None + self._search_matches_self = False + self._search_matches_child = False def addChild(self, cb: "SidebarItem") -> None: self.children.append(cb) @@ -104,6 +106,30 @@ class SidebarItem: except ValueError: return None + def is_expanded(self, searching: bool) -> bool: + if not searching: + return self.expanded + else: + if self._search_matches_child: + return True + # if search matches top level, expand children one level + # FIXME: add types for other roots + return self._search_matches_self and self.item_type in ( + SidebarItemType.SAVED_SEARCH_ROOT, + SidebarItemType.DECK_ROOT, + ) + + def is_highlighted(self) -> bool: + return self._search_matches_self + + def search(self, lowered_text: str) -> bool: + "True if we or child matched." + self._search_matches_self = lowered_text in self.name.lower() + self._search_matches_child = any( + [child.search(lowered_text) for child in self.children] + ) + return self._search_matches_self or self._search_matches_child + class SidebarModel(QAbstractItemModel): def __init__(self, root: SidebarItem) -> None: @@ -120,6 +146,9 @@ class SidebarModel(QAbstractItemModel): def item_for_index(self, idx: QModelIndex) -> SidebarItem: return idx.internalPointer() + def search(self, text: str) -> None: + self.root.search(text.lower()) + # Qt API ###################################################################### @@ -204,39 +233,20 @@ class SidebarModel(QAbstractItemModel): def expand_where_necessary( - model: SidebarModel, tree: QTreeView, parent: Optional[QModelIndex] = None + model: SidebarModel, + tree: QTreeView, + parent: Optional[QModelIndex] = None, + searching: bool = False, ) -> None: parent = parent or QModelIndex() for row in range(model.rowCount(parent)): idx = model.index(row, 0, parent) if not idx.isValid(): continue - expand_where_necessary(model, tree, idx) - item = model.item_for_index(idx) - if item and item.expanded: - tree.setExpanded(idx, True) - - -class FilterModel(QSortFilterProxyModel): - def item_for_index(self, idx: QModelIndex) -> Optional[SidebarItem]: - if not idx.isValid(): - return None - return self.mapToSource(idx).internalPointer() - - def _anyParentMatches(self, item: SidebarItem) -> bool: - if not item.parentItem: - return False - if self.parent().current_search.lower() in item.parentItem.name.lower(): - return True - return self._anyParentMatches(item.parentItem) - - def filterAcceptsRow(self, row: int, parent: QModelIndex) -> bool: - current_search = self.parent().current_search - if not current_search: - return False - current_search = current_search.lower() - item = self.sourceModel().index(row, 0, parent).internalPointer() - return current_search in item.name.lower() or self._anyParentMatches(item) + expand_where_necessary(model, tree, idx, searching) + if item := model.item_for_index(idx): + if item.is_expanded(searching): + tree.setExpanded(idx, True) class SidebarSearchBar(QLineEdit): @@ -312,7 +322,7 @@ class SidebarTreeView(QTreeView): bgcolor = QPalette().window().color().name() self.setStyleSheet("QTreeView { background: '%s'; }" % bgcolor) - def model(self) -> Union[FilterModel, SidebarModel]: + def model(self) -> SidebarModel: return super().model() def refresh(self) -> None: @@ -340,47 +350,22 @@ class SidebarTreeView(QTreeView): self.current_search = None self.refresh() return - if not isinstance(self.model(), FilterModel): - filter_model = FilterModel(self) - filter_model.setSourceModel(self.model()) - filter_model.setFilterCaseSensitivity(False) # type: ignore - filter_model.setRecursiveFilteringEnabled(True) - self.setModel(filter_model) - else: - filter_model = self.model() self.current_search = text - # Without collapsing first, can be very slow. Surely there's - # a better way than this? + # start from a collapsed state, as it's faster self.collapseAll() - filter_model.setFilterFixedString(text) - self.expandMatches(self.rootIndex()) - - def expandMatches(self, parent: QModelIndex) -> bool: - "Expand match trees one level." - expand = False - for i in range(self.model().rowCount(parent)): - idx = self.model().index(i, 0, parent) - item = self.model().item_for_index(idx) - expandChild = self.expandMatches(idx) or ( - bool(item) and self.current_search.lower() in item.name.lower() - ) - expand |= expandChild - self.setExpanded(idx, expandChild) - return expand + self.model().search(text) + expand_where_necessary(self.model(), self, searching=True) def drawRow( self, painter: QPainter, options: QStyleOptionViewItem, idx: QModelIndex ) -> None: - if self.current_search is None: - return super().drawRow(painter, options, idx) - if not (item := self.model().item_for_index(idx)): - return super().drawRow(painter, options, idx) - if self.current_search.lower() in item.name.lower(): - brush = QBrush(theme_manager.qcolor("suspended-bg")) - painter.save() - painter.fillRect(options.rect, brush) - painter.restore() + if self.current_search and (item := self.model().item_for_index(idx)): + if item.is_highlighted(): + brush = QBrush(theme_manager.qcolor("suspended-bg")) + painter.save() + painter.fillRect(options.rect, brush) + painter.restore() return super().drawRow(painter, options, idx) def dropEvent(self, event: QDropEvent) -> None: From 6f5d1bca3fa5b1944175a8b743c4b41cf90ceb08 Mon Sep 17 00:00:00 2001 From: abdo Date: Tue, 2 Feb 2021 04:51:45 +0300 Subject: [PATCH 03/10] Add more sidebar section roots --- qt/aqt/sidebar.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/qt/aqt/sidebar.py b/qt/aqt/sidebar.py index 32060b1fe..2ede5180d 100644 --- a/qt/aqt/sidebar.py +++ b/qt/aqt/sidebar.py @@ -55,6 +55,8 @@ class SidebarItemType(Enum): TEMPLATE = 8 SAVED_SEARCH_ROOT = 9 DECK_ROOT = 10 + NOTETYPE_ROOT = 11 + TAG_ROOT = 12 # used by an add-on hook @@ -113,10 +115,11 @@ class SidebarItem: if self._search_matches_child: return True # if search matches top level, expand children one level - # FIXME: add types for other roots return self._search_matches_self and self.item_type in ( SidebarItemType.SAVED_SEARCH_ROOT, SidebarItemType.DECK_ROOT, + SidebarItemType.NOTETYPE_ROOT, + SidebarItemType.TAG_ROOT, ) def is_highlighted(self) -> bool: @@ -558,6 +561,7 @@ class SidebarTreeView(QTreeView): name=TR.BROWSING_SIDEBAR_TAGS, icon=icon, collapse_key=ConfigBoolKey.COLLAPSE_TAGS, + type=SidebarItemType.TAG_ROOT, ) render(root, tree.children) @@ -604,6 +608,7 @@ class SidebarTreeView(QTreeView): name=TR.BROWSING_SIDEBAR_NOTETYPES, icon=icon, collapse_key=ConfigBoolKey.COLLAPSE_NOTETYPES, + type=SidebarItemType.NOTETYPE_ROOT, ) for nt in sorted(self.col.models.all(), key=lambda nt: nt["name"].lower()): From ee1ed033a2f2a3da723258c600d88654ecf754e3 Mon Sep 17 00:00:00 2001 From: abdo Date: Tue, 2 Feb 2021 05:41:45 +0300 Subject: [PATCH 04/10] Hide sidebar items when there is no match --- qt/aqt/sidebar.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/qt/aqt/sidebar.py b/qt/aqt/sidebar.py index 2ede5180d..07f4281b3 100644 --- a/qt/aqt/sidebar.py +++ b/qt/aqt/sidebar.py @@ -149,8 +149,8 @@ class SidebarModel(QAbstractItemModel): def item_for_index(self, idx: QModelIndex) -> SidebarItem: return idx.internalPointer() - def search(self, text: str) -> None: - self.root.search(text.lower()) + def search(self, text: str) -> bool: + return self.root.search(text.lower()) # Qt API ###################################################################### @@ -349,6 +349,7 @@ class SidebarTreeView(QTreeView): self.mw.taskman.run_in_background(self._root_tree, on_done) def search_for(self, text: str) -> None: + self.showColumn(0) if not text.strip(): self.current_search = None self.refresh() @@ -357,7 +358,7 @@ class SidebarTreeView(QTreeView): self.current_search = text # start from a collapsed state, as it's faster self.collapseAll() - self.model().search(text) + self.setColumnHidden(0, not self.model().search(text)) expand_where_necessary(self.model(), self, searching=True) def drawRow( From 0bf253898931fc2c7923943473fd085f33dcad6e Mon Sep 17 00:00:00 2001 From: Damien Elmes Date: Tue, 2 Feb 2021 16:35:42 +1000 Subject: [PATCH 05/10] remove sidebar margins --- qt/aqt/browser.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/qt/aqt/browser.py b/qt/aqt/browser.py index 0b85bbccc..53f423ab5 100644 --- a/qt/aqt/browser.py +++ b/qt/aqt/browser.py @@ -914,6 +914,8 @@ QTableView {{ gridline-color: {grid} }} l = QVBoxLayout() l.addWidget(searchBar) l.addWidget(self.sidebar) + l.setContentsMargins(0, 0, 0, 0) + l.setSpacing(0) w = QWidget() w.setLayout(l) dw.setWidget(w) From 4b7d30f515e49bb57c1ac0067c7e5d0b1eb79dd0 Mon Sep 17 00:00:00 2001 From: Damien Elmes Date: Tue, 2 Feb 2021 16:47:05 +1000 Subject: [PATCH 06/10] tags start collapsed --- rslib/src/tags.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rslib/src/tags.rs b/rslib/src/tags.rs index 30fc6570c..cf209fa93 100644 --- a/rslib/src/tags.rs +++ b/rslib/src/tags.rs @@ -46,7 +46,7 @@ impl Tag { Tag { name, usn, - collapsed: false, + collapsed: true, } } } From 7d8448a3213e9c5a0d0360c75bafe17652e5d9db Mon Sep 17 00:00:00 2001 From: Damien Elmes Date: Tue, 2 Feb 2021 17:14:11 +1000 Subject: [PATCH 07/10] decks start collapsed --- rslib/src/decks/mod.rs | 6 +++++- rslib/src/filtered.rs | 6 +++++- rslib/src/storage/upgrades/mod.rs | 4 ++++ 3 files changed, 14 insertions(+), 2 deletions(-) diff --git a/rslib/src/decks/mod.rs b/rslib/src/decks/mod.rs index 707193534..e85061654 100644 --- a/rslib/src/decks/mod.rs +++ b/rslib/src/decks/mod.rs @@ -45,7 +45,11 @@ impl Deck { name: "".into(), mtime_secs: TimestampSecs(0), usn: Usn(0), - common: DeckCommon::default(), + common: DeckCommon { + study_collapsed: true, + browser_collapsed: true, + ..Default::default() + }, kind: DeckKind::Normal(norm), } } diff --git a/rslib/src/filtered.rs b/rslib/src/filtered.rs index bb528a8dc..36b0967c3 100644 --- a/rslib/src/filtered.rs +++ b/rslib/src/filtered.rs @@ -133,7 +133,11 @@ impl Deck { name: "".into(), mtime_secs: TimestampSecs(0), usn: Usn(0), - common: DeckCommon::default(), + common: DeckCommon { + study_collapsed: true, + browser_collapsed: true, + ..Default::default() + }, kind: DeckKind::Filtered(filt), } } diff --git a/rslib/src/storage/upgrades/mod.rs b/rslib/src/storage/upgrades/mod.rs index acccf7328..cb2b2ac81 100644 --- a/rslib/src/storage/upgrades/mod.rs +++ b/rslib/src/storage/upgrades/mod.rs @@ -35,6 +35,10 @@ impl SqliteStorage { self.upgrade_tags_to_schema17()?; self.db.execute_batch("update col set ver = 17")?; } + // fixme: on the next schema upgrade, change _collapsed to _expanded + // in DeckCommon and invert existing values, so that we can avoid + // serializing the values in the default case, and use + // DeckCommon::default() in new_normal() and new_filtered() Ok(()) } From 52b256663fc9733526ad0c0692308a2a90fa19c9 Mon Sep 17 00:00:00 2001 From: Damien Elmes Date: Tue, 2 Feb 2021 18:12:50 +1000 Subject: [PATCH 08/10] collapsed->expanded in TagTreeNode --- qt/aqt/sidebar.py | 2 +- rslib/backend.proto | 2 +- rslib/src/dbcheck.rs | 6 +++--- rslib/src/storage/tag/mod.rs | 8 ++++---- rslib/src/tags.rs | 9 +++++---- 5 files changed, 14 insertions(+), 13 deletions(-) diff --git a/qt/aqt/sidebar.py b/qt/aqt/sidebar.py index 07f4281b3..9bc5c80aa 100644 --- a/qt/aqt/sidebar.py +++ b/qt/aqt/sidebar.py @@ -548,7 +548,7 @@ class SidebarTreeView(QTreeView): icon, self._filter_func(SearchTerm(tag=head + node.name)), toggle_expand(), - not node.collapsed, + node.expanded, item_type=SidebarItemType.TAG, full_name=head + node.name, ) diff --git a/rslib/backend.proto b/rslib/backend.proto index 70e436a7c..526488c2b 100644 --- a/rslib/backend.proto +++ b/rslib/backend.proto @@ -865,7 +865,7 @@ message TagTreeNode { string name = 1; repeated TagTreeNode children = 2; uint32 level = 3; - bool collapsed = 4; + bool expanded = 4; } message SetConfigJsonIn { diff --git a/rslib/src/dbcheck.rs b/rslib/src/dbcheck.rs index 0ca55361b..cf7e7a203 100644 --- a/rslib/src/dbcheck.rs +++ b/rslib/src/dbcheck.rs @@ -242,7 +242,7 @@ impl Collection { let usn = self.usn()?; let stamp = TimestampMillis::now(); - let collapsed_tags = self.storage.collapsed_tags()?; + let expanded_tags = self.storage.expanded_tags()?; self.storage.clear_tags()?; let total_notes = self.storage.total_notes()?; @@ -296,7 +296,7 @@ impl Collection { // the note rebuilding process took care of adding tags back, so we just need // to ensure to restore the collapse state - self.storage.restore_collapsed_tags(&collapsed_tags)?; + self.storage.restore_expanded_tags(&expanded_tags)?; // if the collection is empty and the user has deleted all note types, ensure at least // one note type exists @@ -646,7 +646,7 @@ mod test { note.tags.push("two".into()); col.add_note(&mut note, DeckID(1))?; - col.set_tag_collapsed("two", true)?; + col.set_tag_collapsed("one", false)?; col.check_database(progress_fn)?; diff --git a/rslib/src/storage/tag/mod.rs b/rslib/src/storage/tag/mod.rs index e0f1b0bd4..3965097d4 100644 --- a/rslib/src/storage/tag/mod.rs +++ b/rslib/src/storage/tag/mod.rs @@ -24,17 +24,17 @@ impl SqliteStorage { .collect() } - pub(crate) fn collapsed_tags(&self) -> Result> { + pub(crate) fn expanded_tags(&self) -> Result> { self.db - .prepare_cached("select tag from tags where collapsed = true")? + .prepare_cached("select tag from tags where collapsed = false")? .query_and_then(NO_PARAMS, |r| r.get::<_, String>(0).map_err(Into::into))? .collect::>>() } - pub(crate) fn restore_collapsed_tags(&self, tags: &[String]) -> Result<()> { + pub(crate) fn restore_expanded_tags(&self, tags: &[String]) -> Result<()> { let mut stmt = self .db - .prepare_cached("update tags set collapsed = true where tag = ?")?; + .prepare_cached("update tags set collapsed = false where tag = ?")?; for tag in tags { stmt.execute(&[tag])?; } diff --git a/rslib/src/tags.rs b/rslib/src/tags.rs index cf209fa93..7994af592 100644 --- a/rslib/src/tags.rs +++ b/rslib/src/tags.rs @@ -171,7 +171,7 @@ fn add_child_nodes(tags: &mut Peekable>, parent: &mut name: (*split_name.last().unwrap()).into(), children: vec![], level: parent.level + 1, - collapsed: tag.collapsed, + expanded: !tag.collapsed, }); tags.next(); } @@ -273,13 +273,13 @@ impl Collection { } pub fn clear_unused_tags(&self) -> Result<()> { - let collapsed: HashSet<_> = self.storage.collapsed_tags()?.into_iter().collect(); + let expanded: HashSet<_> = self.storage.expanded_tags()?.into_iter().collect(); self.storage.clear_tags()?; let usn = self.usn()?; for name in self.storage.all_tags_in_notes()? { let name = normalize_tag_name(&name).into(); self.storage.register_tag(&Tag { - collapsed: collapsed.contains(&name), + collapsed: !expanded.contains(&name), name, usn, })?; @@ -503,6 +503,7 @@ mod test { name: name.into(), level, children, + ..Default::default() } } @@ -607,7 +608,7 @@ mod test { note.tags.push("two".into()); col.add_note(&mut note, DeckID(1))?; - col.set_tag_collapsed("two", true)?; + col.set_tag_collapsed("one", false)?; col.clear_unused_tags()?; assert_eq!(col.storage.get_tag("one")?.unwrap().collapsed, false); assert_eq!(col.storage.get_tag("two")?.unwrap().collapsed, true); From 8e0f69b71cb8840d6aea86c81dc2c755fba72be5 Mon Sep 17 00:00:00 2001 From: Damien Elmes Date: Tue, 2 Feb 2021 18:32:07 +1000 Subject: [PATCH 09/10] return tags as a string list directly; we don't need usn or collapse state --- pylib/anki/tags.py | 10 +++------- rslib/backend.proto | 16 +++++----------- rslib/src/backend/mod.rs | 21 +++++++++++---------- rslib/src/tags.rs | 22 +--------------------- 4 files changed, 20 insertions(+), 49 deletions(-) diff --git a/pylib/anki/tags.py b/pylib/anki/tags.py index 67ae46c20..7fa0d99ff 100644 --- a/pylib/anki/tags.py +++ b/pylib/anki/tags.py @@ -13,7 +13,7 @@ from __future__ import annotations import pprint import re -from typing import Collection, List, Match, Optional, Sequence, Tuple +from typing import Collection, List, Match, Optional, Sequence import anki # pylint: disable=unused-import import anki._backend.backend_pb2 as _pb @@ -28,19 +28,15 @@ class TagManager: def __init__(self, col: anki.collection.Collection) -> None: self.col = col.weakref() - # all tags + # legacy add-on code expects a List return type def all(self) -> List[str]: - return [t.name for t in self.col._backend.all_tags()] + return list(self.col._backend.all_tags()) def __repr__(self) -> str: d = dict(self.__dict__) del d["col"] return f"{super().__repr__()} {pprint.pformat(d, width=300)}" - # # List of (tag, usn) - def allItems(self) -> List[Tuple[str, int]]: - return [(t.name, t.usn) for t in self.col._backend.all_tags()] - def tree(self) -> TagTreeNode: return self.col._backend.tag_tree() diff --git a/rslib/backend.proto b/rslib/backend.proto index 526488c2b..88d9271e8 100644 --- a/rslib/backend.proto +++ b/rslib/backend.proto @@ -41,6 +41,10 @@ message Bool { bool val = 1; } +message StringList { + repeated string vals = 1; +} + // IDs used in RPC calls /////////////////////////////////////////////////////////// @@ -212,7 +216,7 @@ service BackendService { // tags rpc ClearUnusedTags(Empty) returns (Empty); - rpc AllTags(Empty) returns (AllTagsOut); + rpc AllTags(Empty) returns (StringList); rpc SetTagCollapsed(SetTagCollapsedIn) returns (Empty); rpc ClearTag(String) returns (Empty); rpc TagTree(Empty) returns (TagTreeNode); @@ -842,21 +846,11 @@ message AddOrUpdateDeckConfigLegacyIn { bool preserve_usn_and_mtime = 2; } -message AllTagsOut { - repeated Tag tags = 1; -} - message SetTagCollapsedIn { string name = 1; bool collapsed = 2; } -message Tag { - string name = 1; - sint32 usn = 2; - bool collapsed = 3; -} - message GetChangedTagsOut { repeated string tags = 1; } diff --git a/rslib/src/backend/mod.rs b/rslib/src/backend/mod.rs index 2f5894080..924235c05 100644 --- a/rslib/src/backend/mod.rs +++ b/rslib/src/backend/mod.rs @@ -1399,16 +1399,17 @@ impl BackendService for Backend { // tags //------------------------------------------------------------------- - fn all_tags(&self, _input: Empty) -> BackendResult { - let tags: Vec = self.with_col(|col| { - Ok(col - .storage - .all_tags()? - .into_iter() - .map(|t| t.into()) - .collect()) - })?; - Ok(pb::AllTagsOut { tags }) + fn all_tags(&self, _input: Empty) -> BackendResult { + Ok(pb::StringList { + vals: self.with_col(|col| { + Ok(col + .storage + .all_tags()? + .into_iter() + .map(|t| t.name) + .collect()) + })?, + }) } fn set_tag_collapsed(&self, input: pb::SetTagCollapsedIn) -> BackendResult { diff --git a/rslib/src/tags.rs b/rslib/src/tags.rs index 7994af592..1956b4e1e 100644 --- a/rslib/src/tags.rs +++ b/rslib/src/tags.rs @@ -2,7 +2,7 @@ // License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html use crate::{ - backend_proto::{Tag as TagProto, TagTreeNode}, + backend_proto::TagTreeNode, collection::Collection, err::{AnkiError, Result}, notes::{NoteID, TransformNoteOutput}, @@ -21,26 +21,6 @@ pub struct Tag { pub collapsed: bool, } -impl From for TagProto { - fn from(t: Tag) -> Self { - TagProto { - name: t.name, - usn: t.usn.0, - collapsed: t.collapsed, - } - } -} - -impl From for Tag { - fn from(t: TagProto) -> Self { - Tag { - name: t.name, - usn: Usn(t.usn), - collapsed: t.collapsed, - } - } -} - impl Tag { pub fn new(name: String, usn: Usn) -> Self { Tag { From 467064f873a0bdc2333a92fec1fe0a128f721913 Mon Sep 17 00:00:00 2001 From: Damien Elmes Date: Tue, 2 Feb 2021 18:49:34 +1000 Subject: [PATCH 10/10] collapsed->expanded in other tag uses for consistency --- pylib/anki/tags.py | 6 +++--- qt/aqt/sidebar.py | 4 ++-- rslib/backend.proto | 6 +++--- rslib/src/backend/mod.rs | 4 ++-- rslib/src/dbcheck.rs | 6 +++--- rslib/src/storage/tag/mod.rs | 4 ++-- rslib/src/tags.rs | 18 +++++++++--------- 7 files changed, 24 insertions(+), 24 deletions(-) diff --git a/pylib/anki/tags.py b/pylib/anki/tags.py index 7fa0d99ff..2eab6a3c8 100644 --- a/pylib/anki/tags.py +++ b/pylib/anki/tags.py @@ -68,9 +68,9 @@ class TagManager: res = self.col.db.list(query) return list(set(self.split(" ".join(res)))) - def set_collapsed(self, tag: str, collapsed: bool) -> None: - "Set browser collapse state for tag, registering the tag if missing." - self.col._backend.set_tag_collapsed(name=tag, collapsed=collapsed) + def set_expanded(self, tag: str, expanded: bool) -> None: + "Set browser expansion state for tag, registering the tag if missing." + self.col._backend.set_tag_expanded(name=tag, expanded=expanded) # Bulk addition/removal from notes ############################################################# diff --git a/qt/aqt/sidebar.py b/qt/aqt/sidebar.py index 9bc5c80aa..85b9614d0 100644 --- a/qt/aqt/sidebar.py +++ b/qt/aqt/sidebar.py @@ -539,8 +539,8 @@ class SidebarTreeView(QTreeView): def toggle_expand() -> Callable[[bool], None]: full_name = head + node.name # pylint: disable=cell-var-from-loop - return lambda expanded: self.mw.col.tags.set_collapsed( - full_name, not expanded + return lambda expanded: self.mw.col.tags.set_expanded( + full_name, expanded ) item = SidebarItem( diff --git a/rslib/backend.proto b/rslib/backend.proto index 88d9271e8..196add3a3 100644 --- a/rslib/backend.proto +++ b/rslib/backend.proto @@ -217,7 +217,7 @@ service BackendService { rpc ClearUnusedTags(Empty) returns (Empty); rpc AllTags(Empty) returns (StringList); - rpc SetTagCollapsed(SetTagCollapsedIn) returns (Empty); + rpc SetTagExpanded(SetTagExpandedIn) returns (Empty); rpc ClearTag(String) returns (Empty); rpc TagTree(Empty) returns (TagTreeNode); @@ -846,9 +846,9 @@ message AddOrUpdateDeckConfigLegacyIn { bool preserve_usn_and_mtime = 2; } -message SetTagCollapsedIn { +message SetTagExpandedIn { string name = 1; - bool collapsed = 2; + bool expanded = 2; } message GetChangedTagsOut { diff --git a/rslib/src/backend/mod.rs b/rslib/src/backend/mod.rs index 924235c05..cce55d3d1 100644 --- a/rslib/src/backend/mod.rs +++ b/rslib/src/backend/mod.rs @@ -1412,10 +1412,10 @@ impl BackendService for Backend { }) } - fn set_tag_collapsed(&self, input: pb::SetTagCollapsedIn) -> BackendResult { + fn set_tag_expanded(&self, input: pb::SetTagExpandedIn) -> BackendResult { self.with_col(|col| { col.transact(None, |col| { - col.set_tag_collapsed(&input.name, input.collapsed)?; + col.set_tag_expanded(&input.name, input.expanded)?; Ok(().into()) }) }) diff --git a/rslib/src/dbcheck.rs b/rslib/src/dbcheck.rs index cf7e7a203..9035de2f8 100644 --- a/rslib/src/dbcheck.rs +++ b/rslib/src/dbcheck.rs @@ -646,12 +646,12 @@ mod test { note.tags.push("two".into()); col.add_note(&mut note, DeckID(1))?; - col.set_tag_collapsed("one", false)?; + col.set_tag_expanded("one", true)?; col.check_database(progress_fn)?; - assert_eq!(col.storage.get_tag("one")?.unwrap().collapsed, false); - assert_eq!(col.storage.get_tag("two")?.unwrap().collapsed, true); + assert_eq!(col.storage.get_tag("one")?.unwrap().expanded, true); + assert_eq!(col.storage.get_tag("two")?.unwrap().expanded, false); Ok(()) } diff --git a/rslib/src/storage/tag/mod.rs b/rslib/src/storage/tag/mod.rs index 3965097d4..d3c56c2a2 100644 --- a/rslib/src/storage/tag/mod.rs +++ b/rslib/src/storage/tag/mod.rs @@ -11,7 +11,7 @@ fn row_to_tag(row: &Row) -> Result { Ok(Tag { name: row.get(0)?, usn: row.get(1)?, - collapsed: row.get(2)?, + expanded: !row.get(2)?, }) } @@ -52,7 +52,7 @@ impl SqliteStorage { pub(crate) fn register_tag(&self, tag: &Tag) -> Result<()> { self.db .prepare_cached(include_str!("add.sql"))? - .execute(params![tag.name, tag.usn, tag.collapsed])?; + .execute(params![tag.name, tag.usn, !tag.expanded])?; Ok(()) } diff --git a/rslib/src/tags.rs b/rslib/src/tags.rs index 1956b4e1e..87f50438b 100644 --- a/rslib/src/tags.rs +++ b/rslib/src/tags.rs @@ -18,7 +18,7 @@ use unicase::UniCase; pub struct Tag { pub name: String, pub usn: Usn, - pub collapsed: bool, + pub expanded: bool, } impl Tag { @@ -26,7 +26,7 @@ impl Tag { Tag { name, usn, - collapsed: true, + expanded: false, } } } @@ -151,7 +151,7 @@ fn add_child_nodes(tags: &mut Peekable>, parent: &mut name: (*split_name.last().unwrap()).into(), children: vec![], level: parent.level + 1, - expanded: !tag.collapsed, + expanded: tag.expanded, }); tags.next(); } @@ -259,7 +259,7 @@ impl Collection { for name in self.storage.all_tags_in_notes()? { let name = normalize_tag_name(&name).into(); self.storage.register_tag(&Tag { - collapsed: !expanded.contains(&name), + expanded: expanded.contains(&name), name, usn, })?; @@ -268,7 +268,7 @@ impl Collection { Ok(()) } - pub(crate) fn set_tag_collapsed(&self, name: &str, collapsed: bool) -> Result<()> { + pub(crate) fn set_tag_expanded(&self, name: &str, expanded: bool) -> Result<()> { let mut name = name; let tag; if self.storage.get_tag(name)?.is_none() { @@ -277,7 +277,7 @@ impl Collection { self.storage.register_tag(&tag)?; name = &tag.name; } - self.storage.set_tag_collapsed(name, collapsed) + self.storage.set_tag_collapsed(name, !expanded) } fn replace_tags_for_notes_inner( @@ -588,10 +588,10 @@ mod test { note.tags.push("two".into()); col.add_note(&mut note, DeckID(1))?; - col.set_tag_collapsed("one", false)?; + col.set_tag_expanded("one", true)?; col.clear_unused_tags()?; - assert_eq!(col.storage.get_tag("one")?.unwrap().collapsed, false); - assert_eq!(col.storage.get_tag("two")?.unwrap().collapsed, true); + assert_eq!(col.storage.get_tag("one")?.unwrap().expanded, true); + assert_eq!(col.storage.get_tag("two")?.unwrap().expanded, false); Ok(()) }