This commit is contained in:
Kovid Goyal 2022-02-01 21:34:02 +05:30
commit ef109d55a2
No known key found for this signature in database
GPG Key ID: 06BC317B515ACE7C
6 changed files with 174 additions and 66 deletions

View File

@ -434,17 +434,6 @@ locale_for_sorting = ''
# columns. If False, one column is used. # columns. If False, one column is used.
metadata_single_use_2_cols_for_custom_fields = True metadata_single_use_2_cols_for_custom_fields = True
#: Order of custom column(s) in edit metadata
# Controls the order that custom columns are listed in edit metadata single
# and bulk. The columns listed in the tweak are displayed first and in the
# order provided. Any columns not listed are displayed after the listed ones,
# in alphabetical order. Do note that this tweak does not change the size of
# the edit widgets. Putting comments widgets in this list may result in some
# odd widget spacing when using two-column mode.
# Enter a comma-separated list of custom field lookup names, as in
# metadata_edit_custom_column_order = ['#genre', '#mytags', '#etc']
metadata_edit_custom_column_order = []
#: Edit metadata custom column label width and elision point #: Edit metadata custom column label width and elision point
# Set the width of custom column labels shown in the edit metadata dialogs. # Set the width of custom column labels shown in the edit metadata dialogs.
# If metadata_edit_elide_labels is True then labels wider than the width # If metadata_edit_elide_labels is True then labels wider than the width

View File

@ -6,6 +6,7 @@ __copyright__ = '2010, Kovid Goyal <kovid@kovidgoyal.net>'
__docformat__ = 'restructuredtext en' __docformat__ = 'restructuredtext en'
import os import os
from collections import OrderedDict
from functools import partial from functools import partial
from qt.core import (Qt, QComboBox, QLabel, QSpinBox, QDoubleSpinBox, from qt.core import (Qt, QComboBox, QLabel, QSpinBox, QDoubleSpinBox,
@ -749,10 +750,31 @@ widgets = {
def field_sort_key(y, fm=None): def field_sort_key(y, fm=None):
m1 = fm[y] m1 = fm[y]
name = icu_lower(m1['name']) name = icu_lower(m1['name'])
n1 = 'zzzzz' + name if m1['datatype'] == 'comments' and m1.get('display', {}).get('interpret_as') != 'short-text' else name n1 = 'zzzzz' + name if column_is_comments(y, fm) else name
return sort_key(n1) return sort_key(n1)
def column_is_comments(key, fm):
return (fm[key]['datatype'] == 'comments' and
fm[key].get('display', {}).get('interpret_as') != 'short-text')
def get_field_list(db, use_defaults=False):
fm = db.field_metadata
fields = fm.custom_field_keys(include_composites=False)
displayable = db.prefs.get('edit_metadata_custom_columns_to_display', None)
if use_defaults or displayable is None:
fields.sort(key=partial(field_sort_key, fm=fm))
return [(k, True) for k in fields]
else:
field_set = set(fields)
result = OrderedDict({k:v for k,v in displayable if k in field_set})
for k in fields:
if k not in result:
result[k] = True
return [(k,v) for k,v in result.items()]
def populate_metadata_page(layout, db, book_id, bulk=False, two_column=False, parent=None): def populate_metadata_page(layout, db, book_id, bulk=False, two_column=False, parent=None):
def widget_factory(typ, key): def widget_factory(typ, key):
if bulk: if bulk:
@ -765,36 +787,22 @@ def populate_metadata_page(layout, db, book_id, bulk=False, two_column=False, pa
fm = db.field_metadata fm = db.field_metadata
# Get list of all non-composite custom fields. We must make widgets for these # Get list of all non-composite custom fields. We must make widgets for these
fields = fm.custom_field_keys(include_composites=False) cols = [k[0] for k in get_field_list(db) if k[1]]
cols_to_display = fields # This deals with the historical behavior where comments fields go to the
cols_to_display.sort(key=partial(field_sort_key, fm=fm)) # bottom, starting on the left hand side. If a comment field is moved to
# somewhere else then it isn't moved to either side.
# This will contain the fields in the order to display them comments_at_end = 0
cols = [] for k in cols[::-1]:
if not column_is_comments(k, fm):
# The fields named here must be first in the widget list break
tweak_cols = tweaks['metadata_edit_custom_column_order'] comments_at_end += 1
comments_in_tweak = 0 comments_not_at_end = len([k for k in cols if column_is_comments(k, fm)]) - comments_at_end
for key in (tweak_cols or ()):
# Add the key if it really exists in the database
if key in cols_to_display:
cols.append(key)
if fm[key]['datatype'] == 'comments' and fm[key].get('display', {}).get('interpret_as') != 'short-text':
comments_in_tweak += 1
# Add all the remaining fields
comments_not_in_tweak = 0
for key in cols_to_display:
if key not in cols:
cols.append(key)
if fm[key]['datatype'] == 'comments' and fm[key].get('display', {}).get('interpret_as') != 'short-text':
comments_not_in_tweak += 1
count = len(cols) count = len(cols)
layout_rows_for_comments = 9 layout_rows_for_comments = 9
if two_column: if two_column:
turnover_point = int(((count - comments_not_in_tweak + 1) + turnover_point = int(((count - comments_at_end + 1) +
int(comments_in_tweak*(layout_rows_for_comments-1)))/2) int(comments_not_at_end*(layout_rows_for_comments-1)))/2)
else: else:
# Avoid problems with multi-line widgets # Avoid problems with multi-line widgets
turnover_point = count + 1000 turnover_point = count + 1000
@ -813,22 +821,22 @@ def populate_metadata_page(layout, db, book_id, bulk=False, two_column=False, pa
dt = fm[key]['datatype'] dt = fm[key]['datatype']
if dt == 'composite' or (bulk and dt == 'comments'): if dt == 'composite' or (bulk and dt == 'comments'):
continue continue
is_comments = dt == 'comments' and fm[key].get('display', {}).get('interpret_as') != 'short-text' is_comments = column_is_comments(key, fm)
w = widget_factory(dt, fm[key]['colnum']) w = widget_factory(dt, fm[key]['colnum'])
ans.append(w) ans.append(w)
if two_column and is_comments: if two_column and is_comments:
# Here for compatibility with old layout. Comments always started # Here for compatibility with old layout. Comments always started
# in the left column # in the left column
comments_in_tweak -= 1 comments_not_at_end -= 1
# no special processing if the comment field was named in the tweak # no special processing if the comment field was named in the tweak
if comments_in_tweak < 0 and comments_not_in_tweak > 0: if comments_not_at_end < 0 and comments_at_end > 0:
# Force a turnover, adding comments widgets below max_row. # Force a turnover, adding comments widgets below max_row.
# Save the row to return to if we turn over again # Save the row to return to if we turn over again
column = 0 column = 0
row = max_row row = max_row
base_row = row base_row = row
turnover_point = row + int((comments_not_in_tweak * layout_rows_for_comments)/2) turnover_point = row + int((comments_at_end * layout_rows_for_comments)/2)
comments_not_in_tweak = 0 comments_at_end = 0
l = QGridLayout() l = QGridLayout()
if is_comments: if is_comments:

View File

@ -76,10 +76,6 @@ class ConfigWidget(ConfigWidgetBase, Ui_Form):
r('bools_are_tristate', db.prefs, restart_required=True) r('bools_are_tristate', db.prefs, restart_required=True)
r('numeric_collation', prefs, restart_required=True) r('numeric_collation', prefs, restart_required=True)
r = self.register
choices = [(_('Default'), 'default'), (_('Compact Metadata'), 'alt1'),
(_('All on 1 tab'), 'alt2')]
r('edit_metadata_single_layout', gprefs, choices=choices)
def initialize(self): def initialize(self):
ConfigWidgetBase.initialize(self) ConfigWidgetBase.initialize(self)

View File

@ -75,13 +75,6 @@
</item> </item>
</widget> </widget>
</item> </item>
<item row="14" column="1">
<widget class="QComboBox" name="opt_edit_metadata_single_layout">
<property name="toolTip">
<string>Choose a different layout for the Edit metadata dialog. The compact metadata layout favors editing custom metadata over changing covers and formats.</string>
</property>
</widget>
</item>
<item row="15" column="0" colspan="2"> <item row="15" column="0" colspan="2">
<widget class="QGroupBox" name="groupBox_5"> <widget class="QGroupBox" name="groupBox_5">
<property name="sizePolicy"> <property name="sizePolicy">
@ -175,16 +168,6 @@
</property> </property>
</widget> </widget>
</item> </item>
<item row="14" column="0">
<widget class="QLabel" name="edit_metadata_single_label">
<property name="text">
<string>Edit metadata (single) &amp;layout:</string>
</property>
<property name="buddy">
<cstring>opt_edit_metadata_single_layout</cstring>
</property>
</widget>
</item>
</layout> </layout>
</item> </item>
<item> <item>

View File

@ -22,6 +22,7 @@ from calibre.ebooks.metadata.book.render import DEFAULT_AUTHOR_LINK
from calibre.constants import ismacos, iswindows from calibre.constants import ismacos, iswindows
from calibre.ebooks.metadata.sources.prefs import msprefs from calibre.ebooks.metadata.sources.prefs import msprefs
from calibre.gui2 import default_author_link from calibre.gui2 import default_author_link
from calibre.gui2.custom_column_widgets import get_field_list as em_get_field_list
from calibre.gui2.dialogs.template_dialog import TemplateDialog from calibre.gui2.dialogs.template_dialog import TemplateDialog
from calibre.gui2.preferences import ConfigWidgetBase, test_widget, CommaSeparatedList from calibre.gui2.preferences import ConfigWidgetBase, test_widget, CommaSeparatedList
from calibre.gui2.preferences.look_feel_ui import Ui_Form from calibre.gui2.preferences.look_feel_ui import Ui_Form
@ -259,8 +260,8 @@ class DisplayedFields(QAbstractListModel): # {{{
except: except:
pass pass
if not name: if not name:
name = field return field
return name return f'{name} ({field})'
if role == Qt.ItemDataRole.CheckStateRole: if role == Qt.ItemDataRole.CheckStateRole:
return Qt.CheckState.Checked if visible else Qt.CheckState.Unchecked return Qt.CheckState.Checked if visible else Qt.CheckState.Unchecked
if role == Qt.ItemDataRole.DecorationRole and field.startswith('#'): if role == Qt.ItemDataRole.DecorationRole and field.startswith('#'):
@ -328,6 +329,23 @@ def move_field_down(widget, model):
# }}} # }}}
class EMDisplayedFields(DisplayedFields): # {{{
def __init__(self, db, parent=None):
DisplayedFields.__init__(self, db, parent)
def initialize(self, use_defaults=False):
self.beginResetModel()
self.fields = [[x[0], x[1]] for x in
em_get_field_list(self.db, use_defaults=use_defaults)]
self.endResetModel()
self.changed = True
def commit(self):
if self.changed:
self.db.new_api.set_pref('edit_metadata_custom_columns_to_display', self.fields)
# }}}
class QVDisplayedFields(DisplayedFields): # {{{ class QVDisplayedFields(DisplayedFields): # {{{
def __init__(self, db, parent=None): def __init__(self, db, parent=None):
@ -515,6 +533,12 @@ class ConfigWidget(ConfigWidgetBase, Ui_Form):
key=lambda x:sort_key(x[0])) key=lambda x:sort_key(x[0]))
r('field_under_covers_in_grid', db.prefs, choices=choices) r('field_under_covers_in_grid', db.prefs, choices=choices)
choices = [(_('Default'), 'default'), (_('Compact Metadata'), 'alt1'),
(_('All on 1 tab'), 'alt2')]
r('edit_metadata_single_layout', gprefs,
choices=[(_('Default'), 'default'), (_('Compact Metadata'), 'alt1'),
(_('All on 1 tab'), 'alt2')])
self.current_font = self.initial_font = None self.current_font = self.initial_font = None
self.change_font_button.clicked.connect(self.change_font) self.change_font_button.clicked.connect(self.change_font)
@ -527,6 +551,15 @@ class ConfigWidget(ConfigWidgetBase, Ui_Form):
connect_lambda(self.df_down_button.clicked, self, connect_lambda(self.df_down_button.clicked, self,
lambda self: move_field_down(self.field_display_order, self.display_model)) lambda self: move_field_down(self.field_display_order, self.display_model))
self.em_display_model = EMDisplayedFields(self.gui.current_db,
self.em_display_order)
self.em_display_model.dataChanged.connect(self.changed_signal)
self.em_display_order.setModel(self.em_display_model)
connect_lambda(self.em_up_button.clicked, self,
lambda self: move_field_up(self.em_display_order, self.em_display_model))
connect_lambda(self.em_down_button.clicked, self,
lambda self: move_field_down(self.em_display_order, self.em_display_model))
self.qv_display_model = QVDisplayedFields(self.gui.current_db, self.qv_display_model = QVDisplayedFields(self.gui.current_db,
self.qv_display_order) self.qv_display_order)
self.qv_display_model.dataChanged.connect(self.changed_signal) self.qv_display_model.dataChanged.connect(self.changed_signal)
@ -648,6 +681,7 @@ class ConfigWidget(ConfigWidgetBase, Ui_Form):
self.current_font = self.initial_font = font self.current_font = self.initial_font = font
self.update_font_display() self.update_font_display()
self.display_model.initialize() self.display_model.initialize()
self.em_display_model.initialize()
self.qv_display_model.initialize() self.qv_display_model.initialize()
db = self.gui.current_db db = self.gui.current_db
mi = [] mi = []
@ -709,6 +743,7 @@ class ConfigWidget(ConfigWidgetBase, Ui_Form):
self.changed_signal.emit() self.changed_signal.emit()
self.update_font_display() self.update_font_display()
self.display_model.restore_defaults() self.display_model.restore_defaults()
self.em_display_model.restore_defaults()
self.qv_display_model.restore_defaults() self.qv_display_model.restore_defaults()
self.edit_rules.clear() self.edit_rules.clear()
self.icon_rules.clear() self.icon_rules.clear()
@ -779,6 +814,7 @@ class ConfigWidget(ConfigWidgetBase, Ui_Form):
QApplication.setFont(self.font_display.font()) QApplication.setFont(self.font_display.font())
rr = True rr = True
self.display_model.commit() self.display_model.commit()
self.em_display_model.commit()
self.qv_display_model.commit() self.qv_display_model.commit()
self.edit_rules.commit(self.gui.current_db.prefs) self.edit_rules.commit(self.gui.current_db.prefs)
self.icon_rules.commit(self.gui.current_db.prefs) self.icon_rules.commit(self.gui.current_db.prefs)

View File

@ -881,6 +881,102 @@ A value of zero means calculate automatically.</string>
</item> </item>
</layout> </layout>
</widget> </widget>
<widget class="QWidget" name="edit_metadata_tab">
<attribute name="icon">
<iconset resource="../../../../resources/images.qrc">
<normaloff>:/images/book.png</normaloff>:/images/book.png</iconset>
</attribute>
<attribute name="title">
<string>Edit metadata</string>
</attribute>
<layout class="QGridLayout" name="gridLayout_61">
<item row="1" column="0">
<layout class="QHBoxLayout" name="horizontalLayout1">
<item>
<widget class="QLabel" name="edit_metadata_single_label">
<property name="text">
<string>Edit metadata (single) &amp;layout:</string>
</property>
<property name="buddy">
<cstring>opt_edit_metadata_single_layout</cstring>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="opt_edit_metadata_single_layout">
<property name="toolTip">
<string>Choose a different layout for the Edit metadata dialog. The compact metadata layout favors editing custom metadata over changing covers and formats.</string>
</property>
</widget>
</item>
<item>
<spacer name="verticalSpacer_5">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
<item row="6" column="0">
<widget class="QGroupBox" name="groupBox">
<property name="title">
<string>Select the custom columns to display in the dialogs and their order</string>
</property>
<layout class="QGridLayout" name="gridLayout_3">
<item row="3" column="1">
<widget class="QToolButton" name="em_down_button">
<property name="toolTip">
<string>Move down</string>
</property>
<property name="icon">
<iconset resource="../../../../resources/images.qrc">
<normaloff>:/images/arrow-down.png</normaloff>:/images/arrow-down.png</iconset>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QToolButton" name="em_up_button">
<property name="toolTip">
<string>Move up</string>
</property>
<property name="icon">
<iconset resource="../../../../resources/images.qrc">
<normaloff>:/images/arrow-up.png</normaloff>:/images/arrow-up.png</iconset>
</property>
</widget>
</item>
<item row="2" column="1">
<spacer name="verticalSpacer_5">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
<item row="1" column="0" rowspan="3">
<widget class="QListView" name="em_display_order">
<property name="alternatingRowColors">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</widget>
</item>
</layout>
</widget>
<widget class="QWidget" name="tag_browser_tab"> <widget class="QWidget" name="tag_browser_tab">
<attribute name="icon"> <attribute name="icon">
<iconset resource="../../../../resources/images.qrc"> <iconset resource="../../../../resources/images.qrc">