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()