mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-09 03:04:10 -04:00
move "Look & Feel/Book details" to its own widget
This commit is contained in:
parent
7622074887
commit
b32e1beaf4
@ -5,33 +5,11 @@ __license__ = 'GPL v3'
|
|||||||
__copyright__ = '2010, Kovid Goyal <kovid@kovidgoyal.net>'
|
__copyright__ = '2010, Kovid Goyal <kovid@kovidgoyal.net>'
|
||||||
__docformat__ = 'restructuredtext en'
|
__docformat__ = 'restructuredtext en'
|
||||||
|
|
||||||
from collections import defaultdict
|
|
||||||
from functools import partial
|
from functools import partial
|
||||||
|
|
||||||
from qt.core import (
|
from qt.core import QIcon, QKeySequence, QListWidgetItem, Qt
|
||||||
QComboBox,
|
|
||||||
QDialog,
|
|
||||||
QDialogButtonBox,
|
|
||||||
QFormLayout,
|
|
||||||
QHeaderView,
|
|
||||||
QIcon,
|
|
||||||
QKeySequence,
|
|
||||||
QLabel,
|
|
||||||
QLineEdit,
|
|
||||||
QListWidgetItem,
|
|
||||||
QPushButton,
|
|
||||||
QSize,
|
|
||||||
Qt,
|
|
||||||
QTableWidget,
|
|
||||||
QTableWidgetItem,
|
|
||||||
QVBoxLayout,
|
|
||||||
QWidget,
|
|
||||||
pyqtSignal,
|
|
||||||
)
|
|
||||||
|
|
||||||
from calibre.ebooks.metadata.book.render import DEFAULT_AUTHOR_LINK
|
from calibre.gui2 import gprefs
|
||||||
from calibre.ebooks.metadata.sources.prefs import msprefs
|
|
||||||
from calibre.gui2 import config, default_author_link, error_dialog, gprefs
|
|
||||||
from calibre.gui2.custom_column_widgets import get_field_list as em_get_field_list
|
from calibre.gui2.custom_column_widgets import get_field_list as em_get_field_list
|
||||||
from calibre.gui2.preferences import ConfigWidgetBase, test_widget
|
from calibre.gui2.preferences import ConfigWidgetBase, test_widget
|
||||||
from calibre.gui2.preferences.coloring import EditRules
|
from calibre.gui2.preferences.coloring import EditRules
|
||||||
@ -46,187 +24,6 @@ from calibre.gui2.preferences.look_feel_tabs import (
|
|||||||
)
|
)
|
||||||
from calibre.gui2.preferences.look_feel_ui import Ui_Form
|
from calibre.gui2.preferences.look_feel_ui import Ui_Form
|
||||||
from calibre.gui2.widgets import BusyCursor
|
from calibre.gui2.widgets import BusyCursor
|
||||||
from calibre.gui2.widgets2 import Dialog
|
|
||||||
from calibre.startup import connect_lambda
|
|
||||||
from calibre.utils.icu import sort_key
|
|
||||||
from calibre.utils.resources import get_path as P
|
|
||||||
from calibre.utils.resources import set_data
|
|
||||||
from polyglot.builtins import iteritems
|
|
||||||
|
|
||||||
|
|
||||||
class DefaultAuthorLink(QWidget): # {{{
|
|
||||||
|
|
||||||
changed_signal = pyqtSignal()
|
|
||||||
|
|
||||||
def __init__(self, parent):
|
|
||||||
QWidget.__init__(self, parent)
|
|
||||||
l = QVBoxLayout(parent)
|
|
||||||
l.addWidget(self)
|
|
||||||
l.setContentsMargins(0, 0, 0, 0)
|
|
||||||
l = QFormLayout(self)
|
|
||||||
l.setContentsMargins(0, 0, 0, 0)
|
|
||||||
l.setFieldGrowthPolicy(QFormLayout.FieldGrowthPolicy.AllNonFixedFieldsGrow)
|
|
||||||
self.choices = c = QComboBox()
|
|
||||||
c.setMinimumContentsLength(30)
|
|
||||||
for text, data in [
|
|
||||||
(_('Search for the author on Goodreads'), 'search-goodreads'),
|
|
||||||
(_('Search for the author on Amazon'), 'search-amzn'),
|
|
||||||
(_('Search for the author in your calibre library'), 'search-calibre'),
|
|
||||||
(_('Search for the author on Wikipedia'), 'search-wikipedia'),
|
|
||||||
(_('Search for the author on Google Books'), 'search-google'),
|
|
||||||
(_('Search for the book on Goodreads'), 'search-goodreads-book'),
|
|
||||||
(_('Search for the book on Amazon'), 'search-amzn-book'),
|
|
||||||
(_('Search for the book on Google Books'), 'search-google-book'),
|
|
||||||
(_('Use a custom search URL'), 'url'),
|
|
||||||
]:
|
|
||||||
c.addItem(text, data)
|
|
||||||
l.addRow(_('Clicking on &author names should:'), c)
|
|
||||||
self.custom_url = u = QLineEdit(self)
|
|
||||||
u.setToolTip(_(
|
|
||||||
'Enter the URL to search. It should contain the string {0}'
|
|
||||||
'\nwhich will be replaced by the author name. For example,'
|
|
||||||
'\n{1}').format('{author}', 'https://en.wikipedia.org/w/index.php?search={author}'))
|
|
||||||
u.textChanged.connect(self.changed_signal)
|
|
||||||
u.setPlaceholderText(_('Enter the URL'))
|
|
||||||
c.currentIndexChanged.connect(self.current_changed)
|
|
||||||
l.addRow(u)
|
|
||||||
self.current_changed()
|
|
||||||
c.currentIndexChanged.connect(self.changed_signal)
|
|
||||||
|
|
||||||
@property
|
|
||||||
def value(self):
|
|
||||||
k = self.choices.currentData()
|
|
||||||
if k == 'url':
|
|
||||||
return self.custom_url.text()
|
|
||||||
return k if k != DEFAULT_AUTHOR_LINK else None
|
|
||||||
|
|
||||||
@value.setter
|
|
||||||
def value(self, val):
|
|
||||||
i = self.choices.findData(val)
|
|
||||||
if i < 0:
|
|
||||||
i = self.choices.findData('url')
|
|
||||||
self.custom_url.setText(val)
|
|
||||||
self.choices.setCurrentIndex(i)
|
|
||||||
|
|
||||||
def current_changed(self):
|
|
||||||
k = self.choices.currentData()
|
|
||||||
self.custom_url.setVisible(k == 'url')
|
|
||||||
# }}}
|
|
||||||
|
|
||||||
|
|
||||||
# IdLinksEditor {{{
|
|
||||||
class IdLinksRuleEdit(Dialog):
|
|
||||||
|
|
||||||
def __init__(self, key='', name='', template='', parent=None):
|
|
||||||
title = _('Edit rule') if key else _('Create a new rule')
|
|
||||||
Dialog.__init__(self, title=title, name='id-links-rule-editor', parent=parent)
|
|
||||||
self.key.setText(key), self.nw.setText(name), self.template.setText(template or 'https://example.com/{id}')
|
|
||||||
if self.size().height() < self.sizeHint().height():
|
|
||||||
self.resize(self.sizeHint())
|
|
||||||
|
|
||||||
@property
|
|
||||||
def rule(self):
|
|
||||||
return self.key.text().lower(), self.nw.text(), self.template.text()
|
|
||||||
|
|
||||||
def setup_ui(self):
|
|
||||||
self.l = l = QFormLayout(self)
|
|
||||||
l.setFieldGrowthPolicy(QFormLayout.FieldGrowthPolicy.AllNonFixedFieldsGrow)
|
|
||||||
l.addRow(QLabel(_(
|
|
||||||
'The key of the identifier, for example, in isbn:XXX, the key is "isbn"')))
|
|
||||||
self.key = k = QLineEdit(self)
|
|
||||||
l.addRow(_('&Key:'), k)
|
|
||||||
l.addRow(QLabel(_(
|
|
||||||
'The name that will appear in the Book details panel')))
|
|
||||||
self.nw = n = QLineEdit(self)
|
|
||||||
l.addRow(_('&Name:'), n)
|
|
||||||
la = QLabel(_(
|
|
||||||
'The template used to create the link.'
|
|
||||||
' The placeholder {0} in the template will be replaced'
|
|
||||||
' with the actual identifier value. Use {1} to avoid the value'
|
|
||||||
' being quoted.').format('{id}', '{id_unquoted}'))
|
|
||||||
la.setWordWrap(True)
|
|
||||||
l.addRow(la)
|
|
||||||
self.template = t = QLineEdit(self)
|
|
||||||
l.addRow(_('&Template:'), t)
|
|
||||||
t.selectAll()
|
|
||||||
t.setFocus(Qt.FocusReason.OtherFocusReason)
|
|
||||||
l.addWidget(self.bb)
|
|
||||||
|
|
||||||
def accept(self):
|
|
||||||
r = self.rule
|
|
||||||
for i, which in enumerate([_('Key'), _('Name'), _('Template')]):
|
|
||||||
if not r[i]:
|
|
||||||
return error_dialog(self, _('Value needed'), _(
|
|
||||||
'The %s field cannot be empty') % which, show=True)
|
|
||||||
Dialog.accept(self)
|
|
||||||
|
|
||||||
|
|
||||||
class IdLinksEditor(Dialog):
|
|
||||||
|
|
||||||
def __init__(self, parent=None):
|
|
||||||
Dialog.__init__(self, title=_('Create rules for identifiers'), name='id-links-rules-editor', parent=parent)
|
|
||||||
|
|
||||||
def setup_ui(self):
|
|
||||||
self.l = l = QVBoxLayout(self)
|
|
||||||
self.la = la = QLabel(_(
|
|
||||||
'Create rules to convert identifiers into links.'))
|
|
||||||
la.setWordWrap(True)
|
|
||||||
l.addWidget(la)
|
|
||||||
items = []
|
|
||||||
for k, lx in iteritems(msprefs['id_link_rules']):
|
|
||||||
for n, t in lx:
|
|
||||||
items.append((k, n, t))
|
|
||||||
items.sort(key=lambda x: sort_key(x[1]))
|
|
||||||
self.table = t = QTableWidget(len(items), 3, self)
|
|
||||||
t.setHorizontalHeaderLabels([_('Key'), _('Name'), _('Template')])
|
|
||||||
for r, (key, val, template) in enumerate(items):
|
|
||||||
t.setItem(r, 0, QTableWidgetItem(key))
|
|
||||||
t.setItem(r, 1, QTableWidgetItem(val))
|
|
||||||
t.setItem(r, 2, QTableWidgetItem(template))
|
|
||||||
l.addWidget(t)
|
|
||||||
t.horizontalHeader().setSectionResizeMode(2, QHeaderView.ResizeMode.Stretch)
|
|
||||||
self.cb = b = QPushButton(QIcon.ic('plus.png'), _('&Add rule'), self)
|
|
||||||
connect_lambda(b.clicked, self, lambda self: self.edit_rule())
|
|
||||||
self.bb.addButton(b, QDialogButtonBox.ButtonRole.ActionRole)
|
|
||||||
self.rb = b = QPushButton(QIcon.ic('minus.png'), _('&Remove rule'), self)
|
|
||||||
connect_lambda(b.clicked, self, lambda self: self.remove_rule())
|
|
||||||
self.bb.addButton(b, QDialogButtonBox.ButtonRole.ActionRole)
|
|
||||||
self.eb = b = QPushButton(QIcon.ic('modified.png'), _('&Edit rule'), self)
|
|
||||||
connect_lambda(b.clicked, self, lambda self: self.edit_rule(self.table.currentRow()))
|
|
||||||
self.bb.addButton(b, QDialogButtonBox.ButtonRole.ActionRole)
|
|
||||||
l.addWidget(self.bb)
|
|
||||||
|
|
||||||
def sizeHint(self):
|
|
||||||
return QSize(700, 550)
|
|
||||||
|
|
||||||
def accept(self):
|
|
||||||
rules = defaultdict(list)
|
|
||||||
for r in range(self.table.rowCount()):
|
|
||||||
def item(c):
|
|
||||||
return self.table.item(r, c).text()
|
|
||||||
rules[item(0)].append([item(1), item(2)])
|
|
||||||
msprefs['id_link_rules'] = dict(rules)
|
|
||||||
Dialog.accept(self)
|
|
||||||
|
|
||||||
def edit_rule(self, r=-1):
|
|
||||||
key = name = template = ''
|
|
||||||
if r > -1:
|
|
||||||
key, name, template = (self.table.item(r, c).text() for c in range(3))
|
|
||||||
d = IdLinksRuleEdit(key, name, template, self)
|
|
||||||
if d.exec() == QDialog.DialogCode.Accepted:
|
|
||||||
if r < 0:
|
|
||||||
self.table.setRowCount(self.table.rowCount() + 1)
|
|
||||||
r = self.table.rowCount() - 1
|
|
||||||
rule = d.rule
|
|
||||||
for c in range(3):
|
|
||||||
self.table.setItem(r, c, QTableWidgetItem(rule[c]))
|
|
||||||
self.table.scrollToItem(self.table.item(r, 0))
|
|
||||||
|
|
||||||
def remove_rule(self):
|
|
||||||
r = self.table.currentRow()
|
|
||||||
if r > -1:
|
|
||||||
self.table.removeRow(r)
|
|
||||||
# }}}
|
|
||||||
|
|
||||||
|
|
||||||
class EMDisplayedFields(DisplayedFields): # {{{
|
class EMDisplayedFields(DisplayedFields): # {{{
|
||||||
@ -246,40 +43,6 @@ class EMDisplayedFields(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'] and not k.startswith('#')]
|
|
||||||
cats.append('path')
|
|
||||||
cats.extend([k for k in fm if fm[k]['name'] and fm[k]['is_multiple'] and k.startswith('#')])
|
|
||||||
ans = []
|
|
||||||
if use_defaults:
|
|
||||||
ans = [[k, False] for k in cats]
|
|
||||||
self.changed = True
|
|
||||||
elif pref_data_override:
|
|
||||||
ph = dict(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 ConfigWidget(ConfigWidgetBase, Ui_Form):
|
class ConfigWidget(ConfigWidgetBase, Ui_Form):
|
||||||
|
|
||||||
def genesis(self, gui):
|
def genesis(self, gui):
|
||||||
@ -289,17 +52,6 @@ class ConfigWidget(ConfigWidgetBase, Ui_Form):
|
|||||||
|
|
||||||
r = self.register
|
r = self.register
|
||||||
|
|
||||||
self.default_author_link = DefaultAuthorLink(self.default_author_link_container)
|
|
||||||
self.default_author_link.changed_signal.connect(self.changed_signal)
|
|
||||||
r('bd_show_cover', gprefs)
|
|
||||||
r('bd_overlay_cover_size', gprefs)
|
|
||||||
r('book_details_comments_heading_pos', gprefs, choices=[
|
|
||||||
(_('Never'), 'hide'), (_('Above text'), 'above'), (_('Beside text'), 'side')])
|
|
||||||
r('book_details_note_link_icon_width', gprefs)
|
|
||||||
self.id_links_button.clicked.connect(self.edit_id_link_rules)
|
|
||||||
|
|
||||||
r('use_roman_numerals_for_series_number', config)
|
|
||||||
|
|
||||||
choices = [(_('Default'), 'default'), (_('Compact metadata'), 'alt1'),
|
choices = [(_('Default'), 'default'), (_('Compact metadata'), 'alt1'),
|
||||||
(_('All on 1 tab'), 'alt2')]
|
(_('All on 1 tab'), 'alt2')]
|
||||||
r('edit_metadata_single_layout', gprefs,
|
r('edit_metadata_single_layout', gprefs,
|
||||||
@ -315,15 +67,6 @@ class ConfigWidget(ConfigWidgetBase, Ui_Form):
|
|||||||
r('edit_metadata_single_cc_label_length', gprefs)
|
r('edit_metadata_single_cc_label_length', gprefs)
|
||||||
r('edit_metadata_templates_only_F2_on_booklist', gprefs)
|
r('edit_metadata_templates_only_F2_on_booklist', gprefs)
|
||||||
|
|
||||||
self.display_model = DisplayedFields(self.gui.current_db, self.field_display_order)
|
|
||||||
self.display_model.dataChanged.connect(self.changed_signal)
|
|
||||||
self.field_display_order.setModel(self.display_model)
|
|
||||||
mu = partial(move_field_up, self.field_display_order, self.display_model)
|
|
||||||
md = partial(move_field_down, self.field_display_order, self.display_model)
|
|
||||||
self.df_up_button.clicked.connect(mu)
|
|
||||||
self.df_down_button.clicked.connect(md)
|
|
||||||
self.field_display_order.set_movement_functions(mu, md)
|
|
||||||
|
|
||||||
self.em_display_model = EMDisplayedFields(self.gui.current_db, self.em_display_order)
|
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_model.dataChanged.connect(self.changed_signal)
|
||||||
self.em_display_order.setModel(self.em_display_model)
|
self.em_display_order.setModel(self.em_display_model)
|
||||||
@ -336,10 +79,6 @@ class ConfigWidget(ConfigWidgetBase, Ui_Form):
|
|||||||
self.em_import_layout_button.clicked.connect(partial(import_layout, self, model=self.em_display_model))
|
self.em_import_layout_button.clicked.connect(partial(import_layout, self, model=self.em_display_model))
|
||||||
self.em_reset_layout_button.clicked.connect(partial(reset_layout, model=self.em_display_model))
|
self.em_reset_layout_button.clicked.connect(partial(reset_layout, model=self.em_display_model))
|
||||||
|
|
||||||
self.bd_vertical_cats_model = BDVerticalCats(self.gui.current_db, self.tb_hierarchy_tab.tb_hierarchical_cats)
|
|
||||||
self.bd_vertical_cats_model.dataChanged.connect(self.changed_signal)
|
|
||||||
self.bd_vertical_cats.setModel(self.bd_vertical_cats_model)
|
|
||||||
|
|
||||||
self.edit_rules = EditRules(self.tabWidget)
|
self.edit_rules = EditRules(self.tabWidget)
|
||||||
self.edit_rules.changed.connect(self.changed_signal)
|
self.edit_rules.changed.connect(self.changed_signal)
|
||||||
self.tabWidget.addTab(self.edit_rules, QIcon.ic('format-fill-color.png'), _('Column &coloring'))
|
self.tabWidget.addTab(self.edit_rules, QIcon.ic('format-fill-color.png'), _('Column &coloring'))
|
||||||
@ -354,11 +93,6 @@ class ConfigWidget(ConfigWidgetBase, Ui_Form):
|
|||||||
'Ctrl+Shift+F', QKeySequence.SequenceFormat.PortableText)]
|
'Ctrl+Shift+F', QKeySequence.SequenceFormat.PortableText)]
|
||||||
keys = [str(x.toString(QKeySequence.SequenceFormat.NativeText)) for x in keys]
|
keys = [str(x.toString(QKeySequence.SequenceFormat.NativeText)) for x in keys]
|
||||||
|
|
||||||
self.opt_book_details_css.textChanged.connect(self.changed_signal)
|
|
||||||
from calibre.gui2.tweak_book.editor.text import get_highlighter, get_theme
|
|
||||||
self.css_highlighter = get_highlighter('css')()
|
|
||||||
self.css_highlighter.apply_theme(get_theme(None))
|
|
||||||
self.css_highlighter.set_document(self.opt_book_details_css.document())
|
|
||||||
for i in range(self.tabWidget.count()):
|
for i in range(self.tabWidget.count()):
|
||||||
self.sections_view.addItem(QListWidgetItem(self.tabWidget.tabIcon(i), self.tabWidget.tabText(i).replace('&', '')))
|
self.sections_view.addItem(QListWidgetItem(self.tabWidget.tabIcon(i), self.tabWidget.tabText(i).replace('&', '')))
|
||||||
self.sections_view.setCurrentRow(self.tabWidget.currentIndex())
|
self.sections_view.setCurrentRow(self.tabWidget.currentIndex())
|
||||||
@ -371,58 +105,33 @@ class ConfigWidget(ConfigWidgetBase, Ui_Form):
|
|||||||
def initial_tab_changed(self):
|
def initial_tab_changed(self):
|
||||||
self.sections_view.setCurrentRow(self.tabWidget.currentIndex())
|
self.sections_view.setCurrentRow(self.tabWidget.currentIndex())
|
||||||
|
|
||||||
def edit_id_link_rules(self):
|
|
||||||
if IdLinksEditor(self).exec() == QDialog.DialogCode.Accepted:
|
|
||||||
self.changed_signal.emit()
|
|
||||||
|
|
||||||
def initialize(self):
|
def initialize(self):
|
||||||
ConfigWidgetBase.initialize(self)
|
ConfigWidgetBase.initialize(self)
|
||||||
|
|
||||||
self.default_author_link.value = default_author_link()
|
|
||||||
self.display_model.initialize()
|
|
||||||
self.em_display_model.initialize()
|
self.em_display_model.initialize()
|
||||||
self.bd_vertical_cats_model.initialize()
|
|
||||||
db = self.gui.current_db
|
db = self.gui.current_db
|
||||||
mi = selected_rows_metadatas()
|
mi = selected_rows_metadatas()
|
||||||
self.edit_rules.initialize(db.field_metadata, db.prefs, mi, 'column_color_rules')
|
self.edit_rules.initialize(db.field_metadata, db.prefs, mi, 'column_color_rules')
|
||||||
self.icon_rules.initialize(db.field_metadata, db.prefs, mi, 'column_icon_rules')
|
self.icon_rules.initialize(db.field_metadata, db.prefs, mi, 'column_icon_rules')
|
||||||
self.opt_book_details_css.blockSignals(True)
|
|
||||||
self.opt_book_details_css.setPlainText(P('templates/book_details.css', data=True).decode('utf-8'))
|
|
||||||
self.opt_book_details_css.blockSignals(False)
|
|
||||||
|
|
||||||
def restore_defaults(self):
|
def restore_defaults(self):
|
||||||
ConfigWidgetBase.restore_defaults(self)
|
ConfigWidgetBase.restore_defaults(self)
|
||||||
self.default_author_link.value = DEFAULT_AUTHOR_LINK
|
|
||||||
self.display_model.restore_defaults()
|
|
||||||
self.em_display_model.restore_defaults()
|
self.em_display_model.restore_defaults()
|
||||||
self.bd_vertical_cats_model.restore_defaults()
|
|
||||||
self.edit_rules.clear()
|
self.edit_rules.clear()
|
||||||
self.icon_rules.clear()
|
self.icon_rules.clear()
|
||||||
self.changed_signal.emit()
|
self.changed_signal.emit()
|
||||||
self.opt_book_details_css.setPlainText(P('templates/book_details.css', allow_user_override=False, data=True).decode('utf-8'))
|
|
||||||
|
|
||||||
def commit(self, *args):
|
def commit(self, *args):
|
||||||
with BusyCursor():
|
with BusyCursor():
|
||||||
self.display_model.commit()
|
|
||||||
self.em_display_model.commit()
|
self.em_display_model.commit()
|
||||||
self.bd_vertical_cats_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)
|
||||||
gprefs['default_author_link'] = self.default_author_link.value
|
|
||||||
bcss = self.opt_book_details_css.toPlainText().encode('utf-8')
|
|
||||||
defcss = P('templates/book_details.css', data=True, allow_user_override=False)
|
|
||||||
if defcss == bcss:
|
|
||||||
bcss = None
|
|
||||||
set_data('templates/book_details.css', bcss)
|
|
||||||
|
|
||||||
def refresh_gui(self, gui):
|
def refresh_gui(self, gui):
|
||||||
gui.book_details.book_info.refresh_css()
|
|
||||||
m = gui.library_view.model()
|
m = gui.library_view.model()
|
||||||
m.update_db_prefs_cache()
|
m.update_db_prefs_cache()
|
||||||
m.beginResetModel(), m.endResetModel()
|
m.beginResetModel(), m.endResetModel()
|
||||||
gui.tags_view.model().reset_tag_browser()
|
gui.tags_view.model().reset_tag_browser()
|
||||||
gui.library_view.refresh_book_details(force=True)
|
|
||||||
gui.library_view.refresh_composite_edit()
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
|
@ -37,7 +37,7 @@
|
|||||||
<string>Cover &grid</string>
|
<string>Cover &grid</string>
|
||||||
</attribute>
|
</attribute>
|
||||||
</widget>
|
</widget>
|
||||||
<widget class="QWidget" name="book_details_tab">
|
<widget class="BookDetailsTab" name="book_details_tab">
|
||||||
<attribute name="icon">
|
<attribute name="icon">
|
||||||
<iconset resource="../../../../resources/images.qrc">
|
<iconset resource="../../../../resources/images.qrc">
|
||||||
<normaloff>:/images/book.png</normaloff>:/images/book.png</iconset>
|
<normaloff>:/images/book.png</normaloff>:/images/book.png</iconset>
|
||||||
@ -45,243 +45,6 @@
|
|||||||
<attribute name="title">
|
<attribute name="title">
|
||||||
<string>&Book details</string>
|
<string>&Book details</string>
|
||||||
</attribute>
|
</attribute>
|
||||||
<layout class="QGridLayout" name="gridLayout_6">
|
|
||||||
<item row="6" column="0">
|
|
||||||
<widget class="QGroupBox" name="groupBox_5">
|
|
||||||
<property name="title">
|
|
||||||
<string>Text styling</string>
|
|
||||||
</property>
|
|
||||||
<layout class="QVBoxLayout" name="verticalLayout_3">
|
|
||||||
<item>
|
|
||||||
<widget class="QPlainTextEdit" name="opt_book_details_css"/>
|
|
||||||
</item>
|
|
||||||
</layout>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item row="5" column="0" colspan="3">
|
|
||||||
<widget class="QPushButton" name="id_links_button">
|
|
||||||
<property name="text">
|
|
||||||
<string>Create rules to convert &identifiers into links</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item row="3" column="0" colspan="3">
|
|
||||||
<widget class="QWidget" name="default_author_link_container" native="true">
|
|
||||||
<property name="sizePolicy">
|
|
||||||
<sizepolicy hsizetype="Preferred" vsizetype="Maximum">
|
|
||||||
<horstretch>0</horstretch>
|
|
||||||
<verstretch>0</verstretch>
|
|
||||||
</sizepolicy>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item row="6" column="2">
|
|
||||||
<widget class="QGroupBox" name="categories_on_separate_lines_group_box">
|
|
||||||
<property name="toolTip">
|
|
||||||
<string><p>Check the box if you want the category's values displayed on separate lines instead of separated by commas</p></string>
|
|
||||||
</property>
|
|
||||||
<property name="title">
|
|
||||||
<string>Categories on separate lines</string>
|
|
||||||
</property>
|
|
||||||
<layout class="QVBoxLayout" name="vblayout_3">
|
|
||||||
<item>
|
|
||||||
<widget class="QListView" name="bd_vertical_cats">
|
|
||||||
<property name="alternatingRowColors">
|
|
||||||
<bool>true</bool>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
</layout>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item row="6" column="1">
|
|
||||||
<widget class="QGroupBox" name="groupBox">
|
|
||||||
<property name="title">
|
|
||||||
<string>Select displayed metadata</string>
|
|
||||||
</property>
|
|
||||||
<layout class="QGridLayout" name="gridLayout_3">
|
|
||||||
<item row="3" column="1">
|
|
||||||
<widget class="QToolButton" name="df_down_button">
|
|
||||||
<property name="toolTip">
|
|
||||||
<string>Move down. Keyboard shortcut: Ctrl-Down arrow</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="df_up_button">
|
|
||||||
<property name="toolTip">
|
|
||||||
<string>Move up. Keyboard shortcut: Ctrl-Up arrow</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="ListViewWithMoveByKeyPress" name="field_display_order">
|
|
||||||
<property name="alternatingRowColors">
|
|
||||||
<bool>true</bool>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item row="4" column="0" colspan="2">
|
|
||||||
<widget class="QLabel" name="label_3">
|
|
||||||
<property name="text">
|
|
||||||
<string><p>Note: <b>comments</b>-like columns will always
|
|
||||||
be displayed at the end unless their "Heading position" is
|
|
||||||
"Show heading to the side".</p></string>
|
|
||||||
</property>
|
|
||||||
<property name="wordWrap">
|
|
||||||
<bool>true</bool>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
</layout>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item row="0" column="0" colspan="3">
|
|
||||||
<layout class="QHBoxLayout">
|
|
||||||
<item>
|
|
||||||
<widget class="QCheckBox" name="opt_bd_show_cover">
|
|
||||||
<property name="text">
|
|
||||||
<string>Show &cover</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<widget class="QCheckBox" name="opt_bd_overlay_cover_size">
|
|
||||||
<property name="toolTip">
|
|
||||||
<string>Show the size of the book's cover in pixels</string>
|
|
||||||
</property>
|
|
||||||
<property name="text">
|
|
||||||
<string>Show cover &size</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<widget class="QCheckBox" name="opt_use_roman_numerals_for_series_number">
|
|
||||||
<property name="text">
|
|
||||||
<string>Use &Roman numerals for series</string>
|
|
||||||
</property>
|
|
||||||
<property name="checked">
|
|
||||||
<bool>true</bool>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<spacer name="horizontalSpacer_bd1">
|
|
||||||
<property name="orientation">
|
|
||||||
<enum>Qt::Horizontal</enum>
|
|
||||||
</property>
|
|
||||||
<property name="sizeHint" stdset="0">
|
|
||||||
<size>
|
|
||||||
<width>20</width>
|
|
||||||
<height>0</height>
|
|
||||||
</size>
|
|
||||||
</property>
|
|
||||||
</spacer>
|
|
||||||
</item>
|
|
||||||
</layout>
|
|
||||||
</item>
|
|
||||||
<item row="1" column="0" colspan="3">
|
|
||||||
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
|
||||||
<item>
|
|
||||||
<widget class="QLabel" name="label_25">
|
|
||||||
<property name="text">
|
|
||||||
<string>Show comments &heading:</string>
|
|
||||||
</property>
|
|
||||||
<property name="buddy">
|
|
||||||
<cstring>opt_book_details_comments_heading_pos</cstring>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<widget class="QComboBox" name="opt_book_details_comments_heading_pos">
|
|
||||||
<property name="sizePolicy">
|
|
||||||
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
|
|
||||||
<horstretch>0</horstretch>
|
|
||||||
<verstretch>0</verstretch>
|
|
||||||
</sizepolicy>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<spacer name="horizontalSpacer_bd13">
|
|
||||||
<property name="orientation">
|
|
||||||
<enum>Qt::Horizontal</enum>
|
|
||||||
</property>
|
|
||||||
<property name="sizeHint" stdset="0">
|
|
||||||
<size>
|
|
||||||
<width>10</width>
|
|
||||||
<height>0</height>
|
|
||||||
</size>
|
|
||||||
</property>
|
|
||||||
</spacer>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<widget class="QLabel" name="label_1022">
|
|
||||||
<property name="text">
|
|
||||||
<string>Link and note icon si&ze:</string>
|
|
||||||
</property>
|
|
||||||
<property name="buddy">
|
|
||||||
<cstring>opt_book_details_note_link_icon_width</cstring>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<widget class="QDoubleSpinBox" name="opt_book_details_note_link_icon_width">
|
|
||||||
<property name="toolTip">
|
|
||||||
<string>Increase or decrease the size of the links and notes icons by this number. Larger
|
|
||||||
than one increases the icon size while smaller than one decreases it.</string>
|
|
||||||
</property>
|
|
||||||
<property name="decimals">
|
|
||||||
<number>1</number>
|
|
||||||
</property>
|
|
||||||
<property name="minimum">
|
|
||||||
<double>0.5</double>
|
|
||||||
</property>
|
|
||||||
<property name="maximum">
|
|
||||||
<double>4.0</double>
|
|
||||||
</property>
|
|
||||||
<property name="singleStep">
|
|
||||||
<double>0.1</double>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<spacer name="horizontalSpacer_bd13">
|
|
||||||
<property name="orientation">
|
|
||||||
<enum>Qt::Horizontal</enum>
|
|
||||||
</property>
|
|
||||||
<property name="sizeHint" stdset="0">
|
|
||||||
<size>
|
|
||||||
<width>30</width>
|
|
||||||
<height>0</height>
|
|
||||||
</size>
|
|
||||||
</property>
|
|
||||||
</spacer>
|
|
||||||
</item>
|
|
||||||
</layout>
|
|
||||||
</item>
|
|
||||||
</layout>
|
|
||||||
</widget>
|
</widget>
|
||||||
<widget class="QWidget" name="edit_metadata_tab">
|
<widget class="QWidget" name="edit_metadata_tab">
|
||||||
<attribute name="icon">
|
<attribute name="icon">
|
||||||
@ -631,6 +394,11 @@ columns". Editing with mouse clicks and the Tab key will be disabled.</p
|
|||||||
<extends>ConfigWidgetBase</extends>
|
<extends>ConfigWidgetBase</extends>
|
||||||
<header>calibre/gui2/preferences/look_feel_tabs/cover_grid.h</header>
|
<header>calibre/gui2/preferences/look_feel_tabs/cover_grid.h</header>
|
||||||
</customwidget>
|
</customwidget>
|
||||||
|
<customwidget>
|
||||||
|
<class>BookDetailsTab</class>
|
||||||
|
<extends>ConfigWidgetBase</extends>
|
||||||
|
<header>calibre/gui2/preferences/look_feel_tabs/book_details.h</header>
|
||||||
|
</customwidget>
|
||||||
<customwidget>
|
<customwidget>
|
||||||
<class>TbDisplayTab</class>
|
<class>TbDisplayTab</class>
|
||||||
<extends>ConfigWidgetBase</extends>
|
<extends>ConfigWidgetBase</extends>
|
||||||
|
@ -7,13 +7,76 @@ __docformat__ = 'restructuredtext en'
|
|||||||
|
|
||||||
import json
|
import json
|
||||||
|
|
||||||
from qt.core import QAbstractListModel, QIcon, QItemSelectionModel, Qt
|
from qt.core import QAbstractListModel, QComboBox, QFormLayout, QIcon, QItemSelectionModel, QLineEdit, Qt, QVBoxLayout, QWidget, pyqtSignal
|
||||||
|
|
||||||
|
from calibre.ebooks.metadata.book.render import DEFAULT_AUTHOR_LINK
|
||||||
from calibre.gui2 import choose_files, choose_save_file, error_dialog
|
from calibre.gui2 import choose_files, choose_save_file, error_dialog
|
||||||
from calibre.gui2.book_details import get_field_list
|
from calibre.gui2.book_details import get_field_list
|
||||||
from calibre.gui2.ui import get_gui
|
from calibre.gui2.ui import get_gui
|
||||||
|
|
||||||
|
|
||||||
|
class DefaultAuthorLink(QWidget):
|
||||||
|
|
||||||
|
changed_signal = pyqtSignal()
|
||||||
|
|
||||||
|
def __init__(self, parent):
|
||||||
|
QWidget.__init__(self, parent)
|
||||||
|
l = QVBoxLayout()
|
||||||
|
l.addWidget(self)
|
||||||
|
l.setContentsMargins(0, 0, 0, 0)
|
||||||
|
l = QFormLayout(self)
|
||||||
|
l.setContentsMargins(0, 0, 0, 0)
|
||||||
|
l.setFieldGrowthPolicy(QFormLayout.FieldGrowthPolicy.AllNonFixedFieldsGrow)
|
||||||
|
self.choices = c = QComboBox()
|
||||||
|
c.setMinimumContentsLength(30)
|
||||||
|
for text, data in [
|
||||||
|
(_('Search for the author on Goodreads'), 'search-goodreads'),
|
||||||
|
(_('Search for the author on Amazon'), 'search-amzn'),
|
||||||
|
(_('Search for the author in your calibre library'), 'search-calibre'),
|
||||||
|
(_('Search for the author on Wikipedia'), 'search-wikipedia'),
|
||||||
|
(_('Search for the author on Google Books'), 'search-google'),
|
||||||
|
(_('Search for the book on Goodreads'), 'search-goodreads-book'),
|
||||||
|
(_('Search for the book on Amazon'), 'search-amzn-book'),
|
||||||
|
(_('Search for the book on Google Books'), 'search-google-book'),
|
||||||
|
(_('Use a custom search URL'), 'url'),
|
||||||
|
]:
|
||||||
|
c.addItem(text, data)
|
||||||
|
l.addRow(_('Clicking on &author names should:'), c)
|
||||||
|
self.custom_url = u = QLineEdit(self)
|
||||||
|
u.setToolTip(_(
|
||||||
|
'Enter the URL to search. It should contain the string {0}'
|
||||||
|
'\nwhich will be replaced by the author name. For example,'
|
||||||
|
'\n{1}').format('{author}', 'https://en.wikipedia.org/w/index.php?search={author}'))
|
||||||
|
u.textChanged.connect(self.changed_signal)
|
||||||
|
u.setPlaceholderText(_('Enter the URL'))
|
||||||
|
c.currentIndexChanged.connect(self.current_changed)
|
||||||
|
l.addRow(u)
|
||||||
|
self.current_changed()
|
||||||
|
c.currentIndexChanged.connect(self.changed_signal)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def value(self):
|
||||||
|
k = self.choices.currentData()
|
||||||
|
if k == 'url':
|
||||||
|
return self.custom_url.text()
|
||||||
|
return k if k != DEFAULT_AUTHOR_LINK else None
|
||||||
|
|
||||||
|
@value.setter
|
||||||
|
def value(self, val):
|
||||||
|
i = self.choices.findData(val)
|
||||||
|
if i < 0:
|
||||||
|
i = self.choices.findData('url')
|
||||||
|
self.custom_url.setText(val)
|
||||||
|
self.choices.setCurrentIndex(i)
|
||||||
|
|
||||||
|
def current_changed(self):
|
||||||
|
k = self.choices.currentData()
|
||||||
|
self.custom_url.setVisible(k == 'url')
|
||||||
|
|
||||||
|
def restore_defaults(self):
|
||||||
|
self.value = DEFAULT_AUTHOR_LINK
|
||||||
|
|
||||||
|
|
||||||
class DisplayedFields(QAbstractListModel):
|
class DisplayedFields(QAbstractListModel):
|
||||||
|
|
||||||
def __init__(self, db, parent=None, pref_name=None, category_icons=None):
|
def __init__(self, db, parent=None, pref_name=None, category_icons=None):
|
||||||
|
256
src/calibre/gui2/preferences/look_feel_tabs/book_details.py
Normal file
256
src/calibre/gui2/preferences/look_feel_tabs/book_details.py
Normal file
@ -0,0 +1,256 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
|
||||||
|
__license__ = 'GPL v3'
|
||||||
|
__copyright__ = '2025, Kovid Goyal <kovid@kovidgoyal.net>'
|
||||||
|
__docformat__ = 'restructuredtext en'
|
||||||
|
|
||||||
|
|
||||||
|
from collections import defaultdict
|
||||||
|
from functools import partial
|
||||||
|
|
||||||
|
from qt.core import (
|
||||||
|
QDialog,
|
||||||
|
QDialogButtonBox,
|
||||||
|
QFormLayout,
|
||||||
|
QHeaderView,
|
||||||
|
QIcon,
|
||||||
|
QLabel,
|
||||||
|
QLineEdit,
|
||||||
|
QPushButton,
|
||||||
|
QSize,
|
||||||
|
Qt,
|
||||||
|
QTableWidget,
|
||||||
|
QTableWidgetItem,
|
||||||
|
QVBoxLayout,
|
||||||
|
)
|
||||||
|
|
||||||
|
from calibre.ebooks.metadata.sources.prefs import msprefs
|
||||||
|
from calibre.gui2 import config, default_author_link, error_dialog, gprefs
|
||||||
|
from calibre.gui2.preferences import LazyConfigWidgetBase
|
||||||
|
from calibre.gui2.preferences.look_feel_tabs import DisplayedFields, move_field_down, move_field_up
|
||||||
|
from calibre.gui2.preferences.look_feel_tabs.book_details_ui import Ui_Form
|
||||||
|
from calibre.gui2.widgets import BusyCursor
|
||||||
|
from calibre.gui2.widgets2 import Dialog
|
||||||
|
from calibre.startup import connect_lambda
|
||||||
|
from calibre.utils.icu import sort_key
|
||||||
|
from calibre.utils.resources import set_data
|
||||||
|
from polyglot.builtins import iteritems
|
||||||
|
|
||||||
|
|
||||||
|
class IdLinksRuleEdit(Dialog):
|
||||||
|
|
||||||
|
def __init__(self, key='', name='', template='', parent=None):
|
||||||
|
title = _('Edit rule') if key else _('Create a new rule')
|
||||||
|
Dialog.__init__(self, title=title, name='id-links-rule-editor', parent=parent)
|
||||||
|
self.key.setText(key), self.nw.setText(name), self.template.setText(template or 'https://example.com/{id}')
|
||||||
|
if self.size().height() < self.sizeHint().height():
|
||||||
|
self.resize(self.sizeHint())
|
||||||
|
|
||||||
|
@property
|
||||||
|
def rule(self):
|
||||||
|
return self.key.text().lower(), self.nw.text(), self.template.text()
|
||||||
|
|
||||||
|
def setup_ui(self):
|
||||||
|
self.l = l = QFormLayout(self)
|
||||||
|
l.setFieldGrowthPolicy(QFormLayout.FieldGrowthPolicy.AllNonFixedFieldsGrow)
|
||||||
|
l.addRow(QLabel(_(
|
||||||
|
'The key of the identifier, for example, in isbn:XXX, the key is "isbn"')))
|
||||||
|
self.key = k = QLineEdit(self)
|
||||||
|
l.addRow(_('&Key:'), k)
|
||||||
|
l.addRow(QLabel(_(
|
||||||
|
'The name that will appear in the Book details panel')))
|
||||||
|
self.nw = n = QLineEdit(self)
|
||||||
|
l.addRow(_('&Name:'), n)
|
||||||
|
la = QLabel(_(
|
||||||
|
'The template used to create the link.'
|
||||||
|
' The placeholder {0} in the template will be replaced'
|
||||||
|
' with the actual identifier value. Use {1} to avoid the value'
|
||||||
|
' being quoted.').format('{id}', '{id_unquoted}'))
|
||||||
|
la.setWordWrap(True)
|
||||||
|
l.addRow(la)
|
||||||
|
self.template = t = QLineEdit(self)
|
||||||
|
l.addRow(_('&Template:'), t)
|
||||||
|
t.selectAll()
|
||||||
|
t.setFocus(Qt.FocusReason.OtherFocusReason)
|
||||||
|
l.addWidget(self.bb)
|
||||||
|
|
||||||
|
def accept(self):
|
||||||
|
r = self.rule
|
||||||
|
for i, which in enumerate([_('Key'), _('Name'), _('Template')]):
|
||||||
|
if not r[i]:
|
||||||
|
return error_dialog(self, _('Value needed'), _(
|
||||||
|
'The %s field cannot be empty') % which, show=True)
|
||||||
|
Dialog.accept(self)
|
||||||
|
|
||||||
|
|
||||||
|
class IdLinksEditor(Dialog):
|
||||||
|
|
||||||
|
def __init__(self, parent=None):
|
||||||
|
Dialog.__init__(self, title=_('Create rules for identifiers'), name='id-links-rules-editor', parent=parent)
|
||||||
|
|
||||||
|
def setup_ui(self):
|
||||||
|
self.l = l = QVBoxLayout(self)
|
||||||
|
self.la = la = QLabel(_(
|
||||||
|
'Create rules to convert identifiers into links.'))
|
||||||
|
la.setWordWrap(True)
|
||||||
|
l.addWidget(la)
|
||||||
|
items = []
|
||||||
|
for k, lx in iteritems(msprefs['id_link_rules']):
|
||||||
|
for n, t in lx:
|
||||||
|
items.append((k, n, t))
|
||||||
|
items.sort(key=lambda x: sort_key(x[1]))
|
||||||
|
self.table = t = QTableWidget(len(items), 3, self)
|
||||||
|
t.setHorizontalHeaderLabels([_('Key'), _('Name'), _('Template')])
|
||||||
|
for r, (key, val, template) in enumerate(items):
|
||||||
|
t.setItem(r, 0, QTableWidgetItem(key))
|
||||||
|
t.setItem(r, 1, QTableWidgetItem(val))
|
||||||
|
t.setItem(r, 2, QTableWidgetItem(template))
|
||||||
|
l.addWidget(t)
|
||||||
|
t.horizontalHeader().setSectionResizeMode(2, QHeaderView.ResizeMode.Stretch)
|
||||||
|
self.cb = b = QPushButton(QIcon.ic('plus.png'), _('&Add rule'), self)
|
||||||
|
connect_lambda(b.clicked, self, lambda self: self.edit_rule())
|
||||||
|
self.bb.addButton(b, QDialogButtonBox.ButtonRole.ActionRole)
|
||||||
|
self.rb = b = QPushButton(QIcon.ic('minus.png'), _('&Remove rule'), self)
|
||||||
|
connect_lambda(b.clicked, self, lambda self: self.remove_rule())
|
||||||
|
self.bb.addButton(b, QDialogButtonBox.ButtonRole.ActionRole)
|
||||||
|
self.eb = b = QPushButton(QIcon.ic('modified.png'), _('&Edit rule'), self)
|
||||||
|
connect_lambda(b.clicked, self, lambda self: self.edit_rule(self.table.currentRow()))
|
||||||
|
self.bb.addButton(b, QDialogButtonBox.ButtonRole.ActionRole)
|
||||||
|
l.addWidget(self.bb)
|
||||||
|
|
||||||
|
def sizeHint(self):
|
||||||
|
return QSize(700, 550)
|
||||||
|
|
||||||
|
def accept(self):
|
||||||
|
rules = defaultdict(list)
|
||||||
|
for r in range(self.table.rowCount()):
|
||||||
|
def item(c):
|
||||||
|
return self.table.item(r, c).text()
|
||||||
|
rules[item(0)].append([item(1), item(2)])
|
||||||
|
msprefs['id_link_rules'] = dict(rules)
|
||||||
|
Dialog.accept(self)
|
||||||
|
|
||||||
|
def edit_rule(self, r=-1):
|
||||||
|
key = name = template = ''
|
||||||
|
if r > -1:
|
||||||
|
key, name, template = (self.table.item(r, c).text() for c in range(3))
|
||||||
|
d = IdLinksRuleEdit(key, name, template, self)
|
||||||
|
if d.exec() == QDialog.DialogCode.Accepted:
|
||||||
|
if r < 0:
|
||||||
|
self.table.setRowCount(self.table.rowCount() + 1)
|
||||||
|
r = self.table.rowCount() - 1
|
||||||
|
rule = d.rule
|
||||||
|
for c in range(3):
|
||||||
|
self.table.setItem(r, c, QTableWidgetItem(rule[c]))
|
||||||
|
self.table.scrollToItem(self.table.item(r, 0))
|
||||||
|
|
||||||
|
def remove_rule(self):
|
||||||
|
r = self.table.currentRow()
|
||||||
|
if r > -1:
|
||||||
|
self.table.removeRow(r)
|
||||||
|
|
||||||
|
|
||||||
|
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'] and not k.startswith('#')]
|
||||||
|
cats.append('path')
|
||||||
|
cats.extend([k for k in fm if fm[k]['name'] and fm[k]['is_multiple'] and k.startswith('#')])
|
||||||
|
ans = []
|
||||||
|
if use_defaults:
|
||||||
|
ans = [[k, False] for k in cats]
|
||||||
|
self.changed = True
|
||||||
|
elif pref_data_override:
|
||||||
|
ph = dict(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 BookDetailsTab(LazyConfigWidgetBase, Ui_Form):
|
||||||
|
|
||||||
|
def genesis(self, gui):
|
||||||
|
self.gui = gui
|
||||||
|
r = self.register
|
||||||
|
|
||||||
|
self.default_author_link.changed_signal.connect(self.changed_signal)
|
||||||
|
r('bd_show_cover', gprefs)
|
||||||
|
r('bd_overlay_cover_size', gprefs)
|
||||||
|
r('book_details_comments_heading_pos', gprefs, choices=[
|
||||||
|
(_('Never'), 'hide'), (_('Above text'), 'above'), (_('Beside text'), 'side')])
|
||||||
|
r('book_details_note_link_icon_width', gprefs)
|
||||||
|
self.id_links_button.clicked.connect(self.edit_id_link_rules)
|
||||||
|
|
||||||
|
r('use_roman_numerals_for_series_number', config)
|
||||||
|
|
||||||
|
self.bd_vertical_cats_model = BDVerticalCats(self.gui.current_db, parent=self)
|
||||||
|
self.bd_vertical_cats_model.dataChanged.connect(self.changed_signal)
|
||||||
|
self.bd_vertical_cats.setModel(self.bd_vertical_cats_model)
|
||||||
|
|
||||||
|
self.display_model = DisplayedFields(self.gui.current_db, self.field_display_order)
|
||||||
|
self.display_model.dataChanged.connect(self.changed_signal)
|
||||||
|
self.field_display_order.setModel(self.display_model)
|
||||||
|
mu = partial(move_field_up, self.field_display_order, self.display_model)
|
||||||
|
md = partial(move_field_down, self.field_display_order, self.display_model)
|
||||||
|
self.df_up_button.clicked.connect(mu)
|
||||||
|
self.df_down_button.clicked.connect(md)
|
||||||
|
self.field_display_order.set_movement_functions(mu, md)
|
||||||
|
|
||||||
|
self.opt_book_details_css.textChanged.connect(self.changed_signal)
|
||||||
|
from calibre.gui2.tweak_book.editor.text import get_highlighter, get_theme
|
||||||
|
self.css_highlighter = get_highlighter('css')()
|
||||||
|
self.css_highlighter.apply_theme(get_theme(None))
|
||||||
|
self.css_highlighter.set_document(self.opt_book_details_css.document())
|
||||||
|
|
||||||
|
def lazy_initialize(self):
|
||||||
|
self.default_author_link.value = default_author_link()
|
||||||
|
self.display_model.initialize()
|
||||||
|
self.blockSignals(True)
|
||||||
|
self.bd_vertical_cats_model.initialize()
|
||||||
|
self.opt_book_details_css.setPlainText(P('templates/book_details.css', data=True).decode('utf-8'))
|
||||||
|
self.blockSignals(False)
|
||||||
|
|
||||||
|
def edit_id_link_rules(self):
|
||||||
|
if IdLinksEditor(self).exec() == QDialog.DialogCode.Accepted:
|
||||||
|
self.changed_signal.emit()
|
||||||
|
|
||||||
|
def commit(self):
|
||||||
|
with BusyCursor():
|
||||||
|
self.display_model.commit()
|
||||||
|
self.bd_vertical_cats_model.commit()
|
||||||
|
gprefs['default_author_link'] = self.default_author_link.value
|
||||||
|
bcss = self.opt_book_details_css.toPlainText().encode('utf-8')
|
||||||
|
defcss = P('templates/book_details.css', data=True, allow_user_override=False)
|
||||||
|
if defcss == bcss:
|
||||||
|
bcss = None
|
||||||
|
set_data('templates/book_details.css', bcss)
|
||||||
|
return LazyConfigWidgetBase.commit(self)
|
||||||
|
|
||||||
|
def restore_defaults(self):
|
||||||
|
LazyConfigWidgetBase.restore_defaults(self)
|
||||||
|
self.default_author_link.restore_defaults()
|
||||||
|
self.display_model.restore_defaults()
|
||||||
|
self.bd_vertical_cats_model.restore_defaults()
|
||||||
|
self.opt_book_details_css.setPlainText(P('templates/book_details.css', allow_user_override=False, data=True).decode('utf-8'))
|
||||||
|
self.changed_signal.emit()
|
||||||
|
|
||||||
|
def refresh_gui(self, gui):
|
||||||
|
gui.book_details.book_info.refresh_css()
|
||||||
|
gui.library_view.refresh_book_details(force=True)
|
||||||
|
gui.library_view.refresh_composite_edit()
|
258
src/calibre/gui2/preferences/look_feel_tabs/book_details.ui
Normal file
258
src/calibre/gui2/preferences/look_feel_tabs/book_details.ui
Normal file
@ -0,0 +1,258 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<ui version="4.0">
|
||||||
|
<class>Form</class>
|
||||||
|
<widget class="QWidget" name="book_details_tab">
|
||||||
|
<layout class="QGridLayout" name="gridLayout_6">
|
||||||
|
<item row="6" column="0">
|
||||||
|
<widget class="QGroupBox" name="groupBox_5">
|
||||||
|
<property name="title">
|
||||||
|
<string>Text styling</string>
|
||||||
|
</property>
|
||||||
|
<layout class="QVBoxLayout" name="verticalLayout_3">
|
||||||
|
<item>
|
||||||
|
<widget class="QPlainTextEdit" name="opt_book_details_css"/>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="5" column="0" colspan="3">
|
||||||
|
<widget class="QPushButton" name="id_links_button">
|
||||||
|
<property name="text">
|
||||||
|
<string>Create rules to convert &identifiers into links</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="3" column="0" colspan="3">
|
||||||
|
<widget class="DefaultAuthorLink" name="default_author_link" native="true">
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Preferred" vsizetype="Maximum">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="6" column="2">
|
||||||
|
<widget class="QGroupBox" name="categories_on_separate_lines_group_box">
|
||||||
|
<property name="toolTip">
|
||||||
|
<string><p>Check the box if you want the category's values displayed on separate lines instead of separated by commas</p></string>
|
||||||
|
</property>
|
||||||
|
<property name="title">
|
||||||
|
<string>Categories on separate lines</string>
|
||||||
|
</property>
|
||||||
|
<layout class="QVBoxLayout" name="vblayout_3">
|
||||||
|
<item>
|
||||||
|
<widget class="QListView" name="bd_vertical_cats">
|
||||||
|
<property name="alternatingRowColors">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="6" column="1">
|
||||||
|
<widget class="QGroupBox" name="groupBox">
|
||||||
|
<property name="title">
|
||||||
|
<string>Select displayed metadata</string>
|
||||||
|
</property>
|
||||||
|
<layout class="QGridLayout" name="gridLayout_3">
|
||||||
|
<item row="3" column="1">
|
||||||
|
<widget class="QToolButton" name="df_down_button">
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>Move down. Keyboard shortcut: Ctrl-Down arrow</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="df_up_button">
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>Move up. Keyboard shortcut: Ctrl-Up arrow</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="ListViewWithMoveByKeyPress" name="field_display_order">
|
||||||
|
<property name="alternatingRowColors">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="4" column="0" colspan="2">
|
||||||
|
<widget class="QLabel" name="label_3">
|
||||||
|
<property name="text">
|
||||||
|
<string><p>Note: <b>comments</b>-like columns will always
|
||||||
|
be displayed at the end unless their "Heading position" is
|
||||||
|
"Show heading to the side".</p></string>
|
||||||
|
</property>
|
||||||
|
<property name="wordWrap">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="0" column="0" colspan="3">
|
||||||
|
<layout class="QHBoxLayout">
|
||||||
|
<item>
|
||||||
|
<widget class="QCheckBox" name="opt_bd_show_cover">
|
||||||
|
<property name="text">
|
||||||
|
<string>Show &cover</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QCheckBox" name="opt_bd_overlay_cover_size">
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>Show the size of the book's cover in pixels</string>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Show cover &size</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QCheckBox" name="opt_use_roman_numerals_for_series_number">
|
||||||
|
<property name="text">
|
||||||
|
<string>Use &Roman numerals for series</string>
|
||||||
|
</property>
|
||||||
|
<property name="checked">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<spacer name="horizontalSpacer_bd1">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Horizontal</enum>
|
||||||
|
</property>
|
||||||
|
<property name="sizeHint" stdset="0">
|
||||||
|
<size>
|
||||||
|
<width>20</width>
|
||||||
|
<height>0</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
</spacer>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
<item row="1" column="0" colspan="3">
|
||||||
|
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="label_25">
|
||||||
|
<property name="text">
|
||||||
|
<string>Show comments &heading:</string>
|
||||||
|
</property>
|
||||||
|
<property name="buddy">
|
||||||
|
<cstring>opt_book_details_comments_heading_pos</cstring>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QComboBox" name="opt_book_details_comments_heading_pos">
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<spacer name="horizontalSpacer_bd13">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Horizontal</enum>
|
||||||
|
</property>
|
||||||
|
<property name="sizeHint" stdset="0">
|
||||||
|
<size>
|
||||||
|
<width>10</width>
|
||||||
|
<height>0</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
</spacer>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="label_1022">
|
||||||
|
<property name="text">
|
||||||
|
<string>Link and note icon si&ze:</string>
|
||||||
|
</property>
|
||||||
|
<property name="buddy">
|
||||||
|
<cstring>opt_book_details_note_link_icon_width</cstring>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QDoubleSpinBox" name="opt_book_details_note_link_icon_width">
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>Increase or decrease the size of the links and notes icons by this number. Larger
|
||||||
|
than one increases the icon size while smaller than one decreases it.</string>
|
||||||
|
</property>
|
||||||
|
<property name="decimals">
|
||||||
|
<number>1</number>
|
||||||
|
</property>
|
||||||
|
<property name="minimum">
|
||||||
|
<double>0.5</double>
|
||||||
|
</property>
|
||||||
|
<property name="maximum">
|
||||||
|
<double>4.0</double>
|
||||||
|
</property>
|
||||||
|
<property name="singleStep">
|
||||||
|
<double>0.1</double>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<spacer name="horizontalSpacer_bd13">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Horizontal</enum>
|
||||||
|
</property>
|
||||||
|
<property name="sizeHint" stdset="0">
|
||||||
|
<size>
|
||||||
|
<width>30</width>
|
||||||
|
<height>0</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
</spacer>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
<customwidgets>
|
||||||
|
<customwidget>
|
||||||
|
<class>ListViewWithMoveByKeyPress</class>
|
||||||
|
<extends>QListView</extends>
|
||||||
|
<header>calibre/gui2/preferences.h</header>
|
||||||
|
</customwidget>
|
||||||
|
<customwidget>
|
||||||
|
<class>DefaultAuthorLink</class>
|
||||||
|
<extends>QWidget</extends>
|
||||||
|
<header>calibre/gui2/preferences/look_feel_tabs.h</header>
|
||||||
|
</customwidget>
|
||||||
|
</customwidgets>
|
||||||
|
<resources>
|
||||||
|
<include location="../../../../resources/images.qrc"/>
|
||||||
|
</resources>
|
||||||
|
</ui>
|
Loading…
x
Reference in New Issue
Block a user