diff --git a/qt/aqt/browser/sidebar/item.py b/qt/aqt/browser/sidebar/item.py index 66e9f68e0..935719401 100644 --- a/qt/aqt/browser/sidebar/item.py +++ b/qt/aqt/browser/sidebar/item.py @@ -25,6 +25,7 @@ class SidebarItemType(Enum): NOTETYPE_ROOT = auto() NOTETYPE = auto() NOTETYPE_TEMPLATE = auto() + NOTETYPE_FIELD = auto() TAG_ROOT = auto() TAG_NONE = auto() TAG = auto() @@ -144,7 +145,10 @@ class SidebarItem: SidebarItemType.CARD_STATE, ): return self.name == other.name - elif self.item_type == SidebarItemType.NOTETYPE_TEMPLATE: + elif self.item_type in [ + SidebarItemType.NOTETYPE_TEMPLATE, + SidebarItemType.NOTETYPE_FIELD, + ]: return ( other.id == self.id and other._parent_item.id == self._parent_item.id diff --git a/qt/aqt/browser/sidebar/tree.py b/qt/aqt/browser/sidebar/tree.py index acf0dd982..4ac1cf23a 100644 --- a/qt/aqt/browser/sidebar/tree.py +++ b/qt/aqt/browser/sidebar/tree.py @@ -25,6 +25,7 @@ from aqt.browser.sidebar.model import SidebarModel from aqt.browser.sidebar.searchbar import SidebarSearchBar from aqt.browser.sidebar.toolbar import SidebarTool, SidebarToolbar from aqt.clayout import CardLayout +from aqt.fields import FieldDialog from aqt.flags import load_flags from aqt.models import Models from aqt.operations import CollectionOp, QueryOp @@ -805,7 +806,7 @@ class SidebarTreeView(QTreeView): notetype_icon = ":/icons/newspaper-variant-outline.svg" notetype_multiple_icon = ":/icons/newspaper-variant-multiple-outline.svg" template_icon = ":/icons/card-bulleted-outline.svg" - # field_icon = ":/icons/form-textbox.svg" + field_icon = ":/icons/form-textbox.svg" root = self._section_root( root=root, @@ -838,6 +839,19 @@ class SidebarTreeView(QTreeView): ) item.add_child(child) + for c, fld in enumerate(nt["flds"]): + child = SidebarItem( + fld["name"], + field_icon, + search_node=self.col.group_searches( + SearchNode(note=nt["name"]), SearchNode(field_name=fld["name"]) + ), + item_type=SidebarItemType.NOTETYPE_FIELD, + name_prefix=f"{nt['name']}::", + id=fld["ord"], + ) + item.add_child(child) + root.add_child(item) # Context menu @@ -867,6 +881,8 @@ class SidebarTreeView(QTreeView): ) elif item.item_type == SidebarItemType.NOTETYPE_TEMPLATE: menu.addAction(tr.notetypes_cards(), lambda: self.manage_template(item)) + elif item.item_type == SidebarItemType.NOTETYPE_FIELD: + menu.addAction(tr.notetypes_fields(), lambda: self.manage_fields(item)) elif item.item_type == SidebarItemType.SAVED_SEARCH_ROOT: menu.addAction( tr.browsing_sidebar_save_current_search(), self.save_current_search @@ -1108,6 +1124,10 @@ class SidebarTreeView(QTreeView): note = Note(self.col, self.col.models.get(NotetypeId(item._parent_item.id))) CardLayout(self.mw, note, ord=item.id, parent=self, fill_empty=True) + def manage_fields(self, item: SidebarItem) -> None: + notetype = self.mw.col.models.get(NotetypeId(item._parent_item.id)) + FieldDialog(self.mw, notetype, parent=self, open_at=item.id) + # Helpers #################################### diff --git a/qt/aqt/fields.py b/qt/aqt/fields.py index 679957705..faac707d7 100644 --- a/qt/aqt/fields.py +++ b/qt/aqt/fields.py @@ -24,7 +24,11 @@ from aqt.utils import ( class FieldDialog(QDialog): def __init__( - self, mw: AnkiQt, nt: NotetypeDict, parent: Optional[QWidget] = None + self, + mw: AnkiQt, + nt: NotetypeDict, + parent: Optional[QWidget] = None, + open_at=0, ) -> None: QDialog.__init__(self, parent or mw) self.mw = mw @@ -47,7 +51,7 @@ class FieldDialog(QDialog): self.setupSignals() self.form.fieldList.setDragDropMode(QAbstractItemView.InternalMove) self.form.fieldList.dropEvent = self.onDrop # type: ignore[assignment] - self.form.fieldList.setCurrentRow(0) + self.form.fieldList.setCurrentRow(open_at) self.exec_() ########################################################################## diff --git a/rslib/src/backend/search/search_node.rs b/rslib/src/backend/search/search_node.rs index 0616e89fc..d184dc66f 100644 --- a/rslib/src/backend/search/search_node.rs +++ b/rslib/src/backend/search/search_node.rs @@ -42,7 +42,7 @@ impl TryFrom for Node { }), Filter::FieldName(s) => Node::Search(SearchNode::SingleField { field: escape_anki_wildcards_for_search_node(&s), - text: "*".to_string(), + text: "_*".to_string(), is_re: false, }), Filter::Rated(rated) => Node::Search(SearchNode::Rated {