mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-08 18:54:09 -04:00
Merge branch 'master' of https://github.com/cbhaley/calibre
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:
commit
67cddcea52
@ -44,7 +44,8 @@ class Tag:
|
|||||||
|
|
||||||
@property
|
@property
|
||||||
def string_representation(self):
|
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):
|
def __str__(self):
|
||||||
return self.string_representation
|
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:
|
for c in gst:
|
||||||
if c not in muc:
|
if c not in muc:
|
||||||
continue
|
continue
|
||||||
user_categories[c] = []
|
uc = []
|
||||||
for sc in gst[c]:
|
for sc in gst[c]:
|
||||||
for t in categories.get(sc, ()):
|
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:
|
if user_categories:
|
||||||
# We want to use same node in the user category as in the source
|
# We want to use same node in the user category as in the source
|
||||||
|
@ -56,13 +56,14 @@ class TagTreeItem: # {{{
|
|||||||
file_icon_provider = None
|
file_icon_provider = None
|
||||||
|
|
||||||
def __init__(self, data=None, is_category=False, icon_map=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:
|
if self.file_icon_provider is None:
|
||||||
self.file_icon_provider = TagTreeItem.file_icon_provider = file_icon_provider().icon_from_ext
|
self.file_icon_provider = TagTreeItem.file_icon_provider = file_icon_provider().icon_from_ext
|
||||||
self.parent = parent
|
self.parent = parent
|
||||||
self.children = []
|
self.children = []
|
||||||
self.blank = QIcon()
|
self.blank = QIcon()
|
||||||
self.is_gst = False
|
self.is_gst = is_gst
|
||||||
self.boxed = False
|
self.boxed = False
|
||||||
self.temporary = False
|
self.temporary = False
|
||||||
self.can_be_edited = False
|
self.can_be_edited = False
|
||||||
@ -103,6 +104,12 @@ class TagTreeItem: # {{{
|
|||||||
del self.parent
|
del self.parent
|
||||||
del self.children
|
del self.children
|
||||||
|
|
||||||
|
def root_node(self):
|
||||||
|
p = self
|
||||||
|
while p.parent.type != self.ROOT:
|
||||||
|
p = p.parent
|
||||||
|
return p
|
||||||
|
|
||||||
def ensure_icon(self):
|
def ensure_icon(self):
|
||||||
if self.icon_state_map[0] is not None:
|
if self.icon_state_map[0] is not None:
|
||||||
return
|
return
|
||||||
@ -111,7 +118,10 @@ class TagTreeItem: # {{{
|
|||||||
fmt = self.tag.original_name.replace('ORIGINAL_', '')
|
fmt = self.tag.original_name.replace('ORIGINAL_', '')
|
||||||
cc = self.file_icon_provider(fmt)
|
cc = self.file_icon_provider(fmt)
|
||||||
else:
|
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:
|
elif self.type == self.CATEGORY:
|
||||||
cc = self.category_custom_icons.get(self.category_key, None)
|
cc = self.category_custom_icons.get(self.category_key, None)
|
||||||
self.icon_state_map[0] = cc or QIcon()
|
self.icon_state_map[0] = cc or QIcon()
|
||||||
@ -461,6 +471,7 @@ class TagsModel(QAbstractItemModel): # {{{
|
|||||||
node = self.create_node(parent=last_category_node,
|
node = self.create_node(parent=last_category_node,
|
||||||
data=p[1:] if i == 0 else p,
|
data=p[1:] if i == 0 else p,
|
||||||
is_category=True,
|
is_category=True,
|
||||||
|
is_gst = is_gst,
|
||||||
tooltip=tt if path == key else path,
|
tooltip=tt if path == key else path,
|
||||||
category_key=path,
|
category_key=path,
|
||||||
icon_map=self.icon_state_map)
|
icon_map=self.icon_state_map)
|
||||||
@ -468,7 +479,6 @@ class TagsModel(QAbstractItemModel): # {{{
|
|||||||
category_node_map[path] = node
|
category_node_map[path] = node
|
||||||
self.category_nodes.append(node)
|
self.category_nodes.append(node)
|
||||||
node.can_be_edited = (not is_gst) and (i == (len(path_parts)-1))
|
node.can_be_edited = (not is_gst) and (i == (len(path_parts)-1))
|
||||||
node.is_gst = is_gst
|
|
||||||
if not is_gst:
|
if not is_gst:
|
||||||
node.tag.is_hierarchical = '5state'
|
node.tag.is_hierarchical = '5state'
|
||||||
tree_root[p] = {}
|
tree_root[p] = {}
|
||||||
@ -481,9 +491,9 @@ class TagsModel(QAbstractItemModel): # {{{
|
|||||||
node = self.create_node(parent=self.root_item,
|
node = self.create_node(parent=self.root_item,
|
||||||
data=self.categories[key],
|
data=self.categories[key],
|
||||||
is_category=True,
|
is_category=True,
|
||||||
|
is_gst = False,
|
||||||
tooltip=tt, category_key=key,
|
tooltip=tt, category_key=key,
|
||||||
icon_map=self.icon_state_map)
|
icon_map=self.icon_state_map)
|
||||||
node.is_gst = False
|
|
||||||
category_node_map[key] = node
|
category_node_map[key] = node
|
||||||
last_category_node = node
|
last_category_node = node
|
||||||
self.category_nodes.append(node)
|
self.category_nodes.append(node)
|
||||||
@ -663,10 +673,10 @@ class TagsModel(QAbstractItemModel): # {{{
|
|||||||
sub_cat = self.create_node(parent=category, data=name,
|
sub_cat = self.create_node(parent=category, data=name,
|
||||||
tooltip=None, temporary=True,
|
tooltip=None, temporary=True,
|
||||||
is_category=True,
|
is_category=True,
|
||||||
|
is_gst=is_gst,
|
||||||
category_key=category.category_key,
|
category_key=category.category_key,
|
||||||
icon_map=self.icon_state_map)
|
icon_map=self.icon_state_map)
|
||||||
sub_cat.tag.is_searchable = False
|
sub_cat.tag.is_searchable = False
|
||||||
sub_cat.is_gst = is_gst
|
|
||||||
node_parent = sub_cat
|
node_parent = sub_cat
|
||||||
last_idx = idx # remember where we last partitioned
|
last_idx = idx # remember where we last partitioned
|
||||||
else:
|
else:
|
||||||
@ -678,10 +688,10 @@ class TagsModel(QAbstractItemModel): # {{{
|
|||||||
sub_cat = self.create_node(parent=category,
|
sub_cat = self.create_node(parent=category,
|
||||||
data=collapse_letter,
|
data=collapse_letter,
|
||||||
is_category=True,
|
is_category=True,
|
||||||
|
is_gst=is_gst,
|
||||||
tooltip=None, temporary=True,
|
tooltip=None, temporary=True,
|
||||||
category_key=category.category_key,
|
category_key=category.category_key,
|
||||||
icon_map=self.icon_state_map)
|
icon_map=self.icon_state_map)
|
||||||
sub_cat.is_gst = is_gst
|
|
||||||
node_parent = sub_cat
|
node_parent = sub_cat
|
||||||
else:
|
else:
|
||||||
node_parent = category
|
node_parent = category
|
||||||
@ -698,28 +708,29 @@ class TagsModel(QAbstractItemModel): # {{{
|
|||||||
(fm['is_custom'] and fm['display'].get('is_names', False)) or
|
(fm['is_custom'] and fm['display'].get('is_names', False)) or
|
||||||
not category_is_hierarchical or len(components) == 1):
|
not category_is_hierarchical or len(components) == 1):
|
||||||
n = self.create_node(parent=node_parent, data=tag, tooltip=tt,
|
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
|
category_child_map[tag.name, tag.category] = n
|
||||||
else:
|
else:
|
||||||
|
child_key = key if is_gst else tag.category
|
||||||
for i,comp in enumerate(components):
|
for i,comp in enumerate(components):
|
||||||
if i == 0:
|
if i == 0:
|
||||||
child_map = category_child_map
|
child_map = category_child_map
|
||||||
top_level_component = comp
|
top_level_component = comp
|
||||||
else:
|
else:
|
||||||
child_map = {(t.tag.name, t.tag.category): t
|
child_map = {(t.tag.name, key if is_gst else t.tag.category):
|
||||||
for t in node_parent.children
|
t for t in node_parent.children
|
||||||
if t.type != TagTreeItem.CATEGORY}
|
if t.type != TagTreeItem.CATEGORY}
|
||||||
if (comp,tag.category) in child_map:
|
if (comp,child_key) in child_map:
|
||||||
node_parent = child_map[(comp,tag.category)]
|
node_parent = child_map[(comp,child_key)]
|
||||||
t = node_parent.tag
|
t = node_parent.tag
|
||||||
t.is_hierarchical = '5state' if tag.category != 'search' else '3state'
|
t.is_hierarchical = '5state' if tag.category != 'search' else '3state'
|
||||||
if tag.id_set is not None and t.id_set is not None:
|
if tag.id_set is not None and t.id_set is not None:
|
||||||
t.id_set = t.id_set | tag.id_set
|
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:
|
else:
|
||||||
if i < len(components)-1:
|
if i < len(components)-1:
|
||||||
original_name = '.'.join(components[:i+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:
|
if t is None:
|
||||||
t = copy.copy(tag)
|
t = copy.copy(tag)
|
||||||
t.original_name = original_name
|
t.original_name = original_name
|
||||||
@ -730,18 +741,19 @@ class TagsModel(QAbstractItemModel): # {{{
|
|||||||
t.is_editable = False
|
t.is_editable = False
|
||||||
else:
|
else:
|
||||||
t.is_searchable = t.is_editable = False
|
t.is_searchable = t.is_editable = False
|
||||||
intermediate_nodes[original_name, tag.category] = t
|
intermediate_nodes[original_name,child_key] = t
|
||||||
else:
|
else:
|
||||||
t = tag
|
t = tag
|
||||||
if not in_uc:
|
if not in_uc:
|
||||||
t.original_name = t.name
|
t.original_name = t.name
|
||||||
intermediate_nodes[t.original_name, t.category] = t
|
intermediate_nodes[t.original_name,child_key] = t
|
||||||
t.is_hierarchical = \
|
t.is_hierarchical = \
|
||||||
'5state' if t.category != 'search' else '3state'
|
'5state' if t.category != 'search' else '3state'
|
||||||
t.name = comp
|
t.name = comp
|
||||||
node_parent = self.create_node(parent=node_parent, data=t,
|
node_parent = self.create_node(parent=node_parent,
|
||||||
tooltip=tt, icon_map=self.icon_state_map)
|
data=t, is_gst=is_gst, tooltip=tt,
|
||||||
child_map[(comp,tag.category)] = node_parent
|
icon_map=self.icon_state_map)
|
||||||
|
child_map[(comp, child_key)] = node_parent
|
||||||
|
|
||||||
# Correct the average rating for the node
|
# Correct the average rating for the node
|
||||||
total = count = 0
|
total = count = 0
|
||||||
|
Loading…
x
Reference in New Issue
Block a user