From 70daeb694251cc1c0cdfbd8e24cc94797197628a Mon Sep 17 00:00:00 2001 From: Charles Haley Date: Sun, 27 Oct 2024 12:15:32 +0000 Subject: [PATCH] Changes to displaying and partitioning user categories to ensure that any hierarchical prefix is used. This applies to Tag browser in Look & feel and to the context menu in the tag browser. These changes make user user categories behave like normal categories. --- src/calibre/db/categories.py | 9 ++++++-- src/calibre/gui2/preferences/look_feel.py | 16 +++++++++++++- src/calibre/gui2/tag_browser/model.py | 7 +++++- src/calibre/gui2/tag_browser/view.py | 26 ++++++++++++++++------- 4 files changed, 46 insertions(+), 12 deletions(-) diff --git a/src/calibre/db/categories.py b/src/calibre/db/categories.py index b8e3f5d913..cb8621e464 100644 --- a/src/calibre/db/categories.py +++ b/src/calibre/db/categories.py @@ -136,10 +136,15 @@ def category_display_order(ordered_cats, all_cats): for key in all_cats: if key not in cat_ord and is_standard_category(key): cat_ord.append(key) - # Now add the non-standard cats (user cats and search) + # Now add the non-standard cats (user cats and search). As these are always + # hierarchical, only keep the prefix. + user_cat_prefixes = set() for key in all_cats: if not is_standard_category(key): - cat_ord.append(key) + prefix = key.partition('.')[0] + if prefix not in user_cat_prefixes: + cat_ord.append(prefix) + user_cat_prefixes.add(prefix) return cat_ord diff --git a/src/calibre/gui2/preferences/look_feel.py b/src/calibre/gui2/preferences/look_feel.py index 78e5cb4d74..8449d5ae50 100644 --- a/src/calibre/gui2/preferences/look_feel.py +++ b/src/calibre/gui2/preferences/look_feel.py @@ -292,6 +292,7 @@ class DisplayedFields(QAbstractListModel): # {{{ pass if field == 'path': name = _('Folders/path') + name = field.partition('.')[0][1:] if field.startswith('@') else name if not name: return field return f'{name} ({field})' @@ -445,9 +446,22 @@ class TBPartitionedFields(DisplayedFields): # {{{ from calibre.gui2.ui import get_gui self.gui = get_gui() + def filter_user_categories(self, tv): + cats = tv.model().categories + answer = {} + filtered = set() + for key,name in cats.items(): + if key.startswith('@'): + key = key.partition('.')[0] + name = key[1:] + if key not in filtered: + answer[key] = name + filtered.add(key) + return answer + def initialize(self, use_defaults=False, pref_data_override=None): tv = self.gui.tags_view - cats = tv.model().categories + cats = self.filter_user_categories(tv) ans = [] if use_defaults: ans = [[k, True] for k in cats.keys()] diff --git a/src/calibre/gui2/tag_browser/model.py b/src/calibre/gui2/tag_browser/model.py index 2c2f68e802..ed2e55ea7e 100644 --- a/src/calibre/gui2/tag_browser/model.py +++ b/src/calibre/gui2/tag_browser/model.py @@ -620,10 +620,15 @@ class TagsModel(QAbstractItemModel): # {{{ is_gst = category.is_gst if key not in data: return + + # Ensure we use the prefix for any user category. Non UCs can't have + # a period in the key so doing the partition without an if is safe + k = key.partition('.')[0] # Use old pref if new one doesn't exist - if key in self.db.prefs.get('tag_browser_dont_collapse', + if k in self.db.prefs.get('tag_browser_dont_collapse', self.prefs['tag_browser_dont_collapse']): collapse_model = 'disable' + cat_len = len(data[key]) if cat_len <= 0: return diff --git a/src/calibre/gui2/tag_browser/view.py b/src/calibre/gui2/tag_browser/view.py index eb0beeaae7..6aa15fa60f 100644 --- a/src/calibre/gui2/tag_browser/view.py +++ b/src/calibre/gui2/tag_browser/view.py @@ -861,8 +861,11 @@ class TagsView(QTreeView): # {{{ # exists before offering to unhide it. for col in sorted((c for c in self.hidden_categories if c in self.db.field_metadata), key=lambda x: sort_key(self.db.field_metadata[x]['name'])): - ac = m.addAction(self.db.field_metadata[col]['name'], - partial(self.context_menu_handler, action='show', category=col)) + # Get the prefix for any user categories. The UC name is the same as + # the key but without the '@' + name = self.db.field_metadata[col]['name'] + name = name.partition('.')[0] if col.startswith('@') else name + ac = m.addAction(name, partial(self.context_menu_handler, action='show', category=col)) ic = self.model().category_custom_icons.get(col) if ic: ac.setIcon(QIcon.ic(ic)) @@ -1201,14 +1204,21 @@ class TagsView(QTreeView): # {{{ if gprefs['tags_browser_partition_method'] != 'disable' and key is not None: m = self.context_menu p = self.db.prefs.get('tag_browser_dont_collapse', gprefs['tag_browser_dont_collapse']) - if key in p: - a = m.addAction(_('Sub-categorize {}').format(category), - partial(self.context_menu_handler, action='collapse_category', - category=category, key=key, extra=p)) + # Use the prefix for a user category. The + if key.startswith('@'): + k = key.partition('.')[0] + cat = k[1:] else: - a = m.addAction(_("Don't sub-categorize {}").format(category), + k = key + cat = category + if k in p: + a = m.addAction(_('Sub-categorize {}').format(cat), + partial(self.context_menu_handler, action='collapse_category', + category=cat, key=k, extra=p)) + else: + a = m.addAction(_("Don't sub-categorize {}").format(cat), partial(self.context_menu_handler, action='dont_collapse_category', - category=category, key=key, extra=p)) + category=cat, key=k, extra=p)) a.setIcon(QIcon.ic('config.png')) # Set the partitioning scheme m = self.context_menu.addMenu(_('Change sub-categorization scheme'))