diff --git a/src/calibre/db/categories.py b/src/calibre/db/categories.py index 396bd954bd..6af9b35148 100644 --- a/src/calibre/db/categories.py +++ b/src/calibre/db/categories.py @@ -135,11 +135,19 @@ def get_categories(dbcache, sort='name', book_ids=None, icon_map=None): categories = {} book_ids = frozenset(book_ids) if book_ids else book_ids + get_metadata = partial(dbcache._get_metadata, get_user_categories=False) + bids = None + for category, is_multiple, is_composite in find_categories(fm): tag_class = create_tag_class(category, fm, icon_map) # TODO: Handle composite column based categories (both is_multiple and # not is_multiple) - if category == 'news': + if is_composite: + if bids is None: + bids = dbcache._all_book_ids() if book_ids is None else book_ids + cats = dbcache.fields[category].get_composite_categories( + tag_class, book_rating_map, bids, is_multiple, get_metadata) + elif category == 'news': cats = dbcache.fields['tags'].get_news_category(tag_class, book_ids) else: cats = dbcache.fields[category].get_categories( diff --git a/src/calibre/db/fields.py b/src/calibre/db/fields.py index 5816880576..bd3af5d518 100644 --- a/src/calibre/db/fields.py +++ b/src/calibre/db/fields.py @@ -186,6 +186,25 @@ class CompositeField(OneToOneField): for val, book_ids in val_map.iteritems(): yield val, book_ids + def get_composite_categories(self, tag_class, book_rating_map, book_ids, + is_multiple, get_metadata): + ans = [] + id_map = defaultdict(set) + for book_id in book_ids: + val = self.get_value_with_cache(book_id, get_metadata) + vals = [x.strip() for x in val.split(is_multiple)] if is_multiple else [val] + for val in vals: + if val: + id_map[val].add(book_id) + for item_id, item_book_ids in id_map.iteritems(): + ratings = tuple(r for r in (book_rating_map.get(book_id, 0) for + book_id in item_book_ids) if r > 0) + avg = sum(ratings)/len(ratings) if ratings else 0 + c = tag_class(item_id, id=item_id, sort=item_id, avg=avg, + id_set=item_book_ids, count=len(item_book_ids)) + ans.append(c) + return ans + class OnDeviceField(OneToOneField): def __init__(self, name, table): diff --git a/src/calibre/db/tables.py b/src/calibre/db/tables.py index 4a8b4492fd..90f5db9ac5 100644 --- a/src/calibre/db/tables.py +++ b/src/calibre/db/tables.py @@ -98,10 +98,10 @@ class CompositeTable(OneToOneTable): self.book_col_map = {} d = self.metadata['display'] self.composite_template = ['composite_template'] - self.contains_html = d['contains_html'] - self.make_category = d['make_category'] - self.composite_sort = d['composite_sort'] - self.use_decorations = d['use_decorations'] + self.contains_html = d.get('contains_html', False) + self.make_category = d.get('make_category', False) + self.composite_sort = d.get('composite_sort', False) + self.use_decorations = d.get('use_decorations', False) class ManyToOneTable(Table): diff --git a/src/calibre/db/tests/metadata.db b/src/calibre/db/tests/metadata.db index 70237949d8..88a76ac410 100644 Binary files a/src/calibre/db/tests/metadata.db and b/src/calibre/db/tests/metadata.db differ