From e6c02ec611f26bf8a9736561f7439ecbce57d4cf Mon Sep 17 00:00:00 2001 From: Charles Haley Date: Sat, 17 Oct 2020 12:50:46 +0100 Subject: [PATCH 1/2] Make the tag browser expand and collapse menu items consistent. 1) add separate lines to expand item and expand item and children 2) add collapse lines for all parent nodes, not just the immediate parent and the category root --- src/calibre/gui2/tag_browser/view.py | 88 ++++++++++++++++------------ 1 file changed, 49 insertions(+), 39 deletions(-) diff --git a/src/calibre/gui2/tag_browser/view.py b/src/calibre/gui2/tag_browser/view.py index 7ec1513ca7..c4e6e5c917 100644 --- a/src/calibre/gui2/tag_browser/view.py +++ b/src/calibre/gui2/tag_browser/view.py @@ -806,19 +806,6 @@ class TagsView(QTreeView): # {{{ _('Manage User categories'), partial(self.context_menu_handler, action='manage_categories', category=None)) - - node_name = tag_item.tag.name - parent = tag_item.parent - if parent.type != TagTreeItem.ROOT: - # We have an internal node. Find its immediate parent - parent_index = self._model.parent(index) - parent_node = parent - parent_name = parent.tag.name - else: - # We have a top-level node. - parent_index = index - parent_node = tag_item - parent_name = tag_item.name if self.hidden_categories: if not self.context_menu.isEmpty(): self.context_menu.addSeparator() @@ -850,47 +837,70 @@ class TagsView(QTreeView): # {{{ da.setToolTip('*') pa.setToolTip('*') + # Add expand menu items + node_name = self._model.get_node(index).tag.name self.context_menu.addSeparator() - if index.isValid() and self.model().rowCount(index) > 0: - if self.isExpanded(index): - self.context_menu.addAction(_("Collapse {0}").format(node_name), - partial(self.collapse_node, index)) - else: - self.context_menu.addAction(_('Expand {0}').format(node_name), - partial(self.expand_node_and_descendants, index)) - if parent_index is not None and parent_index != index: - if self.isExpanded(parent_index): - # Don't bother to collapse if it isn't expanded - self.context_menu.addAction(_("Collapse {0}").format(parent_name), - partial(self.collapse_node, parent_index)) - if parent_node.parent.type != TagTreeItem.ROOT: - # Add the top level node if the current parent is an internal node - while parent_node.parent.type != TagTreeItem.ROOT: - parent_node = parent_node.parent - idx = self._model.index_for_category(parent_node.category_key) - self.context_menu.addAction(_("Collapse {0}").format(parent_node.name), - partial(self.collapse_node, idx)) + if self.has_children(index) and not self.isExpanded(index): + self.context_menu.addAction(_('Expand {0}').format(node_name), + partial(self.expand, index)) + if self.has_unexpanded_children(index): + self.context_menu.addAction(_('Expand {0} and all children').format(node_name), + partial(self.expand_node_and_children, index)) + + # Add menu items to collapse parent nodes + idx = index + paths = [] + while True: + # First walk up the node tree getting the displayed names of + # expanded parent nodes + node = self._model.get_node(idx) + if node.type == TagTreeItem.ROOT: + break + if self.has_children(idx): + # leaf nodes don't have children so can't be expanded. + paths.append((node.tag.name, idx)) + idx = self._model.parent(idx) + for p in paths: + # Now add the menu items + self.context_menu.addAction(_("Collapse {0}").format(p[0]), + partial(self.collapse_node, p[1])) self.context_menu.addAction(_('Collapse all'), self.collapseAll) if not self.context_menu.isEmpty(): self.context_menu.popup(self.mapToGlobal(point)) return True + def has_children(self, idx): + return self.model().rowCount(idx) > 0 + + def collapse_node_and_children(self, idx): + self.collapse(idx) + for r in range(self.model().rowCount(idx)): + self.collapse_node_and_children(idx.child(r, 0)) + def collapse_node(self, idx): - def collapse_node_and_children(idx): - self.collapse(idx) - for r in range(self.model().rowCount(idx)): - collapse_node_and_children(idx.child(r, 0)) - collapse_node_and_children(idx) + if not idx.isValid(): + return + self.collapse_node_and_children(idx) self.setCurrentIndex(idx) self.scrollTo(idx) - def expand_node_and_descendants(self, index): + def expand_node_and_children(self, index): if not index.isValid(): return self.expand(index) for r in range(self.model().rowCount(index)): - self.expand_node_and_descendants(index.child(r, 0)) + self.expand_node_and_children(index.child(r, 0)) + + def has_unexpanded_children(self, index): + if not index.isValid(): + return + if self.has_children(index) and not self.isExpanded(index): + return True + for r in range(self.model().rowCount(index)): + if self.has_unexpanded_children(index.child(r, 0)): + return True + return False def collapse_menu_hovered(self, action): tip = action.toolTip() From e0bc2d8ebe38d6e3a4e438a1ca63f168d845c4e7 Mon Sep 17 00:00:00 2001 From: Charles Haley Date: Sat, 17 Oct 2020 14:01:42 +0100 Subject: [PATCH 2/2] Make a submenu for expand and collapse. Also add icons. --- src/calibre/gui2/tag_browser/view.py | 27 +++++++++++++++++---------- 1 file changed, 17 insertions(+), 10 deletions(-) diff --git a/src/calibre/gui2/tag_browser/view.py b/src/calibre/gui2/tag_browser/view.py index c4e6e5c917..5470034322 100644 --- a/src/calibre/gui2/tag_browser/view.py +++ b/src/calibre/gui2/tag_browser/view.py @@ -182,6 +182,10 @@ class TagsView(QTreeView): # {{{ self.edit_metadata_icon = QIcon(I('edit_input.png')) self.delete_icon = QIcon(I('list_remove.png')) self.rename_icon = QIcon(I('edit-undo.png')) + self.up_arrow_icon = QIcon(I('arrow-up.png')) + self.down_arrow_icon = QIcon(I('arrow-down.png')) + self.plus_icon = QIcon(I('plus.png')) + self.minus_icon = QIcon(I('minus.png')) self._model = TagsModel(self) self._model.search_item_renamed.connect(self.search_item_renamed) @@ -676,10 +680,10 @@ class TagsView(QTreeView): # {{{ if fm['datatype'] != 'rating': m = self.context_menu.addMenu(self.edit_metadata_icon, _('Apply %s to selected books')%display_name(tag)) - m.addAction(QIcon(I('plus.png')), + m.addAction(self.plus_icon, _('Add %s to selected books') % display_name(tag), partial(self.context_menu_handler, action='add_tag', index=index)) - m.addAction(QIcon(I('minus.png')), + m.addAction(self.minus_icon, _('Remove %s from selected books') % display_name(tag), partial(self.context_menu_handler, action='remove_tag', index=index)) @@ -838,13 +842,15 @@ class TagsView(QTreeView): # {{{ pa.setToolTip('*') # Add expand menu items - node_name = self._model.get_node(index).tag.name self.context_menu.addSeparator() + m = self.context_menu.addMenu(_('Expand and collapse')) + node_name = self._model.get_node(index).tag.name if self.has_children(index) and not self.isExpanded(index): - self.context_menu.addAction(_('Expand {0}').format(node_name), - partial(self.expand, index)) + m.addAction(self.down_arrow_icon, + _('Expand {0}').format(node_name), partial(self.expand, index)) if self.has_unexpanded_children(index): - self.context_menu.addAction(_('Expand {0} and all children').format(node_name), + m.addAction(self.down_arrow_icon, + _('Expand {0} and its children').format(node_name), partial(self.expand_node_and_children, index)) # Add menu items to collapse parent nodes @@ -856,15 +862,16 @@ class TagsView(QTreeView): # {{{ node = self._model.get_node(idx) if node.type == TagTreeItem.ROOT: break - if self.has_children(idx): + if self.has_children(idx) and self.isExpanded(idx): # leaf nodes don't have children so can't be expanded. + # Also the leaf node might be collapsed paths.append((node.tag.name, idx)) idx = self._model.parent(idx) for p in paths: # Now add the menu items - self.context_menu.addAction(_("Collapse {0}").format(p[0]), - partial(self.collapse_node, p[1])) - self.context_menu.addAction(_('Collapse all'), self.collapseAll) + m.addAction(self.up_arrow_icon, + _("Collapse {0}").format(p[0]), partial(self.collapse_node, p[1])) + m.addAction(_('Collapse all'), self.collapseAll) if not self.context_menu.isEmpty(): self.context_menu.popup(self.mapToGlobal(point))