mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-09 03:04:10 -04:00
Merge branch 'master' of https://github.com/cbhaley/calibre
This commit is contained in:
commit
d33db7bc37
@ -21,11 +21,12 @@ class Tag(object):
|
||||
|
||||
__slots__ = ('name', 'original_name', 'id', 'count', 'state', 'is_hierarchical',
|
||||
'is_editable', 'is_searchable', 'id_set', 'avg_rating', 'sort',
|
||||
'use_sort_as_name', 'category', 'search_expression')
|
||||
'use_sort_as_name', 'category', 'search_expression', 'original_categories')
|
||||
|
||||
def __init__(self, name, id=None, count=0, state=0, avg=0, sort=None,
|
||||
category=None, id_set=None, search_expression=None,
|
||||
is_editable=True, is_searchable=True, use_sort_as_name=False):
|
||||
is_editable=True, is_searchable=True, use_sort_as_name=False,
|
||||
original_categories=None):
|
||||
self.name = self.original_name = name
|
||||
self.id = id
|
||||
self.count = count
|
||||
@ -39,6 +40,7 @@ class Tag(object):
|
||||
self.use_sort_as_name = use_sort_as_name
|
||||
self.category = category
|
||||
self.search_expression = search_expression
|
||||
self.original_categories = None
|
||||
|
||||
def __unicode__(self):
|
||||
return u'%s:%s:%s:%s:%s'%(self.name, self.count, self.id, self.state, self.category)
|
||||
@ -198,12 +200,29 @@ def get_categories(dbcache, sort='name', book_ids=None, first_letter_sort=False)
|
||||
if user_cat_is_gst:
|
||||
# for gst items, make copy and consolidate the tags by name.
|
||||
if n in names_seen:
|
||||
# We must combine this node into a previous one with
|
||||
# the same name ignoring case. As part of the process,
|
||||
# remember the source categories and correct the
|
||||
# average rating
|
||||
t = names_seen[n]
|
||||
other_tag = taglist[label][n]
|
||||
t.id_set |= other_tag.id_set
|
||||
t.count += other_tag.count
|
||||
t.count = len(t.id_set)
|
||||
t.original_categories.add(other_tag.category)
|
||||
|
||||
total_rating = 0
|
||||
count = 0
|
||||
for id_ in t.id_set:
|
||||
rating = book_rating_map[id_]
|
||||
if rating:
|
||||
total_rating += rating/2
|
||||
count += 1
|
||||
if total_rating and count:
|
||||
t.avg_rating = total_rating/count
|
||||
else:
|
||||
t = copy.copy(taglist[label][n])
|
||||
# Must deepcopy so we don't share the id_set between nodes
|
||||
t = copy.deepcopy(taglist[label][n])
|
||||
t.original_categories = {t.category}
|
||||
names_seen[n] = t
|
||||
items.append(t)
|
||||
else:
|
||||
|
@ -73,6 +73,8 @@ class TagTreeItem(object): # {{{
|
||||
is_searchable=category_key not in ['search'])
|
||||
elif self.type == self.TAG:
|
||||
self.tag = data
|
||||
self.cached_average_rating = None
|
||||
self.cached_item_count = None
|
||||
|
||||
self.tooltip = tooltip or ''
|
||||
|
||||
@ -119,6 +121,8 @@ class TagTreeItem(object): # {{{
|
||||
return self.tag.avg_rating
|
||||
if not self.children:
|
||||
return self.tag.avg_rating # leaf node, avg_rating is correct
|
||||
if self.cached_average_rating:
|
||||
return self.cached_average_rating
|
||||
total = num = 0
|
||||
for child in self.children:
|
||||
r = child.average_rating
|
||||
@ -129,9 +133,25 @@ class TagTreeItem(object): # {{{
|
||||
total += 1
|
||||
num += self.tag.avg_rating
|
||||
try:
|
||||
return num/float(total)
|
||||
self.cached_average_rating = num/float(total)
|
||||
except ZeroDivisionError:
|
||||
return 0
|
||||
self.cached_average_rating = 0
|
||||
return self.cached_average_rating
|
||||
|
||||
@property
|
||||
def item_count(self):
|
||||
if not self.tag.is_hierarchical or not self.children:
|
||||
return self.tag.count
|
||||
if self.cached_item_count:
|
||||
return self.cached_item_count
|
||||
|
||||
def child_item_set(node):
|
||||
s = node.tag.id_set.copy()
|
||||
for child in node.children:
|
||||
s |= child_item_set(child)
|
||||
return s
|
||||
self.cached_item_count = len(child_item_set(self))
|
||||
return self.cached_item_count
|
||||
|
||||
def data(self, role):
|
||||
if role == Qt.UserRole:
|
||||
@ -170,8 +190,7 @@ class TagTreeItem(object): # {{{
|
||||
else:
|
||||
name = tag.name
|
||||
if role == Qt.DisplayRole:
|
||||
count = len(tag.id_set)
|
||||
count = count if count > 0 else tag.count
|
||||
count = self.item_count
|
||||
if count == 0:
|
||||
return ('%s'%(name))
|
||||
else:
|
||||
@ -184,7 +203,10 @@ class TagTreeItem(object): # {{{
|
||||
return self.icon_state_map[tag.state]
|
||||
if role == Qt.ToolTipRole:
|
||||
tt = [self.tooltip] if self.tooltip else []
|
||||
tt.append('%s:%s' % (tag.category, tag.original_name))
|
||||
if tag.original_categories:
|
||||
tt.append('%s:%s' % (','.join(tag.original_categories), tag.original_name))
|
||||
else:
|
||||
tt.append('%s:%s' % (tag.category, tag.original_name))
|
||||
ar = self.average_rating
|
||||
if ar:
|
||||
tt.append(_('Average rating for books in this category: %.1f') % ar)
|
||||
@ -210,8 +232,7 @@ class TagTreeItem(object): # {{{
|
||||
name = tag.original_name
|
||||
else:
|
||||
name = tag.name
|
||||
count = len(tag.id_set)
|
||||
count = count if count > 0 else tag.count
|
||||
count = self.item_count
|
||||
rating = self.average_rating
|
||||
if rating:
|
||||
rating = ',rating=%.1f' % rating
|
||||
@ -591,7 +612,6 @@ class TagsModel(QAbstractItemModel): # {{{
|
||||
n = self.create_node(parent=node_parent, data=tag, tooltip=tt,
|
||||
icon_map=self.icon_state_map)
|
||||
category_child_map[tag.name, tag.category] = n
|
||||
intermediate_nodes[tag.original_name, tag.category] = tag
|
||||
else:
|
||||
for i,comp in enumerate(components):
|
||||
if i == 0:
|
||||
@ -603,10 +623,9 @@ class TagsModel(QAbstractItemModel): # {{{
|
||||
if t.type != TagTreeItem.CATEGORY])
|
||||
if (comp,tag.category) in child_map:
|
||||
node_parent = child_map[(comp,tag.category)]
|
||||
node_parent.tag.is_hierarchical = \
|
||||
'5state' if tag.category != 'search' else '3state'
|
||||
if tag.id_set is not None and node_parent.tag.id_set is not None:
|
||||
node_parent.tag.id_set |= tag.id_set
|
||||
t = node_parent.tag
|
||||
t.is_hierarchical = '5state' if tag.category != 'search' else '3state'
|
||||
intermediate_nodes[t.original_name, t.category] = t
|
||||
else:
|
||||
if i < len(components)-1:
|
||||
original_name = '.'.join(components[:i+1])
|
||||
|
@ -85,6 +85,8 @@ def category_item_as_json(x, clear_rating=False):
|
||||
for k in _include_fields:
|
||||
val = getattr(x, k)
|
||||
if val is not None:
|
||||
if k == 'original_categories':
|
||||
val = tuple(val)
|
||||
ans[k] = val.copy() if isinstance(val, set) else val
|
||||
if x.use_sort_as_name:
|
||||
ans['name'] = ans['sort']
|
||||
|
Loading…
x
Reference in New Issue
Block a user