From 8ad1087fd42a44a50e15c44168401a77df3c68f6 Mon Sep 17 00:00:00 2001 From: Charles Haley Date: Sat, 17 Sep 2022 14:30:24 +0100 Subject: [PATCH] Enhancement: in book details, allow displaying is_multiple categories on separate lines. Bug fix: is_multiple composite columns incorrectly depended on a space after the comma. --- src/calibre/ebooks/metadata/book/render.py | 22 +++++++----- src/calibre/gui2/book_details.py | 10 ++++-- src/calibre/gui2/preferences/look_feel.py | 39 ++++++++++++++++++++++ src/calibre/gui2/preferences/look_feel.ui | 27 ++++++++++++--- 4 files changed, 83 insertions(+), 15 deletions(-) diff --git a/src/calibre/ebooks/metadata/book/render.py b/src/calibre/ebooks/metadata/book/render.py index 64c75c5f6c..90c707c8c4 100644 --- a/src/calibre/ebooks/metadata/book/render.py +++ b/src/calibre/ebooks/metadata/book/render.py @@ -89,7 +89,7 @@ def mi_to_html( mi, field_list=None, default_author_link=None, use_roman_numbers=True, rating_font='Liberation Serif', rtl=False, comments_heading_pos='hide', - for_qt=False, + for_qt=False, vertical_fields=() ): if field_list is None: field_list = get_field_list(mi) @@ -108,6 +108,12 @@ def mi_to_html( continue if not metadata: continue + + def value_list(sep, vals): + if field in vertical_fields: + return '
'.join(vals) + return sep.join(vals) + if field == 'sort': field = 'title_sort' if metadata['is_custom'] and metadata['datatype'] in {'bool', 'int', 'float'}: @@ -162,11 +168,11 @@ def mi_to_html( _('Click to see books with {0}: {1}').format(metadata['name'], a(val)), p(val)) else: all_vals = [v.strip() - for v in val.split(metadata['is_multiple']['list_to_ui']) if v.strip()] + for v in val.split(metadata['is_multiple']['cache_to_list']) if v.strip()] links = ['{}'.format( search_action(field, x), _('Click to see books with {0}: {1}').format( metadata['name'], a(x)), p(x)) for x in all_vals] - val = metadata['is_multiple']['list_to_ui'].join(links) + val = value_list(metadata['is_multiple']['list_to_ui'], links) ans.append((field, row % (name, val))) elif field == 'path': if mi.path: @@ -199,7 +205,7 @@ def mi_to_html( } for x in mi.formats) fmts = ['{fmt}'.format(**x) for x in data] - ans.append((field, row % (name, ', '.join(fmts)))) + ans.append((field, row % (name, value_list(', ', fmts)))) elif field == 'identifiers': urls = urls_from_identifiers(mi.identifiers, sort_results=True) links = [ @@ -207,7 +213,7 @@ def mi_to_html( action('identifier', url=url, name=namel, id_type=id_typ, value=id_val, field='identifiers', book_id=book_id), a(id_typ), a(id_val), p(namel)) for namel, id_typ, id_val, url in urls] - links = ', '.join(links) + links = value_list(', ', links) if links: ans.append((field, row % (_('Ids')+':', links))) elif field == 'authors': @@ -233,14 +239,14 @@ def mi_to_html( authors.append('%s'%(a(lt), action('author', url=link, name=aut, title=lt), aut)) else: authors.append(aut) - ans.append((field, row % (name, ' & '.join(authors)))) + ans.append((field, row % (name, value_list(' & ', authors)))) elif field == 'languages': if not mi.languages: continue names = filter(None, map(calibre_langcode_to_name, mi.languages)) names = ['{}'.format(search_action_with_data('languages', n, book_id), _( 'Search calibre for books with the language: {}').format(n), n) for n in names] - ans.append((field, row % (name, ', '.join(names)))) + ans.append((field, row % (name, value_list(', ', names)))) elif field == 'publisher': if not mi.publisher: continue @@ -303,7 +309,7 @@ def mi_to_html( search_action_with_data(st, x, book_id, field), _('Click to see books with {0}: {1}').format( metadata['name'] or field, a(x)), p(x)) for x in all_vals] - val = metadata['is_multiple']['list_to_ui'].join(links) + val = value_list(metadata['is_multiple']['list_to_ui'], links) elif metadata['datatype'] == 'text' or metadata['datatype'] == 'enumeration': # text/is_multiple handled above so no need to add the test to the if try: diff --git a/src/calibre/gui2/book_details.py b/src/calibre/gui2/book_details.py index d57926665a..f9214fbd09 100644 --- a/src/calibre/gui2/book_details.py +++ b/src/calibre/gui2/book_details.py @@ -176,7 +176,9 @@ def init_find_in_grouped_search(menu, field, value, book_info): def render_html(mi, vertical, widget, all_fields=False, render_data_func=None, pref_name='book_display_fields'): # {{{ - func = render_data_func or render_data + from calibre.gui2.ui import get_gui + func = render_data_func or partial(render_data, + vertical_fields=get_gui().current_db.prefs.get('book_details_vertical_categories') or ()) try: table, comment_fields = func(mi, all_fields=all_fields, use_roman_numbers=config['use_roman_numerals_for_series_number'], pref_name=pref_name) @@ -233,13 +235,15 @@ def get_field_list(fm, use_defaults=False, pref_name='book_display_fields'): return [(f, d) for f, d in fieldlist if f in available] -def render_data(mi, use_roman_numbers=True, all_fields=False, pref_name='book_display_fields'): +def render_data(mi, use_roman_numbers=True, all_fields=False, pref_name='book_display_fields', + vertical_fields=()): field_list = get_field_list(getattr(mi, 'field_metadata', field_metadata), pref_name=pref_name) field_list = [(x, all_fields or display) for x, display in field_list] return mi_to_html( mi, field_list=field_list, use_roman_numbers=use_roman_numbers, rtl=is_rtl(), rating_font=rating_font(), default_author_link=default_author_link(), - comments_heading_pos=gprefs['book_details_comments_heading_pos'], for_qt=True + comments_heading_pos=gprefs['book_details_comments_heading_pos'], for_qt=True, + vertical_fields=vertical_fields ) # }}} diff --git a/src/calibre/gui2/preferences/look_feel.py b/src/calibre/gui2/preferences/look_feel.py index 750ca86ce8..71437c65fa 100644 --- a/src/calibre/gui2/preferences/look_feel.py +++ b/src/calibre/gui2/preferences/look_feel.py @@ -470,6 +470,38 @@ class TBHierarchicalFields(DisplayedFields): # {{{ # }}} +class BDVerticalCats(DisplayedFields): # {{{ + + def __init__(self, db, parent=None, category_icons=None): + DisplayedFields.__init__(self, db, parent, category_icons=category_icons) + from calibre.gui2.ui import get_gui + self.gui = get_gui() + + def initialize(self, use_defaults=False, pref_data_override=None): + fm = self.db.field_metadata + cats = [k for k in fm if fm[k]['name'] and fm[k]['is_multiple']] + ans = [] + if use_defaults: + ans = [[k, False] for k in cats] + self.changed = True + elif pref_data_override: + ph = {k:v for k,v in pref_data_override} + ans = [[k, ph.get(k, False)] for k in cats] + self.changed = True + else: + vertical_cats = self.db.prefs.get('book_details_vertical_categories') or () + for key in cats: + ans.append([key, key in vertical_cats]) + self.beginResetModel() + self.fields = ans + self.endResetModel() + + def commit(self): + if self.changed: + self.db.prefs.set('book_details_vertical_categories', [k for k,v in self.fields if v]) +# }}} + + class Background(QWidget): # {{{ def __init__(self, parent): @@ -706,6 +738,10 @@ class ConfigWidget(ConfigWidgetBase, Ui_Form): self.tb_hierarchy_import_layout_button.clicked.connect(partial(self.import_layout, model=self.tb_hierarchical_cats_model)) + self.bd_vertical_cats_model = BDVerticalCats(self.gui.current_db, self.tb_hierarchical_cats) + self.bd_vertical_cats_model.dataChanged.connect(self.changed_signal) + self.bd_vertical_cats.setModel(self.bd_vertical_cats_model) + self.fill_tb_search_order_box() self.tb_search_order_up_button.clicked.connect(self.move_tb_search_up) self.tb_search_order_down_button.clicked.connect(self.move_tb_search_down) @@ -959,6 +995,7 @@ class ConfigWidget(ConfigWidgetBase, Ui_Form): self.tb_display_model.initialize() self.tb_categories_to_part_model.initialize() self.tb_hierarchical_cats_model.initialize() + self.bd_vertical_cats_model.initialize() db = self.gui.current_db mi = [] try: @@ -1022,6 +1059,7 @@ class ConfigWidget(ConfigWidgetBase, Ui_Form): self.display_model.restore_defaults() self.em_display_model.restore_defaults() self.qv_display_model.restore_defaults() + self.bd_vertical_cats_model.restore_defaults() gprefs.set('tb_search_order', gprefs.defaults['tb_search_order']) self.edit_rules.clear() self.icon_rules.clear() @@ -1097,6 +1135,7 @@ class ConfigWidget(ConfigWidgetBase, Ui_Form): self.tb_display_model.commit() self.tb_categories_to_part_model.commit() self.tb_hierarchical_cats_model.commit() + self.bd_vertical_cats_model.commit() self.tb_search_order_commit() self.edit_rules.commit(self.gui.current_db.prefs) self.icon_rules.commit(self.gui.current_db.prefs) diff --git a/src/calibre/gui2/preferences/look_feel.ui b/src/calibre/gui2/preferences/look_feel.ui index 940b3febb1..9ef0610c3f 100644 --- a/src/calibre/gui2/preferences/look_feel.ui +++ b/src/calibre/gui2/preferences/look_feel.ui @@ -733,14 +733,14 @@ A value of zero means calculate automatically. - + Create rules to convert &identifiers into links - + @@ -750,6 +750,25 @@ A value of zero means calculate automatically. + + + + Categories on separate lines + + + <p>Check the box if you want the category's values displayed on separate lines instead of separated by commas</p> + + + + + + true + + + + + + @@ -811,7 +830,7 @@ A value of zero means calculate automatically. - + @@ -855,7 +874,7 @@ A value of zero means calculate automatically. - +