mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-09 03:04:10 -04:00
Merge branch 'split-look_feel' of https://github.com/un-pogaz/calibre
This commit is contained in:
commit
2a8f7de119
@ -5,621 +5,23 @@ __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 qt.core import QKeySequence, QListWidgetItem, Qt
|
||||||
from functools import partial
|
|
||||||
from threading import Thread
|
|
||||||
|
|
||||||
from qt.core import (
|
from calibre.gui2.preferences import ConfigWidgetBase, test_widget
|
||||||
QApplication,
|
|
||||||
QBrush,
|
|
||||||
QColor,
|
|
||||||
QColorDialog,
|
|
||||||
QComboBox,
|
|
||||||
QDialog,
|
|
||||||
QDialogButtonBox,
|
|
||||||
QFont,
|
|
||||||
QFontDialog,
|
|
||||||
QFontInfo,
|
|
||||||
QFormLayout,
|
|
||||||
QHeaderView,
|
|
||||||
QIcon,
|
|
||||||
QKeySequence,
|
|
||||||
QLabel,
|
|
||||||
QLineEdit,
|
|
||||||
QListWidgetItem,
|
|
||||||
QPainter,
|
|
||||||
QPixmap,
|
|
||||||
QPushButton,
|
|
||||||
QSize,
|
|
||||||
QSizePolicy,
|
|
||||||
Qt,
|
|
||||||
QTableWidget,
|
|
||||||
QTableWidgetItem,
|
|
||||||
QVBoxLayout,
|
|
||||||
QWidget,
|
|
||||||
pyqtSignal,
|
|
||||||
)
|
|
||||||
|
|
||||||
from calibre import human_readable
|
|
||||||
from calibre.constants import ismacos, iswindows
|
|
||||||
from calibre.ebooks.metadata.book.render import DEFAULT_AUTHOR_LINK
|
|
||||||
from calibre.ebooks.metadata.sources.prefs import msprefs
|
|
||||||
from calibre.gui2 import config, default_author_link, error_dialog, gprefs, icon_resource_manager, open_local_file, qt_app, question_dialog
|
|
||||||
from calibre.gui2.custom_column_widgets import get_field_list as em_get_field_list
|
|
||||||
from calibre.gui2.dialogs.quickview import get_qv_field_list
|
|
||||||
from calibre.gui2.library.alternate_views import CM_TO_INCH, auto_height
|
|
||||||
from calibre.gui2.preferences import ConfigWidgetBase, Setting, set_help_tips, test_widget
|
|
||||||
from calibre.gui2.preferences.coloring import EditRules
|
|
||||||
from calibre.gui2.preferences.look_feel_tabs import DisplayedFields, export_layout, import_layout, move_field_down, move_field_up, reset_layout
|
|
||||||
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.widgets2 import Dialog
|
|
||||||
from calibre.startup import connect_lambda
|
|
||||||
from calibre.utils.config import prefs
|
|
||||||
from calibre.utils.icu import sort_key
|
|
||||||
from calibre.utils.localization import available_translations, get_lang, get_language
|
|
||||||
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): # {{{
|
|
||||||
def __init__(self, db, parent=None):
|
|
||||||
DisplayedFields.__init__(self, db, parent)
|
|
||||||
|
|
||||||
def initialize(self, use_defaults=False, pref_data_override=None):
|
|
||||||
self.beginResetModel()
|
|
||||||
self.fields = [[x[0], x[1]] for x in
|
|
||||||
em_get_field_list(self.db, use_defaults=use_defaults, pref_data_override=pref_data_override)]
|
|
||||||
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):
|
|
||||||
DisplayedFields.__init__(self, db, parent)
|
|
||||||
|
|
||||||
def initialize(self, use_defaults=False):
|
|
||||||
self.beginResetModel()
|
|
||||||
self.fields = [[x[0], x[1]] for x in
|
|
||||||
get_qv_field_list(self.db.field_metadata, use_defaults=use_defaults)]
|
|
||||||
self.endResetModel()
|
|
||||||
self.changed = True
|
|
||||||
|
|
||||||
def commit(self):
|
|
||||||
if self.changed:
|
|
||||||
self.db.new_api.set_pref('qv_display_fields', self.fields)
|
|
||||||
# }}}
|
|
||||||
|
|
||||||
|
|
||||||
class TBDisplayedFields(DisplayedFields): # {{{
|
|
||||||
# The code in this class depends on the fact that the tag browser is
|
|
||||||
# initialized before this class is instantiated.
|
|
||||||
|
|
||||||
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):
|
|
||||||
tv = self.gui.tags_view
|
|
||||||
cat_ord = tv.model().get_ordered_categories(use_defaults=use_defaults,
|
|
||||||
pref_data_override=pref_data_override)
|
|
||||||
if use_defaults:
|
|
||||||
hc = []
|
|
||||||
self.changed = True
|
|
||||||
elif pref_data_override:
|
|
||||||
hc = [k for k,v in pref_data_override if not v]
|
|
||||||
self.changed = True
|
|
||||||
else:
|
|
||||||
hc = tv.hidden_categories
|
|
||||||
|
|
||||||
self.beginResetModel()
|
|
||||||
self.fields = [[x, x not in hc] for x in cat_ord]
|
|
||||||
self.endResetModel()
|
|
||||||
|
|
||||||
def commit(self):
|
|
||||||
if self.changed:
|
|
||||||
self.db.prefs.set('tag_browser_hidden_categories', [k for k,v in self.fields if not v])
|
|
||||||
self.db.prefs.set('tag_browser_category_order', [k for k,v in self.fields])
|
|
||||||
# }}}
|
|
||||||
|
|
||||||
|
|
||||||
class TBPartitionedFields(DisplayedFields): # {{{
|
|
||||||
# The code in this class depends on the fact that the tag browser is
|
|
||||||
# initialized before this class is instantiated.
|
|
||||||
|
|
||||||
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 filter_user_categories(self, tv):
|
|
||||||
cats = tv.model().categories
|
|
||||||
answer = {}
|
|
||||||
filtered = set()
|
|
||||||
for key,name in cats.items():
|
|
||||||
if key.startswith('@'):
|
|
||||||
key = key.partition('.')[0]
|
|
||||||
name = key[1:]
|
|
||||||
if key not in filtered:
|
|
||||||
answer[key] = name
|
|
||||||
filtered.add(key)
|
|
||||||
return answer
|
|
||||||
|
|
||||||
def initialize(self, use_defaults=False, pref_data_override=None):
|
|
||||||
tv = self.gui.tags_view
|
|
||||||
cats = self.filter_user_categories(tv)
|
|
||||||
ans = []
|
|
||||||
if use_defaults:
|
|
||||||
ans = [[k, True] for k in cats.keys()]
|
|
||||||
self.changed = True
|
|
||||||
elif pref_data_override:
|
|
||||||
po = dict(pref_data_override)
|
|
||||||
ans = [[k, po.get(k, True)] for k in cats.keys()]
|
|
||||||
self.changed = True
|
|
||||||
else:
|
|
||||||
# Check if setting not migrated yet
|
|
||||||
cats_to_partition = frozenset(self.db.prefs.get('tag_browser_dont_collapse', gprefs.get('tag_browser_dont_collapse')) or ())
|
|
||||||
for key in cats:
|
|
||||||
ans.append([key, key not in cats_to_partition])
|
|
||||||
self.beginResetModel()
|
|
||||||
self.fields = ans
|
|
||||||
self.endResetModel()
|
|
||||||
|
|
||||||
def commit(self):
|
|
||||||
if self.changed:
|
|
||||||
# Migrate to a per-library setting
|
|
||||||
self.db.prefs.set('tag_browser_dont_collapse', [k for k,v in self.fields if not v])
|
|
||||||
# }}}
|
|
||||||
|
|
||||||
|
|
||||||
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 Background(QWidget): # {{{
|
|
||||||
|
|
||||||
def __init__(self, parent):
|
|
||||||
QWidget.__init__(self, parent)
|
|
||||||
self.bcol = QColor(*gprefs['cover_grid_color'])
|
|
||||||
self.btex = gprefs['cover_grid_texture']
|
|
||||||
self.update_brush()
|
|
||||||
self.setSizePolicy(QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Fixed)
|
|
||||||
|
|
||||||
def update_brush(self):
|
|
||||||
self.brush = QBrush(self.bcol)
|
|
||||||
if self.btex:
|
|
||||||
from calibre.gui2.preferences.texture_chooser import texture_path
|
|
||||||
path = texture_path(self.btex)
|
|
||||||
if path:
|
|
||||||
p = QPixmap(path)
|
|
||||||
try:
|
|
||||||
dpr = self.devicePixelRatioF()
|
|
||||||
except AttributeError:
|
|
||||||
dpr = self.devicePixelRatio()
|
|
||||||
p.setDevicePixelRatio(dpr)
|
|
||||||
self.brush.setTexture(p)
|
|
||||||
self.update()
|
|
||||||
|
|
||||||
def sizeHint(self):
|
|
||||||
return QSize(200, 120)
|
|
||||||
|
|
||||||
def paintEvent(self, ev):
|
|
||||||
painter = QPainter(self)
|
|
||||||
painter.fillRect(ev.rect(), self.brush)
|
|
||||||
painter.end()
|
|
||||||
# }}}
|
|
||||||
|
|
||||||
|
|
||||||
class LanguageSetting(Setting):
|
|
||||||
|
|
||||||
def commit(self):
|
|
||||||
val = self.get_gui_val()
|
|
||||||
oldval = self.get_config_val()
|
|
||||||
if val != oldval:
|
|
||||||
gprefs.set('last_used_language', oldval)
|
|
||||||
return super().commit()
|
|
||||||
|
|
||||||
|
|
||||||
class ConfigWidget(ConfigWidgetBase, Ui_Form):
|
class ConfigWidget(ConfigWidgetBase, Ui_Form):
|
||||||
|
|
||||||
size_calculated = pyqtSignal(object)
|
|
||||||
|
|
||||||
def genesis(self, gui):
|
def genesis(self, gui):
|
||||||
self.gui = gui
|
self.gui = gui
|
||||||
self.ui_style_available = True
|
|
||||||
if not ismacos and not iswindows:
|
|
||||||
self.label_widget_style.setVisible(False)
|
|
||||||
self.opt_ui_style.setVisible(False)
|
|
||||||
self.ui_style_available = False
|
|
||||||
|
|
||||||
db = gui.library_view.model().db
|
|
||||||
|
|
||||||
r = self.register
|
|
||||||
|
|
||||||
try:
|
|
||||||
self.icon_theme_title = icon_resource_manager.user_theme_title
|
|
||||||
except Exception:
|
|
||||||
self.icon_theme_title = _('Default icons')
|
|
||||||
self.icon_theme.setText(_('Icon theme: <b>%s</b>') % self.icon_theme_title)
|
|
||||||
self.commit_icon_theme = None
|
|
||||||
self.icon_theme_button.clicked.connect(self.choose_icon_theme)
|
|
||||||
self.default_author_link = DefaultAuthorLink(self.default_author_link_container)
|
|
||||||
self.default_author_link.changed_signal.connect(self.changed_signal)
|
|
||||||
r('ui_style', gprefs, restart_required=True, choices=[(_('System default'), 'system'), (_('calibre style'), 'calibre')])
|
|
||||||
r('book_list_tooltips', gprefs)
|
|
||||||
r('dnd_merge', gprefs)
|
|
||||||
r('wrap_toolbar_text', gprefs, restart_required=True)
|
|
||||||
r('show_layout_buttons', gprefs)
|
|
||||||
r('show_sb_all_actions_button', gprefs)
|
|
||||||
# r('show_sb_preference_button', gprefs)
|
|
||||||
r('row_numbers_in_book_list', gprefs)
|
|
||||||
r('bd_show_cover', gprefs)
|
|
||||||
r('bd_overlay_cover_size', gprefs)
|
|
||||||
r('cover_corner_radius', gprefs)
|
|
||||||
r('cover_corner_radius_unit', gprefs, choices=[(_('Pixels'), 'px'), (_('Percentage'), '%')])
|
|
||||||
r('cover_grid_width', gprefs)
|
|
||||||
r('cover_grid_height', gprefs)
|
|
||||||
r('cover_grid_cache_size_multiple', gprefs)
|
|
||||||
r('cover_grid_disk_cache_size', gprefs)
|
|
||||||
r('cover_grid_spacing', gprefs)
|
|
||||||
r('cover_grid_show_title', gprefs)
|
|
||||||
|
|
||||||
r('emblem_size', gprefs)
|
|
||||||
r('emblem_position', gprefs, choices=[
|
|
||||||
(_('Left'), 'left'), (_('Top'), 'top'), (_('Right'), 'right'), (_('Bottom'), 'bottom')])
|
|
||||||
r('book_list_extra_row_spacing', gprefs)
|
|
||||||
r('booklist_grid', 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)
|
|
||||||
|
|
||||||
def get_esc_lang(l):
|
|
||||||
if l == 'en':
|
|
||||||
return 'English'
|
|
||||||
return get_language(l)
|
|
||||||
|
|
||||||
lang = get_lang()
|
|
||||||
if lang is None or lang not in available_translations():
|
|
||||||
lang = 'en'
|
|
||||||
items = [(l, get_esc_lang(l)) for l in available_translations()
|
|
||||||
if l != lang]
|
|
||||||
if lang != 'en':
|
|
||||||
items.append(('en', get_esc_lang('en')))
|
|
||||||
items.sort(key=lambda x: x[1].lower())
|
|
||||||
choices = [(y, x) for x, y in items]
|
|
||||||
# Default language is the autodetected one
|
|
||||||
choices = [(get_language(lang), lang)] + choices
|
|
||||||
lul = gprefs.get('last_used_language')
|
|
||||||
if lul and (lul in available_translations() or lul in ('en', 'eng')):
|
|
||||||
choices.insert(1, ((get_language(lul), lul)))
|
|
||||||
r('language', prefs, choices=choices, restart_required=True, setting=LanguageSetting)
|
|
||||||
|
|
||||||
r('disable_animations', config)
|
|
||||||
r('systray_icon', config, restart_required=True)
|
|
||||||
r('show_splash_screen', gprefs)
|
|
||||||
r('disable_tray_notification', config)
|
|
||||||
r('use_roman_numerals_for_series_number', config)
|
|
||||||
|
|
||||||
choices = [(_('Off'), 'off'), (_('Small'), 'small'),
|
|
||||||
(_('Medium-small'), 'mid-small'), (_('Medium'), 'medium'), (_('Large'), 'large')]
|
|
||||||
r('toolbar_icon_size', gprefs, choices=choices)
|
|
||||||
|
|
||||||
choices = [(_('If there is enough room'), 'auto'), (_('Always'), 'always'),
|
|
||||||
(_('Never'), 'never')]
|
|
||||||
r('toolbar_text', gprefs, choices=choices)
|
|
||||||
|
|
||||||
fm = db.field_metadata
|
|
||||||
choices = sorted(((fm[k]['name'], k) for k in fm.displayable_field_keys() if fm[k]['name']),
|
|
||||||
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')])
|
|
||||||
r('edit_metadata_ignore_display_order', db.prefs)
|
|
||||||
r('edit_metadata_elision_point', gprefs,
|
|
||||||
choices=[(_('Left'), 'left'), (_('Middle'), 'middle'),
|
|
||||||
(_('Right'), 'right')])
|
|
||||||
r('edit_metadata_elide_labels', gprefs)
|
|
||||||
r('edit_metadata_single_use_2_cols_for_custom_fields', gprefs)
|
|
||||||
r('edit_metadata_bulk_cc_label_length', gprefs)
|
|
||||||
r('edit_metadata_single_cc_label_length', gprefs)
|
|
||||||
r('edit_metadata_templates_only_F2_on_booklist', gprefs)
|
|
||||||
|
|
||||||
self.current_font = self.initial_font = None
|
|
||||||
self.change_font_button.clicked.connect(self.change_font)
|
|
||||||
|
|
||||||
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.dataChanged.connect(self.changed_signal)
|
|
||||||
self.em_display_order.setModel(self.em_display_model)
|
|
||||||
mu = partial(move_field_up, self.em_display_order, self.em_display_model)
|
|
||||||
md = partial(move_field_down, self.em_display_order, self.em_display_model)
|
|
||||||
self.em_display_order.set_movement_functions(mu, md)
|
|
||||||
self.em_up_button.clicked.connect(mu)
|
|
||||||
self.em_down_button.clicked.connect(md)
|
|
||||||
self.em_export_layout_button.clicked.connect(partial(export_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.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.changed.connect(self.changed_signal)
|
|
||||||
self.tabWidget.addTab(self.edit_rules, QIcon.ic('format-fill-color.png'), _('Column &coloring'))
|
|
||||||
|
|
||||||
self.icon_rules = EditRules(self.tabWidget)
|
|
||||||
self.icon_rules.changed.connect(self.changed_signal)
|
|
||||||
self.tabWidget.addTab(self.icon_rules, QIcon.ic('icon_choose.png'), _('Column &icons'))
|
|
||||||
|
|
||||||
self.grid_rules = EditRules(self.emblems_tab)
|
|
||||||
self.grid_rules.changed.connect(self.changed_signal)
|
|
||||||
self.emblems_tab.setLayout(QVBoxLayout())
|
|
||||||
self.emblems_tab.layout().addWidget(self.grid_rules)
|
|
||||||
|
|
||||||
self.tabWidget.setCurrentIndex(0)
|
self.tabWidget.setCurrentIndex(0)
|
||||||
self.tabWidget.tabBar().setVisible(False)
|
self.tabWidget.tabBar().setVisible(False)
|
||||||
keys = [QKeySequence('F11', QKeySequence.SequenceFormat.PortableText), QKeySequence(
|
keys = [QKeySequence('F11', QKeySequence.SequenceFormat.PortableText), QKeySequence(
|
||||||
'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.size_calculated.connect(self.update_cg_cache_size, type=Qt.ConnectionType.QueuedConnection)
|
|
||||||
self.tabWidget.currentChanged.connect(self.tab_changed)
|
|
||||||
|
|
||||||
l = self.cg_background_box.layout()
|
|
||||||
self.cg_bg_widget = w = Background(self)
|
|
||||||
l.addWidget(w, 0, 0, 3, 1)
|
|
||||||
self.cover_grid_color_button = b = QPushButton(_('Change &color'), self)
|
|
||||||
b.setSizePolicy(QSizePolicy.Policy.Fixed, QSizePolicy.Policy.Fixed)
|
|
||||||
l.addWidget(b, 0, 1)
|
|
||||||
b.clicked.connect(self.change_cover_grid_color)
|
|
||||||
self.cover_grid_texture_button = b = QPushButton(_('Change &background image'), self)
|
|
||||||
b.setSizePolicy(QSizePolicy.Policy.Fixed, QSizePolicy.Policy.Fixed)
|
|
||||||
l.addWidget(b, 1, 1)
|
|
||||||
b.clicked.connect(self.change_cover_grid_texture)
|
|
||||||
self.cover_grid_default_appearance_button = b = QPushButton(_('Restore default &appearance'), self)
|
|
||||||
b.setSizePolicy(QSizePolicy.Policy.Fixed, QSizePolicy.Policy.Fixed)
|
|
||||||
l.addWidget(b, 2, 1)
|
|
||||||
b.clicked.connect(self.restore_cover_grid_appearance)
|
|
||||||
self.cover_grid_empty_cache.clicked.connect(self.empty_cache)
|
|
||||||
self.cover_grid_open_cache.clicked.connect(self.open_cg_cache)
|
|
||||||
connect_lambda(self.cover_grid_smaller_cover.clicked, self, lambda self: self.resize_cover(True))
|
|
||||||
connect_lambda(self.cover_grid_larger_cover.clicked, self, lambda self: self.resize_cover(False))
|
|
||||||
self.cover_grid_reset_size.clicked.connect(self.cg_reset_size)
|
|
||||||
self.opt_cover_grid_disk_cache_size.setMinimum(self.gui.grid_view.thumbnail_cache.min_disk_cache)
|
|
||||||
self.opt_cover_grid_disk_cache_size.setMaximum(self.gui.grid_view.thumbnail_cache.min_disk_cache * 100)
|
|
||||||
self.opt_cover_grid_width.valueChanged.connect(self.update_aspect_ratio)
|
|
||||||
self.opt_cover_grid_height.valueChanged.connect(self.update_aspect_ratio)
|
|
||||||
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())
|
||||||
@ -628,256 +30,19 @@ class ConfigWidget(ConfigWidgetBase, Ui_Form):
|
|||||||
self.sections_view.setSpacing(4)
|
self.sections_view.setSpacing(4)
|
||||||
self.sections_view.setHorizontalScrollBarPolicy(Qt.ScrollBarPolicy.ScrollBarAlwaysOff)
|
self.sections_view.setHorizontalScrollBarPolicy(Qt.ScrollBarPolicy.ScrollBarAlwaysOff)
|
||||||
self.tabWidget.currentWidget().setFocus(Qt.FocusReason.OtherFocusReason)
|
self.tabWidget.currentWidget().setFocus(Qt.FocusReason.OtherFocusReason)
|
||||||
self.opt_ui_style.currentIndexChanged.connect(self.update_color_palette_state)
|
|
||||||
self.opt_gui_layout.addItem(_('Wide'), 'wide')
|
|
||||||
self.opt_gui_layout.addItem(_('Narrow'), 'narrow')
|
|
||||||
self.opt_gui_layout.currentIndexChanged.connect(self.changed_signal)
|
|
||||||
set_help_tips(self.opt_gui_layout, config.help('gui_layout'))
|
|
||||||
self.button_adjust_colors.clicked.connect(self.adjust_colors)
|
|
||||||
|
|
||||||
def adjust_colors(self):
|
|
||||||
from calibre.gui2.dialogs.palette import PaletteConfig
|
|
||||||
d = PaletteConfig(self)
|
|
||||||
if d.exec() == QDialog.DialogCode.Accepted:
|
|
||||||
d.apply_settings()
|
|
||||||
self.changed_signal.emit()
|
|
||||||
|
|
||||||
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 update_color_palette_state(self):
|
|
||||||
if self.ui_style_available:
|
|
||||||
enabled = self.opt_ui_style.currentData() == 'calibre'
|
|
||||||
self.button_adjust_colors.setEnabled(enabled)
|
|
||||||
|
|
||||||
def choose_icon_theme(self):
|
|
||||||
from calibre.gui2.icon_theme import ChooseTheme
|
|
||||||
d = ChooseTheme(self)
|
|
||||||
if d.exec() == QDialog.DialogCode.Accepted:
|
|
||||||
self.commit_icon_theme = d.commit_changes
|
|
||||||
self.icon_theme_title = d.new_theme_title or _('Default icons')
|
|
||||||
self.icon_theme.setText(_('Icon theme: <b>%s</b>') % self.icon_theme_title)
|
|
||||||
self.changed_signal.emit()
|
|
||||||
|
|
||||||
def edit_id_link_rules(self):
|
|
||||||
if IdLinksEditor(self).exec() == QDialog.DialogCode.Accepted:
|
|
||||||
self.changed_signal.emit()
|
|
||||||
|
|
||||||
@property
|
|
||||||
def current_cover_size(self):
|
|
||||||
cval = self.opt_cover_grid_height.value()
|
|
||||||
wval = self.opt_cover_grid_width.value()
|
|
||||||
if cval < 0.1:
|
|
||||||
dpi = self.opt_cover_grid_height.logicalDpiY()
|
|
||||||
cval = auto_height(self.opt_cover_grid_height) / dpi / CM_TO_INCH
|
|
||||||
if wval < 0.1:
|
|
||||||
wval = 0.75 * cval
|
|
||||||
return wval, cval
|
|
||||||
|
|
||||||
def update_aspect_ratio(self, *args):
|
|
||||||
width, height = self.current_cover_size
|
|
||||||
ar = width / height
|
|
||||||
self.cover_grid_aspect_ratio.setText(_('Current aspect ratio (width/height): %.2g') % ar)
|
|
||||||
|
|
||||||
def resize_cover(self, smaller):
|
|
||||||
wval, cval = self.current_cover_size
|
|
||||||
ar = wval / cval
|
|
||||||
delta = 0.2 * (-1 if smaller else 1)
|
|
||||||
cval += delta
|
|
||||||
cval = max(0, cval)
|
|
||||||
self.opt_cover_grid_height.setValue(cval)
|
|
||||||
self.opt_cover_grid_width.setValue(cval * ar)
|
|
||||||
|
|
||||||
def cg_reset_size(self):
|
|
||||||
self.opt_cover_grid_width.setValue(0)
|
|
||||||
self.opt_cover_grid_height.setValue(0)
|
|
||||||
|
|
||||||
def initialize(self):
|
|
||||||
ConfigWidgetBase.initialize(self)
|
|
||||||
|
|
||||||
self.default_author_link.value = default_author_link()
|
|
||||||
font = gprefs['font']
|
|
||||||
if font is not None:
|
|
||||||
font = list(font)
|
|
||||||
font.append(gprefs.get('font_stretch', QFont.Stretch.Unstretched))
|
|
||||||
self.current_font = self.initial_font = font
|
|
||||||
self.update_font_display()
|
|
||||||
self.display_model.initialize()
|
|
||||||
self.em_display_model.initialize()
|
|
||||||
self.bd_vertical_cats_model.initialize()
|
|
||||||
db = self.gui.current_db
|
|
||||||
mi = []
|
|
||||||
try:
|
|
||||||
rows = self.gui.current_view().selectionModel().selectedRows()
|
|
||||||
for row in rows:
|
|
||||||
if row.isValid():
|
|
||||||
mi.append(db.new_api.get_proxy_metadata(db.data.index_to_id(row.row())))
|
|
||||||
except:
|
|
||||||
pass
|
|
||||||
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.grid_rules.initialize(db.field_metadata, db.prefs, mi, 'cover_grid_icon_rules')
|
|
||||||
self.set_cg_color(gprefs['cover_grid_color'])
|
|
||||||
self.set_cg_texture(gprefs['cover_grid_texture'])
|
|
||||||
self.update_aspect_ratio()
|
|
||||||
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)
|
|
||||||
self.update_color_palette_state()
|
|
||||||
self.opt_gui_layout.setCurrentIndex(0 if self.gui.layout_container.is_wide else 1)
|
|
||||||
|
|
||||||
def open_cg_cache(self):
|
|
||||||
open_local_file(self.gui.grid_view.thumbnail_cache.location)
|
|
||||||
|
|
||||||
def update_cg_cache_size(self, size):
|
|
||||||
self.cover_grid_current_disk_cache.setText(
|
|
||||||
_('Current space used: %s') % human_readable(size))
|
|
||||||
|
|
||||||
def tab_changed(self, index):
|
|
||||||
if self.tabWidget.currentWidget() is self.cover_grid_tab:
|
|
||||||
self.show_current_cache_usage()
|
|
||||||
|
|
||||||
def show_current_cache_usage(self):
|
|
||||||
t = Thread(target=self.calc_cache_size)
|
|
||||||
t.daemon = True
|
|
||||||
t.start()
|
|
||||||
|
|
||||||
def calc_cache_size(self):
|
|
||||||
self.size_calculated.emit(self.gui.grid_view.thumbnail_cache.current_size)
|
|
||||||
|
|
||||||
def set_cg_color(self, val):
|
|
||||||
self.cg_bg_widget.bcol = QColor(*val)
|
|
||||||
self.cg_bg_widget.update_brush()
|
|
||||||
|
|
||||||
def set_cg_texture(self, val):
|
|
||||||
self.cg_bg_widget.btex = val
|
|
||||||
self.cg_bg_widget.update_brush()
|
|
||||||
|
|
||||||
def empty_cache(self):
|
|
||||||
self.gui.grid_view.thumbnail_cache.empty()
|
|
||||||
self.calc_cache_size()
|
|
||||||
|
|
||||||
def restore_defaults(self):
|
def restore_defaults(self):
|
||||||
ConfigWidgetBase.restore_defaults(self)
|
ConfigWidgetBase.restore_defaults(self)
|
||||||
self.default_author_link.value = DEFAULT_AUTHOR_LINK
|
|
||||||
ofont = self.current_font
|
|
||||||
self.current_font = None
|
|
||||||
if ofont is not None:
|
|
||||||
self.changed_signal.emit()
|
|
||||||
self.update_font_display()
|
|
||||||
self.display_model.restore_defaults()
|
|
||||||
self.em_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()
|
|
||||||
self.grid_rules.clear()
|
|
||||||
self.changed_signal.emit()
|
self.changed_signal.emit()
|
||||||
self.set_cg_color(gprefs.defaults['cover_grid_color'])
|
|
||||||
self.set_cg_texture(gprefs.defaults['cover_grid_texture'])
|
|
||||||
self.opt_book_details_css.setPlainText(P('templates/book_details.css', allow_user_override=False, data=True).decode('utf-8'))
|
|
||||||
self.opt_gui_layout.setCurrentIndex(0)
|
|
||||||
|
|
||||||
def change_cover_grid_color(self):
|
|
||||||
col = QColorDialog.getColor(self.cg_bg_widget.bcol,
|
|
||||||
self.gui, _('Choose background color for the Cover grid'))
|
|
||||||
if col.isValid():
|
|
||||||
col = tuple(col.getRgb())[:3]
|
|
||||||
self.set_cg_color(col)
|
|
||||||
self.changed_signal.emit()
|
|
||||||
if self.cg_bg_widget.btex:
|
|
||||||
if question_dialog(
|
|
||||||
self, _('Remove background image?'),
|
|
||||||
_('There is currently a background image set, so the color'
|
|
||||||
' you have chosen will not be visible. Remove the background image?')):
|
|
||||||
self.set_cg_texture(None)
|
|
||||||
|
|
||||||
def change_cover_grid_texture(self):
|
|
||||||
from calibre.gui2.preferences.texture_chooser import TextureChooser
|
|
||||||
d = TextureChooser(parent=self, initial=self.cg_bg_widget.btex)
|
|
||||||
if d.exec() == QDialog.DialogCode.Accepted:
|
|
||||||
self.set_cg_texture(d.texture)
|
|
||||||
self.changed_signal.emit()
|
|
||||||
|
|
||||||
def restore_cover_grid_appearance(self):
|
|
||||||
self.set_cg_color(gprefs.defaults['cover_grid_color'])
|
|
||||||
self.set_cg_texture(gprefs.defaults['cover_grid_texture'])
|
|
||||||
self.changed_signal.emit()
|
|
||||||
|
|
||||||
def build_font_obj(self):
|
|
||||||
font_info = qt_app.original_font if self.current_font is None else self.current_font
|
|
||||||
font = QFont(*(font_info[:4]))
|
|
||||||
font.setStretch(font_info[4])
|
|
||||||
return font
|
|
||||||
|
|
||||||
def update_font_display(self):
|
|
||||||
font = self.build_font_obj()
|
|
||||||
fi = QFontInfo(font)
|
|
||||||
name = str(fi.family())
|
|
||||||
|
|
||||||
self.font_display.setFont(font)
|
|
||||||
self.font_display.setText(name + f' [{fi.pointSize()}pt]')
|
|
||||||
|
|
||||||
def change_font(self, *args):
|
|
||||||
fd = QFontDialog(self.build_font_obj(), self)
|
|
||||||
if fd.exec() == QDialog.DialogCode.Accepted:
|
|
||||||
font = fd.selectedFont()
|
|
||||||
fi = QFontInfo(font)
|
|
||||||
self.current_font = [str(fi.family()), fi.pointSize(),
|
|
||||||
fi.weight(), fi.italic(), font.stretch()]
|
|
||||||
self.update_font_display()
|
|
||||||
self.changed_signal.emit()
|
|
||||||
|
|
||||||
def commit(self, *args):
|
|
||||||
with BusyCursor():
|
|
||||||
rr = ConfigWidgetBase.commit(self, *args)
|
|
||||||
if self.current_font != self.initial_font:
|
|
||||||
gprefs['font'] = (self.current_font[:4] if self.current_font else
|
|
||||||
None)
|
|
||||||
gprefs['font_stretch'] = (self.current_font[4] if self.current_font
|
|
||||||
is not None else QFont.Stretch.Unstretched)
|
|
||||||
QApplication.setFont(self.font_display.font())
|
|
||||||
rr = True
|
|
||||||
self.display_model.commit()
|
|
||||||
self.em_display_model.commit()
|
|
||||||
self.bd_vertical_cats_model.commit()
|
|
||||||
self.edit_rules.commit(self.gui.current_db.prefs)
|
|
||||||
self.icon_rules.commit(self.gui.current_db.prefs)
|
|
||||||
self.grid_rules.commit(self.gui.current_db.prefs)
|
|
||||||
gprefs['cover_grid_color'] = tuple(self.cg_bg_widget.bcol.getRgb())[:3]
|
|
||||||
gprefs['cover_grid_texture'] = self.cg_bg_widget.btex
|
|
||||||
if self.commit_icon_theme is not None:
|
|
||||||
self.commit_icon_theme()
|
|
||||||
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)
|
|
||||||
self.gui.layout_container.change_layout(self.gui, self.opt_gui_layout.currentIndex() == 0)
|
|
||||||
return rr
|
|
||||||
|
|
||||||
def refresh_gui(self, gui):
|
def refresh_gui(self, gui):
|
||||||
gui.book_details.book_info.refresh_css()
|
|
||||||
gui.place_layout_buttons()
|
|
||||||
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()
|
||||||
self.update_font_display()
|
|
||||||
gui.tags_view.set_look_and_feel()
|
|
||||||
gui.tags_view.reread_collapse_parameters()
|
|
||||||
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_grid()
|
|
||||||
gui.library_view.refresh_composite_edit()
|
|
||||||
gui.library_view.set_row_header_visibility()
|
|
||||||
for view in 'library memory card_a card_b'.split():
|
|
||||||
getattr(gui, view + '_view').set_row_header_visibility()
|
|
||||||
gui.library_view.refresh_row_sizing()
|
|
||||||
gui.grid_view.refresh_settings()
|
|
||||||
gui.update_auto_scroll_timeout()
|
|
||||||
gui.sb_all_gui_actions_button.setVisible(gprefs['show_sb_all_actions_button'])
|
|
||||||
# gui.sb_preferences_button.setVisible(gprefs['show_sb_preference_button'])
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -7,13 +7,79 @@ __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.preferences import LazyConfigWidgetBase
|
||||||
|
from calibre.gui2.preferences.coloring import EditRules
|
||||||
|
from calibre.gui2.ui import get_gui
|
||||||
|
|
||||||
|
|
||||||
class DisplayedFields(QAbstractListModel): # {{{
|
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):
|
||||||
|
|
||||||
def __init__(self, db, parent=None, pref_name=None, category_icons=None):
|
def __init__(self, db, parent=None, pref_name=None, category_icons=None):
|
||||||
self.pref_name = pref_name or 'book_display_fields'
|
self.pref_name = pref_name or 'book_display_fields'
|
||||||
@ -103,6 +169,47 @@ class DisplayedFields(QAbstractListModel): # {{{
|
|||||||
return idx
|
return idx
|
||||||
|
|
||||||
|
|
||||||
|
class LazyEditRulesBase(LazyConfigWidgetBase):
|
||||||
|
|
||||||
|
rule_set_name = None
|
||||||
|
|
||||||
|
def __init__(self, parent=None):
|
||||||
|
super().__init__(parent)
|
||||||
|
self.rules_editor = EditRules(parent)
|
||||||
|
self.setLayout(self.rules_editor.layout())
|
||||||
|
|
||||||
|
def genesis(self, gui):
|
||||||
|
self.gui = gui
|
||||||
|
self.rules_editor.changed.connect(self.changed_signal)
|
||||||
|
|
||||||
|
def lazy_initialize(self):
|
||||||
|
if not self.rule_set_name:
|
||||||
|
raise NotImplementedError('You must define the attribut "rule_set_name" in LazyEditRulesBase subclasses')
|
||||||
|
self.load_rule_set(self.rule_set_name)
|
||||||
|
|
||||||
|
def load_rule_set(self, name):
|
||||||
|
db = self.gui.current_db
|
||||||
|
mi = selected_rows_metadatas()
|
||||||
|
self.rules_editor.initialize(db.field_metadata, db.prefs, mi, name)
|
||||||
|
|
||||||
|
def commit(self):
|
||||||
|
self.rules_editor.commit(self, self.gui.current_db.prefs)
|
||||||
|
return LazyConfigWidgetBase.commit(self)
|
||||||
|
|
||||||
|
def restore_defaults(self):
|
||||||
|
LazyConfigWidgetBase.restore_defaults(self)
|
||||||
|
self.rules_editor.clear(self)
|
||||||
|
self.changed_signal.emit()
|
||||||
|
|
||||||
|
|
||||||
|
class ColumnColorRules(LazyEditRulesBase):
|
||||||
|
rule_set_name = 'column_color_rules'
|
||||||
|
|
||||||
|
|
||||||
|
class ColumnIconRules(LazyEditRulesBase):
|
||||||
|
rule_set_name = 'column_icon_rules'
|
||||||
|
|
||||||
|
|
||||||
def export_layout(in_widget, model=None):
|
def export_layout(in_widget, model=None):
|
||||||
filename = choose_save_file(in_widget, 'look_feel_prefs_import_export_field_list',
|
filename = choose_save_file(in_widget, 'look_feel_prefs_import_export_field_list',
|
||||||
_('Save column list to file'),
|
_('Save column list to file'),
|
||||||
@ -155,4 +262,15 @@ def move_field_down(widget, model):
|
|||||||
sm.select(idx, QItemSelectionModel.SelectionFlag.ClearAndSelect)
|
sm.select(idx, QItemSelectionModel.SelectionFlag.ClearAndSelect)
|
||||||
widget.setCurrentIndex(idx)
|
widget.setCurrentIndex(idx)
|
||||||
|
|
||||||
# }}}
|
|
||||||
|
def selected_rows_metadatas():
|
||||||
|
rslt = []
|
||||||
|
try:
|
||||||
|
db = get_gui().current_db
|
||||||
|
rows = get_gui().current_view().selectionModel().selectedRows()
|
||||||
|
for row in rows:
|
||||||
|
if row.isValid():
|
||||||
|
rslt.append(db.new_api.get_proxy_metadata(db.data.index_to_id(row.row())))
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
return rslt
|
||||||
|
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.blockSignals(True)
|
||||||
|
self.default_author_link.value = default_author_link()
|
||||||
|
self.display_model.initialize()
|
||||||
|
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>
|
228
src/calibre/gui2/preferences/look_feel_tabs/cover_grid.py
Normal file
228
src/calibre/gui2/preferences/look_feel_tabs/cover_grid.py
Normal file
@ -0,0 +1,228 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
|
||||||
|
__license__ = 'GPL v3'
|
||||||
|
__copyright__ = '2025, Kovid Goyal <kovid@kovidgoyal.net>'
|
||||||
|
__docformat__ = 'restructuredtext en'
|
||||||
|
|
||||||
|
|
||||||
|
from threading import Thread
|
||||||
|
|
||||||
|
from qt.core import QBrush, QColor, QColorDialog, QDialog, QPainter, QPixmap, QPushButton, QSize, QSizePolicy, Qt, QTabWidget, QVBoxLayout, QWidget, pyqtSignal
|
||||||
|
|
||||||
|
from calibre import human_readable
|
||||||
|
from calibre.gui2 import gprefs, open_local_file, question_dialog
|
||||||
|
from calibre.gui2.library.alternate_views import CM_TO_INCH, auto_height
|
||||||
|
from calibre.gui2.preferences import LazyConfigWidgetBase
|
||||||
|
from calibre.gui2.preferences.coloring import EditRules
|
||||||
|
from calibre.gui2.preferences.look_feel_tabs import selected_rows_metadatas
|
||||||
|
from calibre.gui2.preferences.look_feel_tabs.cover_grid_ui import Ui_Form
|
||||||
|
from calibre.gui2.widgets import BusyCursor
|
||||||
|
from calibre.startup import connect_lambda
|
||||||
|
from calibre.utils.icu import sort_key
|
||||||
|
|
||||||
|
|
||||||
|
class Background(QWidget):
|
||||||
|
|
||||||
|
def __init__(self, parent):
|
||||||
|
QWidget.__init__(self, parent)
|
||||||
|
self.bcol = QColor(*gprefs['cover_grid_color'])
|
||||||
|
self.btex = gprefs['cover_grid_texture']
|
||||||
|
self.update_brush()
|
||||||
|
self.setSizePolicy(QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Fixed)
|
||||||
|
|
||||||
|
def update_brush(self):
|
||||||
|
self.brush = QBrush(self.bcol)
|
||||||
|
if self.btex:
|
||||||
|
from calibre.gui2.preferences.texture_chooser import texture_path
|
||||||
|
path = texture_path(self.btex)
|
||||||
|
if path:
|
||||||
|
p = QPixmap(path)
|
||||||
|
try:
|
||||||
|
dpr = self.devicePixelRatioF()
|
||||||
|
except AttributeError:
|
||||||
|
dpr = self.devicePixelRatio()
|
||||||
|
p.setDevicePixelRatio(dpr)
|
||||||
|
self.brush.setTexture(p)
|
||||||
|
self.update()
|
||||||
|
|
||||||
|
def sizeHint(self):
|
||||||
|
return QSize(200, 120)
|
||||||
|
|
||||||
|
def paintEvent(self, ev):
|
||||||
|
painter = QPainter(self)
|
||||||
|
painter.fillRect(ev.rect(), self.brush)
|
||||||
|
painter.end()
|
||||||
|
|
||||||
|
|
||||||
|
class CoverGridTab(QTabWidget, LazyConfigWidgetBase, Ui_Form):
|
||||||
|
|
||||||
|
changed_signal = pyqtSignal()
|
||||||
|
restart_now = pyqtSignal()
|
||||||
|
size_calculated = pyqtSignal(object)
|
||||||
|
|
||||||
|
def __init__(self, parent=None):
|
||||||
|
super().__init__(parent)
|
||||||
|
|
||||||
|
def genesis(self, gui):
|
||||||
|
self.gui = gui
|
||||||
|
db = self.gui.library_view.model().db
|
||||||
|
r = self.register
|
||||||
|
|
||||||
|
r('cover_grid_width', gprefs)
|
||||||
|
r('cover_grid_height', gprefs)
|
||||||
|
r('cover_grid_cache_size_multiple', gprefs)
|
||||||
|
r('cover_grid_disk_cache_size', gprefs)
|
||||||
|
r('cover_grid_spacing', gprefs)
|
||||||
|
r('cover_grid_show_title', gprefs)
|
||||||
|
r('emblem_size', gprefs)
|
||||||
|
r('emblem_position', gprefs, choices=[
|
||||||
|
(_('Left'), 'left'), (_('Top'), 'top'), (_('Right'), 'right'), (_('Bottom'), 'bottom')])
|
||||||
|
|
||||||
|
fm = db.field_metadata
|
||||||
|
choices = sorted(((fm[k]['name'], k) for k in fm.displayable_field_keys() if fm[k]['name']),
|
||||||
|
key=lambda x:sort_key(x[0]))
|
||||||
|
r('field_under_covers_in_grid', db.prefs, choices=choices)
|
||||||
|
|
||||||
|
self.grid_rules = EditRules(self.emblems_tab)
|
||||||
|
self.grid_rules.changed.connect(self.changed_signal)
|
||||||
|
self.emblems_tab.setLayout(QVBoxLayout())
|
||||||
|
self.emblems_tab.layout().addWidget(self.grid_rules)
|
||||||
|
|
||||||
|
self.size_calculated.connect(self.update_cg_cache_size, type=Qt.ConnectionType.QueuedConnection)
|
||||||
|
|
||||||
|
l = self.cg_background_box.layout()
|
||||||
|
self.cg_bg_widget = w = Background(self)
|
||||||
|
l.addWidget(w, 0, 0, 3, 1)
|
||||||
|
self.cover_grid_color_button = b = QPushButton(_('Change &color'), self)
|
||||||
|
b.setSizePolicy(QSizePolicy.Policy.Fixed, QSizePolicy.Policy.Fixed)
|
||||||
|
l.addWidget(b, 0, 1)
|
||||||
|
b.clicked.connect(self.change_cover_grid_color)
|
||||||
|
self.cover_grid_texture_button = b = QPushButton(_('Change &background image'), self)
|
||||||
|
b.setSizePolicy(QSizePolicy.Policy.Fixed, QSizePolicy.Policy.Fixed)
|
||||||
|
l.addWidget(b, 1, 1)
|
||||||
|
b.clicked.connect(self.change_cover_grid_texture)
|
||||||
|
self.cover_grid_default_appearance_button = b = QPushButton(_('Restore default &appearance'), self)
|
||||||
|
b.setSizePolicy(QSizePolicy.Policy.Fixed, QSizePolicy.Policy.Fixed)
|
||||||
|
l.addWidget(b, 2, 1)
|
||||||
|
b.clicked.connect(self.restore_cover_grid_appearance)
|
||||||
|
self.cover_grid_empty_cache.clicked.connect(self.empty_cache)
|
||||||
|
self.cover_grid_open_cache.clicked.connect(self.open_cg_cache)
|
||||||
|
connect_lambda(self.cover_grid_smaller_cover.clicked, self, lambda self: self.resize_cover(True))
|
||||||
|
connect_lambda(self.cover_grid_larger_cover.clicked, self, lambda self: self.resize_cover(False))
|
||||||
|
self.cover_grid_reset_size.clicked.connect(self.cg_reset_size)
|
||||||
|
self.opt_cover_grid_disk_cache_size.setMinimum(self.gui.grid_view.thumbnail_cache.min_disk_cache)
|
||||||
|
self.opt_cover_grid_disk_cache_size.setMaximum(self.gui.grid_view.thumbnail_cache.min_disk_cache * 100)
|
||||||
|
self.opt_cover_grid_width.valueChanged.connect(self.update_aspect_ratio)
|
||||||
|
self.opt_cover_grid_height.valueChanged.connect(self.update_aspect_ratio)
|
||||||
|
|
||||||
|
def lazy_initialize(self):
|
||||||
|
self.show_current_cache_usage()
|
||||||
|
|
||||||
|
db = self.gui.current_db
|
||||||
|
self.blockSignals(True)
|
||||||
|
self.grid_rules.initialize(db.field_metadata, db.prefs, selected_rows_metadatas(), 'cover_grid_icon_rules')
|
||||||
|
self.blockSignals(False)
|
||||||
|
self.set_cg_color(gprefs['cover_grid_color'])
|
||||||
|
self.set_cg_texture(gprefs['cover_grid_texture'])
|
||||||
|
self.update_aspect_ratio()
|
||||||
|
|
||||||
|
def show_current_cache_usage(self):
|
||||||
|
t = Thread(target=self.calc_cache_size)
|
||||||
|
t.daemon = True
|
||||||
|
t.start()
|
||||||
|
|
||||||
|
def calc_cache_size(self):
|
||||||
|
self.size_calculated.emit(self.gui.grid_view.thumbnail_cache.current_size)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def current_cover_size(self):
|
||||||
|
cval = self.opt_cover_grid_height.value()
|
||||||
|
wval = self.opt_cover_grid_width.value()
|
||||||
|
if cval < 0.1:
|
||||||
|
dpi = self.opt_cover_grid_height.logicalDpiY()
|
||||||
|
cval = auto_height(self.opt_cover_grid_height) / dpi / CM_TO_INCH
|
||||||
|
if wval < 0.1:
|
||||||
|
wval = 0.75 * cval
|
||||||
|
return wval, cval
|
||||||
|
|
||||||
|
def update_aspect_ratio(self):
|
||||||
|
width, height = self.current_cover_size
|
||||||
|
ar = width / height
|
||||||
|
self.cover_grid_aspect_ratio.setText(_('Current aspect ratio (width/height): %.2g') % ar)
|
||||||
|
|
||||||
|
def resize_cover(self, smaller):
|
||||||
|
wval, cval = self.current_cover_size
|
||||||
|
ar = wval / cval
|
||||||
|
delta = 0.2 * (-1 if smaller else 1)
|
||||||
|
cval += delta
|
||||||
|
cval = max(0, cval)
|
||||||
|
self.opt_cover_grid_height.setValue(cval)
|
||||||
|
self.opt_cover_grid_width.setValue(cval * ar)
|
||||||
|
|
||||||
|
def cg_reset_size(self):
|
||||||
|
self.opt_cover_grid_width.setValue(0)
|
||||||
|
self.opt_cover_grid_height.setValue(0)
|
||||||
|
|
||||||
|
def open_cg_cache(self):
|
||||||
|
open_local_file(self.gui.grid_view.thumbnail_cache.location)
|
||||||
|
|
||||||
|
def update_cg_cache_size(self, size):
|
||||||
|
self.cover_grid_current_disk_cache.setText(
|
||||||
|
_('Current space used: %s') % human_readable(size))
|
||||||
|
|
||||||
|
def empty_cache(self):
|
||||||
|
self.gui.grid_view.thumbnail_cache.empty()
|
||||||
|
self.calc_cache_size()
|
||||||
|
|
||||||
|
def set_cg_color(self, val):
|
||||||
|
self.cg_bg_widget.bcol = QColor(*val)
|
||||||
|
self.cg_bg_widget.update_brush()
|
||||||
|
|
||||||
|
def set_cg_texture(self, val):
|
||||||
|
self.cg_bg_widget.btex = val
|
||||||
|
self.cg_bg_widget.update_brush()
|
||||||
|
|
||||||
|
def change_cover_grid_color(self):
|
||||||
|
col = QColorDialog.getColor(self.cg_bg_widget.bcol,
|
||||||
|
self.gui, _('Choose background color for the Cover grid'))
|
||||||
|
if col.isValid():
|
||||||
|
col = tuple(col.getRgb())[:3]
|
||||||
|
self.set_cg_color(col)
|
||||||
|
self.changed_signal.emit()
|
||||||
|
if self.cg_bg_widget.btex:
|
||||||
|
if question_dialog(
|
||||||
|
self, _('Remove background image?'),
|
||||||
|
_('There is currently a background image set, so the color'
|
||||||
|
' you have chosen will not be visible. Remove the background image?')):
|
||||||
|
self.set_cg_texture(None)
|
||||||
|
|
||||||
|
def change_cover_grid_texture(self):
|
||||||
|
from calibre.gui2.preferences.texture_chooser import TextureChooser
|
||||||
|
d = TextureChooser(parent=self, initial=self.cg_bg_widget.btex)
|
||||||
|
if d.exec() == QDialog.DialogCode.Accepted:
|
||||||
|
self.set_cg_texture(d.texture)
|
||||||
|
self.changed_signal.emit()
|
||||||
|
|
||||||
|
def restore_cover_grid_appearance(self):
|
||||||
|
self.set_cg_color(gprefs.defaults['cover_grid_color'])
|
||||||
|
self.set_cg_texture(gprefs.defaults['cover_grid_texture'])
|
||||||
|
self.changed_signal.emit()
|
||||||
|
|
||||||
|
def commit(self):
|
||||||
|
with BusyCursor():
|
||||||
|
self.grid_rules.commit(self.gui.current_db.prefs)
|
||||||
|
gprefs['cover_grid_color'] = tuple(self.cg_bg_widget.bcol.getRgb())[:3]
|
||||||
|
gprefs['cover_grid_texture'] = self.cg_bg_widget.btex
|
||||||
|
return LazyConfigWidgetBase.commit(self)
|
||||||
|
|
||||||
|
def restore_defaults(self):
|
||||||
|
LazyConfigWidgetBase.restore_defaults(self)
|
||||||
|
self.grid_rules.clear()
|
||||||
|
self.set_cg_color(gprefs.defaults['cover_grid_color'])
|
||||||
|
self.set_cg_texture(gprefs.defaults['cover_grid_texture'])
|
||||||
|
self.changed_signal.emit()
|
||||||
|
|
||||||
|
def refresh_gui(self, gui):
|
||||||
|
gui.library_view.refresh_grid()
|
||||||
|
gui.grid_view.refresh_settings()
|
||||||
|
gui.update_auto_scroll_timeout()
|
436
src/calibre/gui2/preferences/look_feel_tabs/cover_grid.ui
Normal file
436
src/calibre/gui2/preferences/look_feel_tabs/cover_grid.ui
Normal file
@ -0,0 +1,436 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<ui version="4.0">
|
||||||
|
<class>Form</class>
|
||||||
|
<widget class="QTabWidget" name="cover_grid_tab">
|
||||||
|
<property name="currentIndex">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<widget class="QWidget" name="tab_5">
|
||||||
|
<attribute name="title">
|
||||||
|
<string>&Layout</string>
|
||||||
|
</attribute>
|
||||||
|
<layout class="QFormLayout" name="formLayout_2">
|
||||||
|
<property name="fieldGrowthPolicy">
|
||||||
|
<enum>QFormLayout::ExpandingFieldsGrow</enum>
|
||||||
|
</property>
|
||||||
|
<item row="0" column="0" colspan="2">
|
||||||
|
<widget class="QLabel" name="label_19">
|
||||||
|
<property name="text">
|
||||||
|
<string>Control the Cover grid view. You can enable this view by clicking the "Layout" button in the bottom right corner of the main calibre window.</string>
|
||||||
|
</property>
|
||||||
|
<property name="wordWrap">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="3" column="1">
|
||||||
|
<spacer name="verticalSpacer_6">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Vertical</enum>
|
||||||
|
</property>
|
||||||
|
<property name="sizeType">
|
||||||
|
<enum>QSizePolicy::Fixed</enum>
|
||||||
|
</property>
|
||||||
|
<property name="sizeHint" stdset="0">
|
||||||
|
<size>
|
||||||
|
<width>20</width>
|
||||||
|
<height>10</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
</spacer>
|
||||||
|
</item>
|
||||||
|
<item row="5" column="0">
|
||||||
|
<widget class="QLabel" name="label_14">
|
||||||
|
<property name="text">
|
||||||
|
<string>Field to show &under the covers:</string>
|
||||||
|
</property>
|
||||||
|
<property name="buddy">
|
||||||
|
<cstring>opt_field_under_covers_in_grid</cstring>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="5" column="1">
|
||||||
|
<widget class="QComboBox" name="opt_field_under_covers_in_grid"/>
|
||||||
|
</item>
|
||||||
|
<item row="6" column="0">
|
||||||
|
<widget class="QLabel" name="label_16">
|
||||||
|
<property name="text">
|
||||||
|
<string>Spac&ing between covers:</string>
|
||||||
|
</property>
|
||||||
|
<property name="buddy">
|
||||||
|
<cstring>opt_cover_grid_spacing</cstring>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="6" column="1">
|
||||||
|
<widget class="QDoubleSpinBox" name="opt_cover_grid_spacing">
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>The spacing between covers. A value of zero means calculate automatically based on cover size.</string>
|
||||||
|
</property>
|
||||||
|
<property name="specialValueText">
|
||||||
|
<string>Automatic</string>
|
||||||
|
</property>
|
||||||
|
<property name="suffix">
|
||||||
|
<string> cm</string>
|
||||||
|
</property>
|
||||||
|
<property name="decimals">
|
||||||
|
<number>2</number>
|
||||||
|
</property>
|
||||||
|
<property name="singleStep">
|
||||||
|
<double>0.100000000000000</double>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="7" column="0" colspan="2">
|
||||||
|
<widget class="QGroupBox" name="cg_background_box">
|
||||||
|
<property name="title">
|
||||||
|
<string>Background for the Cover grid</string>
|
||||||
|
</property>
|
||||||
|
<layout class="QGridLayout" name="gridLayout_5"/>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="10" column="0" colspan="2">
|
||||||
|
<widget class="QGroupBox" name="groupBox_4">
|
||||||
|
<property name="title">
|
||||||
|
<string>Cover size</string>
|
||||||
|
</property>
|
||||||
|
<layout class="QGridLayout" name="gridLayout_4">
|
||||||
|
<item row="1" column="2">
|
||||||
|
<widget class="QPushButton" name="cover_grid_larger_cover">
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>Make the covers larger, maintaining current aspect ratio.</string>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>&Larger covers</string>
|
||||||
|
</property>
|
||||||
|
<property name="icon">
|
||||||
|
<iconset resource="../../../../resources/images.qrc">
|
||||||
|
<normaloff>:/images/plus.png</normaloff>:/images/plus.png</iconset>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="2" column="2">
|
||||||
|
<widget class="QPushButton" name="cover_grid_smaller_cover">
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>Make the covers smaller, maintaining current aspect ratio.</string>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>&Smaller covers</string>
|
||||||
|
</property>
|
||||||
|
<property name="icon">
|
||||||
|
<iconset resource="../../../../resources/images.qrc">
|
||||||
|
<normaloff>:/images/minus.png</normaloff>:/images/minus.png</iconset>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="2" column="0">
|
||||||
|
<widget class="QLabel" name="label_12">
|
||||||
|
<property name="text">
|
||||||
|
<string>Cover &height: </string>
|
||||||
|
</property>
|
||||||
|
<property name="buddy">
|
||||||
|
<cstring>opt_cover_grid_height</cstring>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="1" column="0">
|
||||||
|
<widget class="QLabel" name="label_11">
|
||||||
|
<property name="text">
|
||||||
|
<string>Cover &width: </string>
|
||||||
|
</property>
|
||||||
|
<property name="buddy">
|
||||||
|
<cstring>opt_cover_grid_width</cstring>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="2" column="1">
|
||||||
|
<widget class="QDoubleSpinBox" name="opt_cover_grid_height">
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>The height of displayed covers.
|
||||||
|
Aue of zero means calculate automatically.</string>
|
||||||
|
</property>
|
||||||
|
<property name="specialValueText">
|
||||||
|
<string>Automatic</string>
|
||||||
|
</property>
|
||||||
|
<property name="suffix">
|
||||||
|
<string> cm</string>
|
||||||
|
</property>
|
||||||
|
<property name="decimals">
|
||||||
|
<number>1</number>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="1" column="3" rowspan="2">
|
||||||
|
<widget class="QPushButton" name="cover_grid_reset_size">
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>Reset size to automatic</string>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>&Reset size</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="3" column="0" colspan="5">
|
||||||
|
<widget class="QLabel" name="cover_grid_aspect_ratio">
|
||||||
|
<property name="text">
|
||||||
|
<string/>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="1" column="4">
|
||||||
|
<spacer name="horizontalSpacer_4">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Horizontal</enum>
|
||||||
|
</property>
|
||||||
|
<property name="sizeHint" stdset="0">
|
||||||
|
<size>
|
||||||
|
<width>40</width>
|
||||||
|
<height>20</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
</spacer>
|
||||||
|
</item>
|
||||||
|
<item row="1" column="1">
|
||||||
|
<widget class="QDoubleSpinBox" name="opt_cover_grid_width">
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>The width of displayed covers.
|
||||||
|
Aue of zero means calculate automatically.</string>
|
||||||
|
</property>
|
||||||
|
<property name="specialValueText">
|
||||||
|
<string>Automatic</string>
|
||||||
|
</property>
|
||||||
|
<property name="suffix">
|
||||||
|
<string> cm</string>
|
||||||
|
</property>
|
||||||
|
<property name="decimals">
|
||||||
|
<number>1</number>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="0" column="0" colspan="5">
|
||||||
|
<widget class="QLabel" name="cover_size_label">
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Preferred" vsizetype="Minimum">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>By default, calibre chooses a cover size based on your computer's screen size. You can change the cover size here:</string>
|
||||||
|
</property>
|
||||||
|
<property name="wordWrap">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="11" column="1">
|
||||||
|
<widget class="QSpinBox" name="opt_emblem_size">
|
||||||
|
<property name="suffix">
|
||||||
|
<string> px</string>
|
||||||
|
</property>
|
||||||
|
<property name="minimum">
|
||||||
|
<number>16</number>
|
||||||
|
</property>
|
||||||
|
<property name="maximum">
|
||||||
|
<number>1000</number>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="11" column="0">
|
||||||
|
<widget class="QLabel" name="label_21">
|
||||||
|
<property name="text">
|
||||||
|
<string>Size of the emblems (if any) shown &next to the covers: </string>
|
||||||
|
</property>
|
||||||
|
<property name="buddy">
|
||||||
|
<cstring>opt_emblem_size</cstring>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="4" column="0" colspan="2">
|
||||||
|
<widget class="QCheckBox" name="opt_cover_grid_show_title">
|
||||||
|
<property name="text">
|
||||||
|
<string>Show a &field (such as title) under the covers</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="12" column="0">
|
||||||
|
<widget class="QLabel" name="label_22">
|
||||||
|
<property name="text">
|
||||||
|
<string>&Location of the emblems shown next to the covers:</string>
|
||||||
|
</property>
|
||||||
|
<property name="buddy">
|
||||||
|
<cstring>opt_emblem_position</cstring>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="12" column="1">
|
||||||
|
<widget class="QComboBox" name="opt_emblem_position"/>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
<widget class="QWidget" name="emblems_tab">
|
||||||
|
<attribute name="title">
|
||||||
|
<string>&Emblems</string>
|
||||||
|
</attribute>
|
||||||
|
</widget>
|
||||||
|
<widget class="QWidget" name="tab_6">
|
||||||
|
<attribute name="title">
|
||||||
|
<string>&Performance</string>
|
||||||
|
</attribute>
|
||||||
|
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||||
|
<item>
|
||||||
|
<widget class="QGroupBox" name="groupBox_3">
|
||||||
|
<property name="title">
|
||||||
|
<string>Caching of covers for improved performance</string>
|
||||||
|
</property>
|
||||||
|
<layout class="QGridLayout" name="gridLayout">
|
||||||
|
<item row="0" column="0" colspan="5">
|
||||||
|
<widget class="QLabel" name="label_13">
|
||||||
|
<property name="text">
|
||||||
|
<string>There are two kinds of caches that calibre uses to improve performance when rendering covers in the grid view. A disk cache that is kept on your hard disk and stores the cover thumbnails and an in memory cache used to ensure flicker free rendering of covers. For best results, keep the memory cache small and the disk cache large, unless you have a lot of extra RAM in your computer and don't mind it being used by the memory cache.</string>
|
||||||
|
</property>
|
||||||
|
<property name="wordWrap">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="2" column="2">
|
||||||
|
<widget class="QSpinBox" name="opt_cover_grid_disk_cache_size">
|
||||||
|
<property name="specialValueText">
|
||||||
|
<string>Disable</string>
|
||||||
|
</property>
|
||||||
|
<property name="suffix">
|
||||||
|
<string> MB</string>
|
||||||
|
</property>
|
||||||
|
<property name="minimum">
|
||||||
|
<number>100</number>
|
||||||
|
</property>
|
||||||
|
<property name="singleStep">
|
||||||
|
<number>100</number>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="4" column="0">
|
||||||
|
<widget class="QPushButton" name="cover_grid_empty_cache">
|
||||||
|
<property name="text">
|
||||||
|
<string>&Empty disk cache</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="4" column="1">
|
||||||
|
<widget class="QPushButton" name="cover_grid_open_cache">
|
||||||
|
<property name="text">
|
||||||
|
<string>&Open cache folder</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="4" column="2" colspan="3">
|
||||||
|
<spacer name="horizontalSpacer_3">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Horizontal</enum>
|
||||||
|
</property>
|
||||||
|
<property name="sizeHint" stdset="0">
|
||||||
|
<size>
|
||||||
|
<width>310</width>
|
||||||
|
<height>20</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
</spacer>
|
||||||
|
</item>
|
||||||
|
<item row="5" column="1">
|
||||||
|
<spacer name="verticalSpacer_2">
|
||||||
|
<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="3">
|
||||||
|
<spacer name="horizontalSpacer_5">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Horizontal</enum>
|
||||||
|
</property>
|
||||||
|
<property name="sizeHint" stdset="0">
|
||||||
|
<size>
|
||||||
|
<width>40</width>
|
||||||
|
<height>20</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
</spacer>
|
||||||
|
</item>
|
||||||
|
<item row="1" column="0" colspan="2">
|
||||||
|
<widget class="QLabel" name="label_15">
|
||||||
|
<property name="text">
|
||||||
|
<string>Number of screenfulls of covers to cache in &memory (keep this small):</string>
|
||||||
|
</property>
|
||||||
|
<property name="buddy">
|
||||||
|
<cstring>opt_cover_grid_cache_size_multiple</cstring>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="2" column="0" colspan="2">
|
||||||
|
<widget class="QLabel" name="label_18">
|
||||||
|
<property name="text">
|
||||||
|
<string>Maximum amount of &disk space to use for caching thumbnails: </string>
|
||||||
|
</property>
|
||||||
|
<property name="buddy">
|
||||||
|
<cstring>opt_cover_grid_disk_cache_size</cstring>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="1" column="2">
|
||||||
|
<widget class="QSpinBox" name="opt_cover_grid_cache_size_multiple">
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>The maximum number of screenfulls of thumbnails to keep in memory. Increasing this will make rendering faster, at the cost of more memory usage. Note that regardless of this setting, a minimum of one hundred thumbnails are always kept in memory, to ensure flicker free rendering.</string>
|
||||||
|
</property>
|
||||||
|
<property name="minimum">
|
||||||
|
<number>2</number>
|
||||||
|
</property>
|
||||||
|
<property name="maximum">
|
||||||
|
<number>100</number>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="3" column="2">
|
||||||
|
<widget class="QLabel" name="cover_grid_current_disk_cache">
|
||||||
|
<property name="text">
|
||||||
|
<string/>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
</widget>
|
||||||
|
<resources>
|
||||||
|
<include location="../../../../resources/images.qrc"/>
|
||||||
|
</resources>
|
||||||
|
<connections>
|
||||||
|
<connection>
|
||||||
|
<sender>opt_cover_grid_show_title</sender>
|
||||||
|
<signal>toggled(bool)</signal>
|
||||||
|
<receiver>opt_field_under_covers_in_grid</receiver>
|
||||||
|
<slot>setEnabled(bool)</slot>
|
||||||
|
<hints>
|
||||||
|
<hint type="sourcelabel">
|
||||||
|
<x>86</x>
|
||||||
|
<y>49</y>
|
||||||
|
</hint>
|
||||||
|
<hint type="destinationlabel">
|
||||||
|
<x>101</x>
|
||||||
|
<y>51</y>
|
||||||
|
</hint>
|
||||||
|
</hints>
|
||||||
|
</connection>
|
||||||
|
</connections>
|
||||||
|
</ui>
|
@ -10,7 +10,7 @@ from qt.core import QKeySequence
|
|||||||
|
|
||||||
from calibre.gui2 import config, gprefs
|
from calibre.gui2 import config, gprefs
|
||||||
from calibre.gui2.dialogs.template_dialog import TemplateDialog
|
from calibre.gui2.dialogs.template_dialog import TemplateDialog
|
||||||
from calibre.gui2.preferences import ConfigWidgetBase, LazyConfigWidgetBase, set_help_tips
|
from calibre.gui2.preferences import LazyConfigWidgetBase, set_help_tips
|
||||||
from calibre.gui2.preferences.look_feel_tabs.cover_view_ui import Ui_Form
|
from calibre.gui2.preferences.look_feel_tabs.cover_view_ui import Ui_Form
|
||||||
|
|
||||||
|
|
||||||
@ -41,8 +41,6 @@ class CoverView(LazyConfigWidgetBase, Ui_Form):
|
|||||||
self.fs_help_msg.setText(self.fs_help_msg.text()%(
|
self.fs_help_msg.setText(self.fs_help_msg.text()%(
|
||||||
QKeySequence(QKeySequence.StandardKey.FullScreen).toString(QKeySequence.SequenceFormat.NativeText)))
|
QKeySequence(QKeySequence.StandardKey.FullScreen).toString(QKeySequence.SequenceFormat.NativeText)))
|
||||||
|
|
||||||
def lazy_initialize(self):
|
|
||||||
ConfigWidgetBase.initialize(self)
|
|
||||||
set_help_tips(self.opt_cover_browser_narrow_view_position, _(
|
set_help_tips(self.opt_cover_browser_narrow_view_position, _(
|
||||||
'This option controls the position of the cover browser when using the Narrow user '
|
'This option controls the position of the cover browser when using the Narrow user '
|
||||||
'interface layout. "Automatic" will place the cover browser on top or on the right '
|
'interface layout. "Automatic" will place the cover browser on top or on the right '
|
||||||
@ -64,12 +62,6 @@ class CoverView(LazyConfigWidgetBase, Ui_Form):
|
|||||||
if t.exec():
|
if t.exec():
|
||||||
self.opt_cover_browser_title_template.setText(t.rule[1])
|
self.opt_cover_browser_title_template.setText(t.rule[1])
|
||||||
|
|
||||||
def commit(self):
|
|
||||||
return ConfigWidgetBase.commit(self)
|
|
||||||
|
|
||||||
def restore_defaults(self):
|
|
||||||
ConfigWidgetBase.restore_defaults(self)
|
|
||||||
|
|
||||||
def refresh_gui(self, gui):
|
def refresh_gui(self, gui):
|
||||||
gui.cover_flow.setShowReflections(gprefs['cover_browser_reflections'])
|
gui.cover_flow.setShowReflections(gprefs['cover_browser_reflections'])
|
||||||
gui.cover_flow.setPreserveAspectRatio(gprefs['cb_preserve_aspect_ratio'])
|
gui.cover_flow.setPreserveAspectRatio(gprefs['cb_preserve_aspect_ratio'])
|
||||||
|
@ -2,13 +2,6 @@
|
|||||||
<ui version="4.0">
|
<ui version="4.0">
|
||||||
<class>Form</class>
|
<class>Form</class>
|
||||||
<widget class="QWidget" name="cover_browser_tab">
|
<widget class="QWidget" name="cover_browser_tab">
|
||||||
<attribute name="icon">
|
|
||||||
<iconset resource="../../../../resources/images.qrc">
|
|
||||||
<normaloff>:/images/cover_flow.png</normaloff>:/images/cover_flow.png</iconset>
|
|
||||||
</attribute>
|
|
||||||
<attribute name="title">
|
|
||||||
<string>Cover &browser</string>
|
|
||||||
</attribute>
|
|
||||||
<layout class="QGridLayout" name="gridLayout_cover_browser">
|
<layout class="QGridLayout" name="gridLayout_cover_browser">
|
||||||
<property name="leftMargin">
|
<property name="leftMargin">
|
||||||
<number>0</number>
|
<number>0</number>
|
||||||
|
77
src/calibre/gui2/preferences/look_feel_tabs/edit_metadata.py
Normal file
77
src/calibre/gui2/preferences/look_feel_tabs/edit_metadata.py
Normal file
@ -0,0 +1,77 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
|
||||||
|
__license__ = 'GPL v3'
|
||||||
|
__copyright__ = '2025, Kovid Goyal <kovid@kovidgoyal.net>'
|
||||||
|
__docformat__ = 'restructuredtext en'
|
||||||
|
|
||||||
|
|
||||||
|
from functools import partial
|
||||||
|
|
||||||
|
from calibre.gui2 import gprefs
|
||||||
|
from calibre.gui2.custom_column_widgets import get_field_list as em_get_field_list
|
||||||
|
from calibre.gui2.preferences import LazyConfigWidgetBase
|
||||||
|
from calibre.gui2.preferences.look_feel_tabs import DisplayedFields, export_layout, import_layout, move_field_down, move_field_up, reset_layout
|
||||||
|
from calibre.gui2.preferences.look_feel_tabs.edit_metadata_ui import Ui_Form
|
||||||
|
from calibre.gui2.widgets import BusyCursor
|
||||||
|
|
||||||
|
|
||||||
|
class EMDisplayedFields(DisplayedFields):
|
||||||
|
def __init__(self, db, parent=None):
|
||||||
|
DisplayedFields.__init__(self, db, parent)
|
||||||
|
|
||||||
|
def initialize(self, use_defaults=False, pref_data_override=None):
|
||||||
|
self.beginResetModel()
|
||||||
|
self.fields = [[x[0], x[1]] for x in
|
||||||
|
em_get_field_list(self.db, use_defaults=use_defaults, pref_data_override=pref_data_override)]
|
||||||
|
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 EditMetadataTab(LazyConfigWidgetBase, Ui_Form):
|
||||||
|
|
||||||
|
def genesis(self, gui):
|
||||||
|
self.gui = gui
|
||||||
|
db = self.gui.library_view.model().db
|
||||||
|
r = self.register
|
||||||
|
|
||||||
|
r('edit_metadata_single_layout', gprefs,
|
||||||
|
choices=[(_('Default'), 'default'), (_('Compact metadata'), 'alt1'),
|
||||||
|
(_('All on 1 tab'), 'alt2')])
|
||||||
|
r('edit_metadata_ignore_display_order', db.prefs)
|
||||||
|
r('edit_metadata_elision_point', gprefs,
|
||||||
|
choices=[(_('Left'), 'left'), (_('Middle'), 'middle'),
|
||||||
|
(_('Right'), 'right')])
|
||||||
|
r('edit_metadata_elide_labels', gprefs)
|
||||||
|
r('edit_metadata_single_use_2_cols_for_custom_fields', gprefs)
|
||||||
|
r('edit_metadata_bulk_cc_label_length', gprefs)
|
||||||
|
r('edit_metadata_single_cc_label_length', gprefs)
|
||||||
|
r('edit_metadata_templates_only_F2_on_booklist', gprefs)
|
||||||
|
|
||||||
|
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)
|
||||||
|
mu = partial(move_field_up, self.em_display_order, self.em_display_model)
|
||||||
|
md = partial(move_field_down, self.em_display_order, self.em_display_model)
|
||||||
|
self.em_display_order.set_movement_functions(mu, md)
|
||||||
|
self.em_up_button.clicked.connect(mu)
|
||||||
|
self.em_down_button.clicked.connect(md)
|
||||||
|
self.em_export_layout_button.clicked.connect(partial(export_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))
|
||||||
|
|
||||||
|
def lazy_initialize(self):
|
||||||
|
self.em_display_model.initialize()
|
||||||
|
|
||||||
|
def commit(self):
|
||||||
|
with BusyCursor():
|
||||||
|
self.em_display_model.commit()
|
||||||
|
return LazyConfigWidgetBase.commit(self)
|
||||||
|
|
||||||
|
def restore_defaults(self):
|
||||||
|
LazyConfigWidgetBase.restore_defaults(self)
|
||||||
|
self.em_display_model.restore_defaults()
|
||||||
|
self.changed_signal.emit()
|
274
src/calibre/gui2/preferences/look_feel_tabs/edit_metadata.ui
Normal file
274
src/calibre/gui2/preferences/look_feel_tabs/edit_metadata.ui
Normal file
@ -0,0 +1,274 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<ui version="4.0">
|
||||||
|
<class>Form</class>
|
||||||
|
<widget class="QWidget" name="edit_metadata_tab">
|
||||||
|
<attribute name="icon">
|
||||||
|
<iconset resource="../../../../resources/images.qrc">
|
||||||
|
<normaloff>:/images/edit_input.png</normaloff>:/images/edit_input.png</iconset>
|
||||||
|
</attribute>
|
||||||
|
<attribute name="title">
|
||||||
|
<string>Edit &metadata</string>
|
||||||
|
</attribute>
|
||||||
|
<layout class="QVBoxLayout" name="vbox_layout_61">
|
||||||
|
<item>
|
||||||
|
<layout class="QFormLayout">
|
||||||
|
<item row="0" column="0">
|
||||||
|
<widget class="QLabel" name="edit_metadata_single_label">
|
||||||
|
<property name="text">
|
||||||
|
<string>Edit metadata (single) &layout:</string>
|
||||||
|
</property>
|
||||||
|
<property name="buddy">
|
||||||
|
<cstring>opt_edit_metadata_single_layout</cstring>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="0" 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>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QGroupBox" name="groupBox">
|
||||||
|
<property name="title">
|
||||||
|
<string>Select the custom columns (for this library) to display in the edit metadata 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. 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="em_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="em_display_order">
|
||||||
|
<property name="alternatingRowColors">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="5" column="0">
|
||||||
|
<layout class="QHBoxLayout" name="horizontalLayout_4">
|
||||||
|
<item>
|
||||||
|
<widget class="QPushButton" name="em_reset_layout_button">
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>Click this button to reset the list to its default order.</string>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Reset list</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QPushButton" name="em_import_layout_button">
|
||||||
|
<property name="toolTip">
|
||||||
|
<string><p>Click this button to set the list to one
|
||||||
|
previously exported. This could be useful if you have several libraries with
|
||||||
|
similar structure and you want to use the same column order for each one. Columns
|
||||||
|
in the imported list that aren't in the current library are ignored. Columns in
|
||||||
|
the library that are not in the imported list are put at the end and marked
|
||||||
|
as displayable.</p></string>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Import list</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QPushButton" name="em_export_layout_button">
|
||||||
|
<property name="toolTip">
|
||||||
|
<string><p>Click this button to write the current display
|
||||||
|
settings to a file. This could be useful if you have several libraries with similar
|
||||||
|
structure and you want to use the same column order for each one.</p></string>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Export list</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<spacer name="horizontalSpacer">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Horizontal</enum>
|
||||||
|
</property>
|
||||||
|
<property name="sizeHint" stdset="0">
|
||||||
|
<size>
|
||||||
|
<width>40</width>
|
||||||
|
<height>20</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
</spacer>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<layout class="QHBoxLayout">
|
||||||
|
<item>
|
||||||
|
<layout class="QFormLayout">
|
||||||
|
<item row="0" column="0" colspan="2">
|
||||||
|
<widget class="QCheckBox" name="opt_edit_metadata_ignore_display_order">
|
||||||
|
<property name="toolTip">
|
||||||
|
<string><p>Check this box to make the edit metadata dialogs ignore the
|
||||||
|
above specifications, showing all the columns in the default order. This is
|
||||||
|
useful for temporarily seeing all your columns in the dialogs without losing
|
||||||
|
the display and order specifications.</p></string>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Show &all columns in default order when editing metadata</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="1" column="0" colspan="2">
|
||||||
|
<widget class="QCheckBox" name="opt_edit_metadata_elide_labels">
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>If checked then labels wider than the label width
|
||||||
|
will be elided, otherwise they will be word wrapped.</string>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>&Elide labels when editing custom columns</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="2" column="0">
|
||||||
|
<widget class="QLabel" name="label_1023">
|
||||||
|
<property name="text">
|
||||||
|
<string/>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="2" column="1">
|
||||||
|
<layout class="QHBoxLayout">
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="label_102">
|
||||||
|
<property name="text">
|
||||||
|
<string>Elision point:</string>
|
||||||
|
</property>
|
||||||
|
<property name="buddy">
|
||||||
|
<cstring>opt_edit_metadata_elision_point</cstring>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QComboBox" name="opt_edit_metadata_elision_point">
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>Choose where in the label to put the...</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
<item row="3" column="0" colspan="2">
|
||||||
|
<widget class="QCheckBox" name="opt_edit_metadata_templates_only_F2_on_booklist">
|
||||||
|
<property name="toolTip">
|
||||||
|
<string><p>Check this box to allow only the F2 (Edit) key to
|
||||||
|
open the template editor in the book list for a "Column built from other
|
||||||
|
columns". Editing with mouse clicks and the Tab key will be disabled.</p></string>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Only the &F2 (Edit) key edits column templates in the book list</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<layout class="QFormLayout">
|
||||||
|
<item row="0" column="0" colspan="2">
|
||||||
|
<widget class="QCheckBox" name="opt_edit_metadata_single_use_2_cols_for_custom_fields">
|
||||||
|
<property name="text">
|
||||||
|
<string>Use &two columns for custom columns in the Default layout</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="1" column="0">
|
||||||
|
<widget class="QLabel" name="label_102">
|
||||||
|
<property name="text">
|
||||||
|
<string>&Bulk edit custom column label length:</string>
|
||||||
|
</property>
|
||||||
|
<property name="buddy">
|
||||||
|
<cstring>opt_edit_metadata_bulk_cc_label_length</cstring>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="1" column="1">
|
||||||
|
<widget class="QSpinBox" name="opt_edit_metadata_bulk_cc_label_length">
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>The maximum width of a custom column label for the bulk metadata edit dialog in average characters.</string>
|
||||||
|
</property>
|
||||||
|
<property name="suffix">
|
||||||
|
<string> chars</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="2" column="0">
|
||||||
|
<widget class="QLabel" name="label_1022">
|
||||||
|
<property name="text">
|
||||||
|
<string>&Single edit custom column label length:</string>
|
||||||
|
</property>
|
||||||
|
<property name="buddy">
|
||||||
|
<cstring>opt_edit_metadata_single_cc_label_length</cstring>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="2" column="1">
|
||||||
|
<widget class="QSpinBox" name="opt_edit_metadata_single_cc_label_length">
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>The maximum width of a custom column label for the single metadata edit dialog in average characters.</string>
|
||||||
|
</property>
|
||||||
|
<property name="suffix">
|
||||||
|
<string> chars</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
<customwidgets>
|
||||||
|
<customwidget>
|
||||||
|
<class>ListViewWithMoveByKeyPress</class>
|
||||||
|
<extends>QListView</extends>
|
||||||
|
<header>calibre/gui2/preferences.h</header>
|
||||||
|
</customwidget>
|
||||||
|
</customwidgets>
|
||||||
|
<resources>
|
||||||
|
<include location="../../../../resources/images.qrc"/>
|
||||||
|
</resources>
|
||||||
|
</ui>
|
193
src/calibre/gui2/preferences/look_feel_tabs/main_interface.py
Normal file
193
src/calibre/gui2/preferences/look_feel_tabs/main_interface.py
Normal file
@ -0,0 +1,193 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
|
||||||
|
__license__ = 'GPL v3'
|
||||||
|
__copyright__ = '2025, Kovid Goyal <kovid@kovidgoyal.net>'
|
||||||
|
__docformat__ = 'restructuredtext en'
|
||||||
|
|
||||||
|
|
||||||
|
from qt.core import QApplication, QDialog, QFont, QFontDialog, QFontInfo
|
||||||
|
|
||||||
|
from calibre.constants import ismacos, iswindows
|
||||||
|
from calibre.gui2 import config, gprefs, icon_resource_manager, qt_app
|
||||||
|
from calibre.gui2.preferences import LazyConfigWidgetBase, Setting, set_help_tips
|
||||||
|
from calibre.gui2.preferences.look_feel_tabs.main_interface_ui import Ui_Form
|
||||||
|
from calibre.gui2.widgets import BusyCursor
|
||||||
|
from calibre.utils.config import prefs
|
||||||
|
from calibre.utils.localization import available_translations, get_lang, get_language
|
||||||
|
|
||||||
|
|
||||||
|
class LanguageSetting(Setting):
|
||||||
|
|
||||||
|
def commit(self):
|
||||||
|
val = self.get_gui_val()
|
||||||
|
oldval = self.get_config_val()
|
||||||
|
if val != oldval:
|
||||||
|
gprefs.set('last_used_language', oldval)
|
||||||
|
return super().commit()
|
||||||
|
|
||||||
|
|
||||||
|
class MainInterfaceTab(LazyConfigWidgetBase, Ui_Form):
|
||||||
|
|
||||||
|
def genesis(self, gui):
|
||||||
|
self.gui = gui
|
||||||
|
self.ui_style_available = True
|
||||||
|
if not ismacos and not iswindows:
|
||||||
|
self.label_widget_style.setVisible(False)
|
||||||
|
self.opt_ui_style.setVisible(False)
|
||||||
|
self.ui_style_available = False
|
||||||
|
|
||||||
|
r = self.register
|
||||||
|
|
||||||
|
try:
|
||||||
|
self.icon_theme_title = icon_resource_manager.user_theme_title
|
||||||
|
except Exception:
|
||||||
|
self.icon_theme_title = _('Default icons')
|
||||||
|
self.icon_theme.setText(_('Icon theme: <b>%s</b>') % self.icon_theme_title)
|
||||||
|
self.commit_icon_theme = None
|
||||||
|
self.icon_theme_button.clicked.connect(self.choose_icon_theme)
|
||||||
|
|
||||||
|
r('ui_style', gprefs, restart_required=True, choices=[(_('System default'), 'system'), (_('calibre style'), 'calibre')])
|
||||||
|
r('book_list_tooltips', gprefs)
|
||||||
|
r('dnd_merge', gprefs)
|
||||||
|
r('wrap_toolbar_text', gprefs, restart_required=True)
|
||||||
|
r('show_layout_buttons', gprefs)
|
||||||
|
r('show_sb_all_actions_button', gprefs)
|
||||||
|
# r('show_sb_preference_button', gprefs)
|
||||||
|
r('row_numbers_in_book_list', gprefs)
|
||||||
|
r('cover_corner_radius', gprefs)
|
||||||
|
r('cover_corner_radius_unit', gprefs, choices=[(_('Pixels'), 'px'), (_('Percentage'), '%')])
|
||||||
|
r('book_list_extra_row_spacing', gprefs)
|
||||||
|
r('booklist_grid', gprefs)
|
||||||
|
|
||||||
|
def get_esc_lang(l):
|
||||||
|
if l == 'en':
|
||||||
|
return 'English'
|
||||||
|
return get_language(l)
|
||||||
|
|
||||||
|
lang = get_lang()
|
||||||
|
if lang is None or lang not in available_translations():
|
||||||
|
lang = 'en'
|
||||||
|
items = [(l, get_esc_lang(l)) for l in available_translations()
|
||||||
|
if l != lang]
|
||||||
|
if lang != 'en':
|
||||||
|
items.append(('en', get_esc_lang('en')))
|
||||||
|
items.sort(key=lambda x: x[1].lower())
|
||||||
|
choices = [(y, x) for x, y in items]
|
||||||
|
# Default language is the autodetected one
|
||||||
|
choices = [(get_language(lang), lang)] + choices
|
||||||
|
lul = gprefs.get('last_used_language')
|
||||||
|
if lul and (lul in available_translations() or lul in ('en', 'eng')):
|
||||||
|
choices.insert(1, ((get_language(lul), lul)))
|
||||||
|
r('language', prefs, choices=choices, restart_required=True, setting=LanguageSetting)
|
||||||
|
|
||||||
|
r('disable_animations', config)
|
||||||
|
r('systray_icon', config, restart_required=True)
|
||||||
|
r('show_splash_screen', gprefs)
|
||||||
|
r('disable_tray_notification', config)
|
||||||
|
|
||||||
|
choices = [(_('Off'), 'off'), (_('Small'), 'small'),
|
||||||
|
(_('Medium-small'), 'mid-small'), (_('Medium'), 'medium'), (_('Large'), 'large')]
|
||||||
|
r('toolbar_icon_size', gprefs, choices=choices)
|
||||||
|
|
||||||
|
choices = [(_('If there is enough room'), 'auto'), (_('Always'), 'always'),
|
||||||
|
(_('Never'), 'never')]
|
||||||
|
r('toolbar_text', gprefs, choices=choices)
|
||||||
|
|
||||||
|
self.current_font = self.initial_font = None
|
||||||
|
self.change_font_button.clicked.connect(self.change_font)
|
||||||
|
|
||||||
|
self.opt_ui_style.currentIndexChanged.connect(self.update_color_palette_state)
|
||||||
|
self.opt_gui_layout.addItem(_('Wide'), 'wide')
|
||||||
|
self.opt_gui_layout.addItem(_('Narrow'), 'narrow')
|
||||||
|
self.opt_gui_layout.currentIndexChanged.connect(self.changed_signal)
|
||||||
|
set_help_tips(self.opt_gui_layout, config.help('gui_layout'))
|
||||||
|
self.button_adjust_colors.clicked.connect(self.adjust_colors)
|
||||||
|
|
||||||
|
def lazy_initialize(self):
|
||||||
|
font = gprefs['font']
|
||||||
|
if font is not None:
|
||||||
|
font = list(font)
|
||||||
|
font.append(gprefs.get('font_stretch', QFont.Stretch.Unstretched))
|
||||||
|
self.current_font = self.initial_font = font
|
||||||
|
self.update_font_display()
|
||||||
|
self.update_color_palette_state()
|
||||||
|
self.opt_gui_layout.setCurrentIndex(0 if self.gui.layout_container.is_wide else 1)
|
||||||
|
|
||||||
|
def adjust_colors(self):
|
||||||
|
from calibre.gui2.dialogs.palette import PaletteConfig
|
||||||
|
d = PaletteConfig(self)
|
||||||
|
if d.exec() == QDialog.DialogCode.Accepted:
|
||||||
|
d.apply_settings()
|
||||||
|
self.changed_signal.emit()
|
||||||
|
|
||||||
|
def update_color_palette_state(self):
|
||||||
|
if self.ui_style_available:
|
||||||
|
enabled = self.opt_ui_style.currentData() == 'calibre'
|
||||||
|
self.button_adjust_colors.setEnabled(enabled)
|
||||||
|
|
||||||
|
def choose_icon_theme(self):
|
||||||
|
from calibre.gui2.icon_theme import ChooseTheme
|
||||||
|
d = ChooseTheme(self)
|
||||||
|
if d.exec() == QDialog.DialogCode.Accepted:
|
||||||
|
self.commit_icon_theme = d.commit_changes
|
||||||
|
self.icon_theme_title = d.new_theme_title or _('Default icons')
|
||||||
|
self.icon_theme.setText(_('Icon theme: <b>%s</b>') % self.icon_theme_title)
|
||||||
|
self.changed_signal.emit()
|
||||||
|
|
||||||
|
def build_font_obj(self):
|
||||||
|
font_info = qt_app.original_font if self.current_font is None else self.current_font
|
||||||
|
font = QFont(*(font_info[:4]))
|
||||||
|
font.setStretch(font_info[4])
|
||||||
|
return font
|
||||||
|
|
||||||
|
def change_font(self, *args):
|
||||||
|
fd = QFontDialog(self.build_font_obj(), self)
|
||||||
|
if fd.exec() == QDialog.DialogCode.Accepted:
|
||||||
|
font = fd.selectedFont()
|
||||||
|
fi = QFontInfo(font)
|
||||||
|
self.current_font = [str(fi.family()), fi.pointSize(),
|
||||||
|
fi.weight(), fi.italic(), font.stretch()]
|
||||||
|
self.update_font_display()
|
||||||
|
self.changed_signal.emit()
|
||||||
|
|
||||||
|
def update_font_display(self):
|
||||||
|
font = self.build_font_obj()
|
||||||
|
fi = QFontInfo(font)
|
||||||
|
name = str(fi.family())
|
||||||
|
|
||||||
|
self.font_display.setFont(font)
|
||||||
|
self.font_display.setText(name + f' [{fi.pointSize()}pt]')
|
||||||
|
|
||||||
|
def commit(self):
|
||||||
|
rr = LazyConfigWidgetBase.commit(self)
|
||||||
|
with BusyCursor():
|
||||||
|
if self.current_font != self.initial_font:
|
||||||
|
gprefs['font'] = (self.current_font[:4] if self.current_font else None)
|
||||||
|
gprefs['font_stretch'] = (self.current_font[4] if self.current_font
|
||||||
|
is not None else QFont.Stretch.Unstretched)
|
||||||
|
QApplication.setFont(self.font_display.font())
|
||||||
|
rr = True
|
||||||
|
if self.commit_icon_theme is not None:
|
||||||
|
self.commit_icon_theme()
|
||||||
|
self.gui.layout_container.change_layout(self.gui, self.opt_gui_layout.currentIndex() == 0)
|
||||||
|
return rr
|
||||||
|
|
||||||
|
def restore_defaults(self):
|
||||||
|
LazyConfigWidgetBase.restore_defaults(self)
|
||||||
|
ofont = self.current_font
|
||||||
|
self.current_font = None
|
||||||
|
if ofont is not None:
|
||||||
|
self.changed_signal.emit()
|
||||||
|
self.main_interface_tab.update_font_display()
|
||||||
|
self.opt_gui_layout.setCurrentIndex(0)
|
||||||
|
self.changed_signal.emit()
|
||||||
|
|
||||||
|
def refresh_gui(self, gui):
|
||||||
|
gui.place_layout_buttons()
|
||||||
|
self.update_font_display()
|
||||||
|
gui.library_view.set_row_header_visibility()
|
||||||
|
for view in 'library memory card_a card_b'.split():
|
||||||
|
getattr(gui, view + '_view').set_row_header_visibility()
|
||||||
|
gui.library_view.refresh_row_sizing()
|
||||||
|
gui.sb_all_gui_actions_button.setVisible(gprefs['show_sb_all_actions_button'])
|
||||||
|
# gui.sb_preferences_button.setVisible(gprefs['show_sb_preference_button'])
|
356
src/calibre/gui2/preferences/look_feel_tabs/main_interface.ui
Normal file
356
src/calibre/gui2/preferences/look_feel_tabs/main_interface.ui
Normal file
@ -0,0 +1,356 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<ui version="4.0">
|
||||||
|
<class>Form</class>
|
||||||
|
<widget class="QWidget" name="main_interface_tab">
|
||||||
|
<layout class="QGridLayout" name="gridLayout_main_interface">
|
||||||
|
<item row="0" column="0">
|
||||||
|
<widget class="QLabel" name="label_widget_style">
|
||||||
|
<property name="text">
|
||||||
|
<string>User interface style (&needs restart):</string>
|
||||||
|
</property>
|
||||||
|
<property name="buddy">
|
||||||
|
<cstring>opt_ui_style</cstring>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="0" column="1">
|
||||||
|
<widget class="QComboBox" name="opt_ui_style"/>
|
||||||
|
</item>
|
||||||
|
<item row="0" column="2">
|
||||||
|
<layout class="QHBoxLayout">
|
||||||
|
<item>
|
||||||
|
<spacer name="horizontalSpacer_3">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Horizontal</enum>
|
||||||
|
</property>
|
||||||
|
<property name="sizeHint" stdset="0">
|
||||||
|
<size>
|
||||||
|
<width>20</width>
|
||||||
|
<height>1</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
</spacer>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
<item row="1" column="0">
|
||||||
|
<widget class="QLabel" name="icon_theme">
|
||||||
|
<property name="text">
|
||||||
|
<string/>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="1" column="1">
|
||||||
|
<widget class="QPushButton" name="icon_theme_button">
|
||||||
|
<property name="text">
|
||||||
|
<string>Change &icon theme</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="2" column="0">
|
||||||
|
<widget class="QLabel" name="opt_color_palette_label">
|
||||||
|
<property name="text">
|
||||||
|
<string>User interface &colors:</string>
|
||||||
|
</property>
|
||||||
|
<property name="buddy">
|
||||||
|
<cstring>button_adjust_colors</cstring>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="2" column="1">
|
||||||
|
<widget class="QPushButton" name="button_adjust_colors">
|
||||||
|
<property name="text">
|
||||||
|
<string>Adjust &colors</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="3" column="0">
|
||||||
|
<widget class="QLabel" name="label_17">
|
||||||
|
<property name="text">
|
||||||
|
<string>&User interface layout:</string>
|
||||||
|
</property>
|
||||||
|
<property name="buddy">
|
||||||
|
<cstring>opt_gui_layout</cstring>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="3" column="1">
|
||||||
|
<widget class="QComboBox" name="opt_gui_layout">
|
||||||
|
<property name="maximumSize">
|
||||||
|
<size>
|
||||||
|
<width>250</width>
|
||||||
|
<height>16777215</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
<property name="sizeAdjustPolicy">
|
||||||
|
<enum>QComboBox::AdjustToMinimumContentsLengthWithIcon</enum>
|
||||||
|
</property>
|
||||||
|
<property name="minimumContentsLength">
|
||||||
|
<number>20</number>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="4" column="0">
|
||||||
|
<widget class="QLabel" name="label_7">
|
||||||
|
<property name="text">
|
||||||
|
<string>Choose &language (needs restart):</string>
|
||||||
|
</property>
|
||||||
|
<property name="buddy">
|
||||||
|
<cstring>opt_language</cstring>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="4" column="1">
|
||||||
|
<widget class="QComboBox" name="opt_language">
|
||||||
|
<property name="sizeAdjustPolicy">
|
||||||
|
<enum>QComboBox::AdjustToMinimumContentsLengthWithIcon</enum>
|
||||||
|
</property>
|
||||||
|
<property name="minimumContentsLength">
|
||||||
|
<number>20</number>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="5" column="0">
|
||||||
|
<widget class="QLabel" name="label_6">
|
||||||
|
<property name="text">
|
||||||
|
<string>&Round the corners of covers:</string>
|
||||||
|
</property>
|
||||||
|
<property name="buddy">
|
||||||
|
<cstring>opt_cover_corner_radius</cstring>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="5" column="1">
|
||||||
|
<layout class="QHBoxLayout" name="horizontalLayout_3">
|
||||||
|
<item>
|
||||||
|
<widget class="QSpinBox" name="opt_cover_corner_radius">
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>Round the corners of covers in many places they are displayed such as the Cover grid, Book details panel, etc. Adjust the amount of rounding with this setting. A value of between 5 and 10 looks good with most covers sizes. Zero disables rounding and is the default.</string>
|
||||||
|
</property>
|
||||||
|
<property name="specialValueText">
|
||||||
|
<string>no rounding</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QComboBox" name="opt_cover_corner_radius_unit">
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>The unit for the cover corner rounding. Either pixel values or as a percentage of the cover size.</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
<item row="6" column="0">
|
||||||
|
<widget class="QCheckBox" name="opt_systray_icon">
|
||||||
|
<property name="text">
|
||||||
|
<string>Enable s&ystem tray icon (needs restart)</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="6" column="1">
|
||||||
|
<widget class="QCheckBox" name="opt_disable_animations">
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>Disable all animations. Useful if you have a slow/old computer.</string>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Disable &animations</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="7" column="0">
|
||||||
|
<widget class="QCheckBox" name="opt_disable_tray_notification">
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>Disable popup notifications when calibre completes jobs such a conversion, sending to device etc. The notifications are sent via the operating system notification facility, if available.</string>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Disable n&otifications on job completion</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="7" column="1">
|
||||||
|
<widget class="QCheckBox" name="opt_show_splash_screen">
|
||||||
|
<property name="text">
|
||||||
|
<string>Show the &splash screen at startup</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="8" column="0">
|
||||||
|
<widget class="QCheckBox" name="opt_book_list_tooltips">
|
||||||
|
<property name="text">
|
||||||
|
<string>Show &tooltips in the book list</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="9" column="0">
|
||||||
|
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="label_2">
|
||||||
|
<property name="text">
|
||||||
|
<string>&Interface font:</string>
|
||||||
|
</property>
|
||||||
|
<property name="buddy">
|
||||||
|
<cstring>font_display</cstring>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QLineEdit" name="font_display">
|
||||||
|
<property name="readOnly">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
<item row="9" column="1">
|
||||||
|
<widget class="QPushButton" name="change_font_button">
|
||||||
|
<property name="text">
|
||||||
|
<string>Change &font (needs restart)</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="10" column="0">
|
||||||
|
<widget class="QGroupBox" name="groupBox_2">
|
||||||
|
<property name="title">
|
||||||
|
<string>Toolbar</string>
|
||||||
|
</property>
|
||||||
|
<layout class="QGridLayout" name="gridLayout_8">
|
||||||
|
<item row="0" column="1">
|
||||||
|
<widget class="QComboBox" name="opt_toolbar_icon_size"/>
|
||||||
|
</item>
|
||||||
|
<item row="0" column="0">
|
||||||
|
<widget class="QLabel" name="label_5">
|
||||||
|
<property name="text">
|
||||||
|
<string>Icon si&ze:</string>
|
||||||
|
</property>
|
||||||
|
<property name="buddy">
|
||||||
|
<cstring>opt_toolbar_icon_size</cstring>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="1" column="1">
|
||||||
|
<widget class="QComboBox" name="opt_toolbar_text"/>
|
||||||
|
</item>
|
||||||
|
<item row="1" column="0">
|
||||||
|
<widget class="QLabel" name="label_8">
|
||||||
|
<property name="text">
|
||||||
|
<string>Show &text under icons:</string>
|
||||||
|
</property>
|
||||||
|
<property name="buddy">
|
||||||
|
<cstring>opt_toolbar_text</cstring>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="2" column="0" colspan="2">
|
||||||
|
<widget class="QCheckBox" name="opt_wrap_toolbar_text">
|
||||||
|
<property name="text">
|
||||||
|
<string>Use t&wo lines for the text under the icons (needs restart)</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="10" column="1">
|
||||||
|
<widget class="QGroupBox" name="groupBox">
|
||||||
|
<property name="title">
|
||||||
|
<string>Status bar buttons</string>
|
||||||
|
</property>
|
||||||
|
<layout class="QVBoxLayout">
|
||||||
|
<item>
|
||||||
|
<widget class="QCheckBox" name="opt_show_layout_buttons">
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>Show individual buttons to control the layout of the interface rather than a single button with a popup.</string>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Show &layout buttons</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QCheckBox" name="opt_show_sb_all_actions_button">
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>Show a button that gives quick access to all available actions with a single click.</string>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>S&how actions button</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<spacer name="horizontalSpacer_3">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Vertical</enum>
|
||||||
|
</property>
|
||||||
|
<property name="sizeHint" stdset="0">
|
||||||
|
<size>
|
||||||
|
<width>10</width>
|
||||||
|
<height>20</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
</spacer>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="11" column="0">
|
||||||
|
<widget class="QLabel" name="label_4">
|
||||||
|
<property name="text">
|
||||||
|
<string>E&xtra spacing to add between rows in the book list (can be negative):</string>
|
||||||
|
</property>
|
||||||
|
<property name="buddy">
|
||||||
|
<cstring>opt_book_list_extra_row_spacing</cstring>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="11" column="1">
|
||||||
|
<widget class="QSpinBox" name="opt_book_list_extra_row_spacing">
|
||||||
|
<property name="suffix">
|
||||||
|
<string> px</string>
|
||||||
|
</property>
|
||||||
|
<property name="minimum">
|
||||||
|
<number>-20</number>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="12" column="0">
|
||||||
|
<widget class="QCheckBox" name="opt_row_numbers_in_book_list">
|
||||||
|
<property name="text">
|
||||||
|
<string>Show &row numbers in the book list</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="13" column="0">
|
||||||
|
<widget class="QCheckBox" name="opt_booklist_grid">
|
||||||
|
<property name="text">
|
||||||
|
<string>Draw a &grid in the book list</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="14" column="0">
|
||||||
|
<widget class="QCheckBox" name="opt_dnd_merge">
|
||||||
|
<property name="text">
|
||||||
|
<string>Allow using &drag and drop to merge books</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="15" column="0">
|
||||||
|
<spacer name="verticalSpacer_3">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Vertical</enum>
|
||||||
|
</property>
|
||||||
|
<property name="sizeHint" stdset="0">
|
||||||
|
<size>
|
||||||
|
<width>20</width>
|
||||||
|
<height>40</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
</spacer>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
<resources>
|
||||||
|
<include location="../../../../resources/images.qrc"/>
|
||||||
|
</resources>
|
||||||
|
</ui>
|
@ -10,12 +10,12 @@ from functools import partial
|
|||||||
from calibre.gui2 import gprefs
|
from calibre.gui2 import gprefs
|
||||||
from calibre.gui2.actions.show_quickview import get_quickview_action_plugin
|
from calibre.gui2.actions.show_quickview import get_quickview_action_plugin
|
||||||
from calibre.gui2.dialogs.quickview import get_qv_field_list
|
from calibre.gui2.dialogs.quickview import get_qv_field_list
|
||||||
from calibre.gui2.preferences import ConfigWidgetBase, LazyConfigWidgetBase
|
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 import DisplayedFields, move_field_down, move_field_up
|
||||||
from calibre.gui2.preferences.look_feel_tabs.quickview_ui import Ui_Form
|
from calibre.gui2.preferences.look_feel_tabs.quickview_ui import Ui_Form
|
||||||
|
|
||||||
|
|
||||||
class QVDisplayedFields(DisplayedFields): # {{{
|
class QVDisplayedFields(DisplayedFields):
|
||||||
|
|
||||||
def __init__(self, db, parent=None):
|
def __init__(self, db, parent=None):
|
||||||
DisplayedFields.__init__(self, db, parent)
|
DisplayedFields.__init__(self, db, parent)
|
||||||
@ -31,8 +31,6 @@ class QVDisplayedFields(DisplayedFields): # {{{
|
|||||||
if self.changed:
|
if self.changed:
|
||||||
self.db.new_api.set_pref('qv_display_fields', self.fields)
|
self.db.new_api.set_pref('qv_display_fields', self.fields)
|
||||||
|
|
||||||
# }}}
|
|
||||||
|
|
||||||
|
|
||||||
class QuickviewTab(LazyConfigWidgetBase, Ui_Form):
|
class QuickviewTab(LazyConfigWidgetBase, Ui_Form):
|
||||||
|
|
||||||
@ -59,7 +57,7 @@ class QuickviewTab(LazyConfigWidgetBase, Ui_Form):
|
|||||||
self.qv_display_model.initialize()
|
self.qv_display_model.initialize()
|
||||||
|
|
||||||
def restore_defaults(self):
|
def restore_defaults(self):
|
||||||
ConfigWidgetBase.restore_defaults(self)
|
LazyConfigWidgetBase.restore_defaults(self)
|
||||||
self.qv_display_model.restore_defaults()
|
self.qv_display_model.restore_defaults()
|
||||||
|
|
||||||
def refresh_gui(self, gui):
|
def refresh_gui(self, gui):
|
||||||
@ -67,7 +65,6 @@ class QuickviewTab(LazyConfigWidgetBase, Ui_Form):
|
|||||||
if qv:
|
if qv:
|
||||||
qv.refill_quickview()
|
qv.refill_quickview()
|
||||||
|
|
||||||
def commit(self, *args):
|
def commit(self):
|
||||||
rr = ConfigWidgetBase.commit(self, *args)
|
|
||||||
self.qv_display_model.commit()
|
self.qv_display_model.commit()
|
||||||
return rr
|
return LazyConfigWidgetBase.commit(self)
|
||||||
|
@ -2,10 +2,6 @@
|
|||||||
<ui version="4.0">
|
<ui version="4.0">
|
||||||
<class>Form</class>
|
<class>Form</class>
|
||||||
<widget class="QWidget" name="cover_browser_tab">
|
<widget class="QWidget" name="cover_browser_tab">
|
||||||
<attribute name="icon">
|
|
||||||
<iconset resource="../../../../resources/images.qrc">
|
|
||||||
<normaloff>:/images/cover_flow.png</normaloff>:/images/cover_flow.png</iconset>
|
|
||||||
</attribute>
|
|
||||||
<layout class="QGridLayout" name="gridLayout_122">
|
<layout class="QGridLayout" name="gridLayout_122">
|
||||||
<item row="1" column="0" colspan="2">
|
<item row="1" column="0" colspan="2">
|
||||||
<layout class="QGridLayout" name="gridLayout_122">
|
<layout class="QGridLayout" name="gridLayout_122">
|
||||||
|
@ -9,12 +9,12 @@ from functools import partial
|
|||||||
|
|
||||||
from calibre.db.categories import is_standard_category
|
from calibre.db.categories import is_standard_category
|
||||||
from calibre.gui2 import config, gprefs
|
from calibre.gui2 import config, gprefs
|
||||||
from calibre.gui2.preferences import ConfigWidgetBase, LazyConfigWidgetBase
|
from calibre.gui2.preferences import LazyConfigWidgetBase
|
||||||
from calibre.gui2.preferences.look_feel_tabs import DisplayedFields, export_layout, import_layout, move_field_down, move_field_up, reset_layout
|
from calibre.gui2.preferences.look_feel_tabs import DisplayedFields, export_layout, import_layout, move_field_down, move_field_up, reset_layout
|
||||||
from calibre.gui2.preferences.look_feel_tabs.tb_display_ui import Ui_Form
|
from calibre.gui2.preferences.look_feel_tabs.tb_display_ui import Ui_Form
|
||||||
|
|
||||||
|
|
||||||
class TBDisplayedFields(DisplayedFields): # {{{
|
class TBDisplayedFields(DisplayedFields):
|
||||||
# The code in this class depends on the fact that the tag browser is
|
# The code in this class depends on the fact that the tag browser is
|
||||||
# initialized before this class is instantiated.
|
# initialized before this class is instantiated.
|
||||||
|
|
||||||
@ -44,7 +44,6 @@ class TBDisplayedFields(DisplayedFields): # {{{
|
|||||||
if self.changed:
|
if self.changed:
|
||||||
self.db.prefs.set('tag_browser_hidden_categories', [k for k,v in self.fields if not v])
|
self.db.prefs.set('tag_browser_hidden_categories', [k for k,v in self.fields if not v])
|
||||||
self.db.prefs.set('tag_browser_category_order', [k for k,v in self.fields])
|
self.db.prefs.set('tag_browser_category_order', [k for k,v in self.fields])
|
||||||
# }}}
|
|
||||||
|
|
||||||
|
|
||||||
class TbDisplayTab(LazyConfigWidgetBase, Ui_Form):
|
class TbDisplayTab(LazyConfigWidgetBase, Ui_Form):
|
||||||
@ -104,9 +103,12 @@ class TbDisplayTab(LazyConfigWidgetBase, Ui_Form):
|
|||||||
move_field_up(self.tb_display_order, model)
|
move_field_up(self.tb_display_order, model)
|
||||||
|
|
||||||
def restore_defaults(self):
|
def restore_defaults(self):
|
||||||
ConfigWidgetBase.restore_defaults(self)
|
LazyConfigWidgetBase.restore_defaults(self)
|
||||||
self.tb_display_model.restore_defaults()
|
self.tb_display_model.restore_defaults()
|
||||||
|
|
||||||
def commit(self):
|
def commit(self):
|
||||||
self.tb_display_model.commit()
|
self.tb_display_model.commit()
|
||||||
return ConfigWidgetBase.commit(self)
|
return LazyConfigWidgetBase.commit(self)
|
||||||
|
|
||||||
|
def refresh_gui(self, gui):
|
||||||
|
gui.tags_view.set_look_and_feel()
|
||||||
|
@ -2,17 +2,6 @@
|
|||||||
<ui version="4.0">
|
<ui version="4.0">
|
||||||
<class>Form</class>
|
<class>Form</class>
|
||||||
<widget class="QWidget" name="Form">
|
<widget class="QWidget" name="Form">
|
||||||
<property name="geometry">
|
|
||||||
<rect>
|
|
||||||
<x>0</x>
|
|
||||||
<y>0</y>
|
|
||||||
<width>1096</width>
|
|
||||||
<height>791</height>
|
|
||||||
</rect>
|
|
||||||
</property>
|
|
||||||
<property name="windowTitle">
|
|
||||||
<string>Form</string>
|
|
||||||
</property>
|
|
||||||
<layout class="QGridLayout" name="verticalLayout_42">
|
<layout class="QGridLayout" name="verticalLayout_42">
|
||||||
<item row="0" column="0">
|
<item row="0" column="0">
|
||||||
<widget class="QLabel" name="label">
|
<widget class="QLabel" name="label">
|
||||||
|
@ -16,7 +16,7 @@ from calibre.gui2.preferences.look_feel_tabs import DisplayedFields
|
|||||||
from calibre.gui2.preferences.look_feel_tabs.tb_hierarchy_ui import Ui_Form
|
from calibre.gui2.preferences.look_feel_tabs.tb_hierarchy_ui import Ui_Form
|
||||||
|
|
||||||
|
|
||||||
class TBHierarchicalFields(DisplayedFields): # {{{
|
class TBHierarchicalFields(DisplayedFields):
|
||||||
# The code in this class depends on the fact that the tag browser is
|
# The code in this class depends on the fact that the tag browser is
|
||||||
# initialized before this class is instantiated.
|
# initialized before this class is instantiated.
|
||||||
|
|
||||||
@ -51,7 +51,6 @@ class TBHierarchicalFields(DisplayedFields): # {{{
|
|||||||
def commit(self):
|
def commit(self):
|
||||||
if self.changed:
|
if self.changed:
|
||||||
self.db.prefs.set('categories_using_hierarchy', [k for k,v in self.fields if v])
|
self.db.prefs.set('categories_using_hierarchy', [k for k,v in self.fields if v])
|
||||||
# }}}
|
|
||||||
|
|
||||||
|
|
||||||
class TbHierarchyTab(LazyConfigWidgetBase, Ui_Form):
|
class TbHierarchyTab(LazyConfigWidgetBase, Ui_Form):
|
||||||
@ -175,3 +174,4 @@ class TbHierarchyTab(LazyConfigWidgetBase, Ui_Form):
|
|||||||
def commit(self):
|
def commit(self):
|
||||||
self.tb_search_order_commit()
|
self.tb_search_order_commit()
|
||||||
self.tb_hierarchical_cats_model.commit()
|
self.tb_hierarchical_cats_model.commit()
|
||||||
|
return LazyConfigWidgetBase.commit(self)
|
||||||
|
@ -2,17 +2,6 @@
|
|||||||
<ui version="4.0">
|
<ui version="4.0">
|
||||||
<class>Form</class>
|
<class>Form</class>
|
||||||
<widget class="QWidget" name="Form">
|
<widget class="QWidget" name="Form">
|
||||||
<property name="geometry">
|
|
||||||
<rect>
|
|
||||||
<x>0</x>
|
|
||||||
<y>0</y>
|
|
||||||
<width>1035</width>
|
|
||||||
<height>547</height>
|
|
||||||
</rect>
|
|
||||||
</property>
|
|
||||||
<property name="windowTitle">
|
|
||||||
<string>Form</string>
|
|
||||||
</property>
|
|
||||||
<layout class="QGridLayout">
|
<layout class="QGridLayout">
|
||||||
<item row="0" column="0">
|
<item row="0" column="0">
|
||||||
<widget class="QLabel" name="label">
|
<widget class="QLabel" name="label">
|
||||||
|
@ -2,17 +2,6 @@
|
|||||||
<ui version="4.0">
|
<ui version="4.0">
|
||||||
<class>Form</class>
|
<class>Form</class>
|
||||||
<widget class="QWidget" name="Form">
|
<widget class="QWidget" name="Form">
|
||||||
<property name="geometry">
|
|
||||||
<rect>
|
|
||||||
<x>0</x>
|
|
||||||
<y>0</y>
|
|
||||||
<width>1035</width>
|
|
||||||
<height>547</height>
|
|
||||||
</rect>
|
|
||||||
</property>
|
|
||||||
<property name="windowTitle">
|
|
||||||
<string>Form</string>
|
|
||||||
</property>
|
|
||||||
<layout class="QVBoxLayout">
|
<layout class="QVBoxLayout">
|
||||||
<item>
|
<item>
|
||||||
<layout class="QHBoxLayout">
|
<layout class="QHBoxLayout">
|
||||||
|
@ -9,12 +9,12 @@ __docformat__ = 'restructuredtext en'
|
|||||||
from functools import partial
|
from functools import partial
|
||||||
|
|
||||||
from calibre.gui2 import gprefs
|
from calibre.gui2 import gprefs
|
||||||
from calibre.gui2.preferences import ConfigWidgetBase, LazyConfigWidgetBase
|
from calibre.gui2.preferences import LazyConfigWidgetBase
|
||||||
from calibre.gui2.preferences.look_feel_tabs import DisplayedFields, export_layout, import_layout, reset_layout
|
from calibre.gui2.preferences.look_feel_tabs import DisplayedFields, export_layout, import_layout, reset_layout
|
||||||
from calibre.gui2.preferences.look_feel_tabs.tb_partitioning_ui import Ui_Form
|
from calibre.gui2.preferences.look_feel_tabs.tb_partitioning_ui import Ui_Form
|
||||||
|
|
||||||
|
|
||||||
class TBPartitionedFields(DisplayedFields): # {{{
|
class TBPartitionedFields(DisplayedFields):
|
||||||
# The code in this class depends on the fact that the tag browser is
|
# The code in this class depends on the fact that the tag browser is
|
||||||
# initialized before this class is instantiated.
|
# initialized before this class is instantiated.
|
||||||
|
|
||||||
@ -60,7 +60,6 @@ class TBPartitionedFields(DisplayedFields): # {{{
|
|||||||
if self.changed:
|
if self.changed:
|
||||||
# Migrate to a per-library setting
|
# Migrate to a per-library setting
|
||||||
self.db.prefs.set('tag_browser_dont_collapse', [k for k,v in self.fields if not v])
|
self.db.prefs.set('tag_browser_dont_collapse', [k for k,v in self.fields if not v])
|
||||||
# }}}
|
|
||||||
|
|
||||||
|
|
||||||
class TbPartitioningTab(LazyConfigWidgetBase, Ui_Form):
|
class TbPartitioningTab(LazyConfigWidgetBase, Ui_Form):
|
||||||
@ -92,4 +91,7 @@ class TbPartitioningTab(LazyConfigWidgetBase, Ui_Form):
|
|||||||
|
|
||||||
def commit(self):
|
def commit(self):
|
||||||
self.tb_categories_to_part_model.commit()
|
self.tb_categories_to_part_model.commit()
|
||||||
return ConfigWidgetBase.commit(self)
|
return LazyConfigWidgetBase.commit(self)
|
||||||
|
|
||||||
|
def refresh_gui(self, gui):
|
||||||
|
gui.tags_view.reread_collapse_parameters()
|
||||||
|
@ -2,17 +2,6 @@
|
|||||||
<ui version="4.0">
|
<ui version="4.0">
|
||||||
<class>Form</class>
|
<class>Form</class>
|
||||||
<widget class="QWidget" name="Form">
|
<widget class="QWidget" name="Form">
|
||||||
<property name="geometry">
|
|
||||||
<rect>
|
|
||||||
<x>0</x>
|
|
||||||
<y>0</y>
|
|
||||||
<width>1035</width>
|
|
||||||
<height>547</height>
|
|
||||||
</rect>
|
|
||||||
</property>
|
|
||||||
<property name="windowTitle">
|
|
||||||
<string>Form</string>
|
|
||||||
</property>
|
|
||||||
<layout class="QVBoxLayout" name="verticalLayout_4">
|
<layout class="QVBoxLayout" name="verticalLayout_4">
|
||||||
<item>
|
<item>
|
||||||
<layout class="QGridLayout" name="gridLayout_10">
|
<layout class="QGridLayout" name="gridLayout_10">
|
||||||
|
@ -397,7 +397,7 @@ class Preferences(QDialog):
|
|||||||
|
|
||||||
def commit(self, *args):
|
def commit(self, *args):
|
||||||
# Commit the child widgets first in case the main widget uses the information
|
# Commit the child widgets first in case the main widget uses the information
|
||||||
must_restart = bool(self.showing_widget.do_on_child_tabs('commit')) | self.showing_widget.commit()
|
must_restart = bool(self.showing_widget.do_on_child_tabs('commit')) | bool(self.showing_widget.commit())
|
||||||
rc = self.showing_widget.restart_critical
|
rc = self.showing_widget.restart_critical
|
||||||
self.committed = True
|
self.committed = True
|
||||||
do_restart = False
|
do_restart = False
|
||||||
|
Loading…
x
Reference in New Issue
Block a user