Fix #1955732 [Hierarchical entries in user category may not merge correctly in tag browser](https://bugs.launchpad.net/calibre/+bug/1955732)
This commit is contained in:
Kovid Goyal 2021-12-25 19:55:14 +05:30
commit 67cddcea52
No known key found for this signature in database
GPG Key ID: 06BC317B515ACE7C
2 changed files with 36 additions and 22 deletions

View File

@ -44,7 +44,8 @@ class Tag:
@property
def string_representation(self):
return '%s:%s:%s:%s:%s'%(self.name, self.count, self.id, self.state, self.category)
return '%s:%s:%s:%s:%s:%s'%(self.name, self.count, self.id, self.state,
self.category, self.original_categories)
def __str__(self):
return self.string_representation
@ -207,10 +208,11 @@ def get_categories(dbcache, sort='name', book_ids=None, first_letter_sort=False)
for c in gst:
if c not in muc:
continue
user_categories[c] = []
uc = []
for sc in gst[c]:
for t in categories.get(sc, ()):
user_categories[c].append([t.name, sc, 0])
uc.append([t.name, sc, 0])
user_categories[c] = uc
if user_categories:
# We want to use same node in the user category as in the source

View File

@ -56,13 +56,14 @@ class TagTreeItem: # {{{
file_icon_provider = None
def __init__(self, data=None, is_category=False, icon_map=None,
parent=None, tooltip=None, category_key=None, temporary=False):
parent=None, tooltip=None, category_key=None, temporary=False,
is_gst=False):
if self.file_icon_provider is None:
self.file_icon_provider = TagTreeItem.file_icon_provider = file_icon_provider().icon_from_ext
self.parent = parent
self.children = []
self.blank = QIcon()
self.is_gst = False
self.is_gst = is_gst
self.boxed = False
self.temporary = False
self.can_be_edited = False
@ -103,6 +104,12 @@ class TagTreeItem: # {{{
del self.parent
del self.children
def root_node(self):
p = self
while p.parent.type != self.ROOT:
p = p.parent
return p
def ensure_icon(self):
if self.icon_state_map[0] is not None:
return
@ -111,7 +118,10 @@ class TagTreeItem: # {{{
fmt = self.tag.original_name.replace('ORIGINAL_', '')
cc = self.file_icon_provider(fmt)
else:
cc = self.category_custom_icons.get(self.tag.category, None)
if self.is_gst:
cc = self.category_custom_icons.get(self.root_node().category_key, None)
else:
cc = self.category_custom_icons.get(self.tag.category, None)
elif self.type == self.CATEGORY:
cc = self.category_custom_icons.get(self.category_key, None)
self.icon_state_map[0] = cc or QIcon()
@ -461,6 +471,7 @@ class TagsModel(QAbstractItemModel): # {{{
node = self.create_node(parent=last_category_node,
data=p[1:] if i == 0 else p,
is_category=True,
is_gst = is_gst,
tooltip=tt if path == key else path,
category_key=path,
icon_map=self.icon_state_map)
@ -468,7 +479,6 @@ class TagsModel(QAbstractItemModel): # {{{
category_node_map[path] = node
self.category_nodes.append(node)
node.can_be_edited = (not is_gst) and (i == (len(path_parts)-1))
node.is_gst = is_gst
if not is_gst:
node.tag.is_hierarchical = '5state'
tree_root[p] = {}
@ -481,9 +491,9 @@ class TagsModel(QAbstractItemModel): # {{{
node = self.create_node(parent=self.root_item,
data=self.categories[key],
is_category=True,
is_gst = False,
tooltip=tt, category_key=key,
icon_map=self.icon_state_map)
node.is_gst = False
category_node_map[key] = node
last_category_node = node
self.category_nodes.append(node)
@ -663,10 +673,10 @@ class TagsModel(QAbstractItemModel): # {{{
sub_cat = self.create_node(parent=category, data=name,
tooltip=None, temporary=True,
is_category=True,
is_gst=is_gst,
category_key=category.category_key,
icon_map=self.icon_state_map)
sub_cat.tag.is_searchable = False
sub_cat.is_gst = is_gst
node_parent = sub_cat
last_idx = idx # remember where we last partitioned
else:
@ -678,10 +688,10 @@ class TagsModel(QAbstractItemModel): # {{{
sub_cat = self.create_node(parent=category,
data=collapse_letter,
is_category=True,
is_gst=is_gst,
tooltip=None, temporary=True,
category_key=category.category_key,
icon_map=self.icon_state_map)
sub_cat.is_gst = is_gst
node_parent = sub_cat
else:
node_parent = category
@ -698,28 +708,29 @@ class TagsModel(QAbstractItemModel): # {{{
(fm['is_custom'] and fm['display'].get('is_names', False)) or
not category_is_hierarchical or len(components) == 1):
n = self.create_node(parent=node_parent, data=tag, tooltip=tt,
icon_map=self.icon_state_map)
is_gst=is_gst, icon_map=self.icon_state_map)
category_child_map[tag.name, tag.category] = n
else:
child_key = key if is_gst else tag.category
for i,comp in enumerate(components):
if i == 0:
child_map = category_child_map
top_level_component = comp
else:
child_map = {(t.tag.name, t.tag.category): t
for t in node_parent.children
child_map = {(t.tag.name, key if is_gst else t.tag.category):
t for t in node_parent.children
if t.type != TagTreeItem.CATEGORY}
if (comp,tag.category) in child_map:
node_parent = child_map[(comp,tag.category)]
if (comp,child_key) in child_map:
node_parent = child_map[(comp,child_key)]
t = node_parent.tag
t.is_hierarchical = '5state' if tag.category != 'search' else '3state'
if tag.id_set is not None and t.id_set is not None:
t.id_set = t.id_set | tag.id_set
intermediate_nodes[t.original_name, t.category] = t
intermediate_nodes[t.original_name,child_key] = t
else:
if i < len(components)-1:
original_name = '.'.join(components[:i+1])
t = intermediate_nodes.get((original_name, tag.category), None)
t = intermediate_nodes.get((original_name, child_key), None)
if t is None:
t = copy.copy(tag)
t.original_name = original_name
@ -730,18 +741,19 @@ class TagsModel(QAbstractItemModel): # {{{
t.is_editable = False
else:
t.is_searchable = t.is_editable = False
intermediate_nodes[original_name, tag.category] = t
intermediate_nodes[original_name,child_key] = t
else:
t = tag
if not in_uc:
t.original_name = t.name
intermediate_nodes[t.original_name, t.category] = t
intermediate_nodes[t.original_name,child_key] = t
t.is_hierarchical = \
'5state' if t.category != 'search' else '3state'
t.name = comp
node_parent = self.create_node(parent=node_parent, data=t,
tooltip=tt, icon_map=self.icon_state_map)
child_map[(comp,tag.category)] = node_parent
node_parent = self.create_node(parent=node_parent,
data=t, is_gst=is_gst, tooltip=tt,
icon_map=self.icon_state_map)
child_map[(comp, child_key)] = node_parent
# Correct the average rating for the node
total = count = 0