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.
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
# 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

View File

@ -6,6 +6,7 @@ __copyright__ = '2010, Kovid Goyal <kovid@kovidgoyal.net>'
__docformat__ = 'restructuredtext en'
import os
from collections import OrderedDict
from functools import partial
from qt.core import (Qt, QComboBox, QLabel, QSpinBox, QDoubleSpinBox,
@ -749,10 +750,31 @@ widgets = {
def field_sort_key(y, fm=None):
m1 = fm[y]
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)
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 widget_factory(typ, key):
if bulk:
@ -765,36 +787,22 @@ def populate_metadata_page(layout, db, book_id, bulk=False, two_column=False, pa
fm = db.field_metadata
# Get list of all non-composite custom fields. We must make widgets for these
fields = fm.custom_field_keys(include_composites=False)
cols_to_display = fields
cols_to_display.sort(key=partial(field_sort_key, fm=fm))
# This will contain the fields in the order to display them
cols = []
# The fields named here must be first in the widget list
tweak_cols = tweaks['metadata_edit_custom_column_order']
comments_in_tweak = 0
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
cols = [k[0] for k in get_field_list(db) if k[1]]
# This deals with the historical behavior where comments fields go to the
# bottom, starting on the left hand side. If a comment field is moved to
# somewhere else then it isn't moved to either side.
comments_at_end = 0
for k in cols[::-1]:
if not column_is_comments(k, fm):
break
comments_at_end += 1
comments_not_at_end = len([k for k in cols if column_is_comments(k, fm)]) - comments_at_end
count = len(cols)
layout_rows_for_comments = 9
if two_column:
turnover_point = int(((count - comments_not_in_tweak + 1) +
int(comments_in_tweak*(layout_rows_for_comments-1)))/2)
turnover_point = int(((count - comments_at_end + 1) +
int(comments_not_at_end*(layout_rows_for_comments-1)))/2)
else:
# Avoid problems with multi-line widgets
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']
if dt == 'composite' or (bulk and dt == 'comments'):
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'])
ans.append(w)
if two_column and is_comments:
# Here for compatibility with old layout. Comments always started
# 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
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.
# Save the row to return to if we turn over again
column = 0
row = max_row
base_row = row
turnover_point = row + int((comments_not_in_tweak * layout_rows_for_comments)/2)
comments_not_in_tweak = 0
turnover_point = row + int((comments_at_end * layout_rows_for_comments)/2)
comments_at_end = 0
l = QGridLayout()
if is_comments:

View File

@ -76,10 +76,6 @@ class ConfigWidget(ConfigWidgetBase, Ui_Form):
r('bools_are_tristate', db.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):
ConfigWidgetBase.initialize(self)

View File

@ -75,13 +75,6 @@
</item>
</widget>
</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">
<widget class="QGroupBox" name="groupBox_5">
<property name="sizePolicy">
@ -175,16 +168,6 @@
</property>
</widget>
</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>
</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.ebooks.metadata.sources.prefs import msprefs
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.preferences import ConfigWidgetBase, test_widget, CommaSeparatedList
from calibre.gui2.preferences.look_feel_ui import Ui_Form
@ -259,8 +260,8 @@ class DisplayedFields(QAbstractListModel): # {{{
except:
pass
if not name:
name = field
return name
return field
return f'{name} ({field})'
if role == Qt.ItemDataRole.CheckStateRole:
return Qt.CheckState.Checked if visible else Qt.CheckState.Unchecked
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): # {{{
def __init__(self, db, parent=None):
@ -515,6 +533,12 @@ class ConfigWidget(ConfigWidgetBase, Ui_Form):
key=lambda x:sort_key(x[0]))
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.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,
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_order)
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.update_font_display()
self.display_model.initialize()
self.em_display_model.initialize()
self.qv_display_model.initialize()
db = self.gui.current_db
mi = []
@ -709,6 +743,7 @@ class ConfigWidget(ConfigWidgetBase, Ui_Form):
self.changed_signal.emit()
self.update_font_display()
self.display_model.restore_defaults()
self.em_display_model.restore_defaults()
self.qv_display_model.restore_defaults()
self.edit_rules.clear()
self.icon_rules.clear()
@ -779,6 +814,7 @@ class ConfigWidget(ConfigWidgetBase, Ui_Form):
QApplication.setFont(self.font_display.font())
rr = True
self.display_model.commit()
self.em_display_model.commit()
self.qv_display_model.commit()
self.edit_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>
</layout>
</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">
<attribute name="icon">
<iconset resource="../../../../resources/images.qrc">