Allow configuring the metadata fields displayed in the popup book details window. To configure, simply click the 'Configure' link at the bottom of the window.

This commit is contained in:
Kovid Goyal 2017-11-05 15:04:57 +05:30
parent 9daf8f7f7e
commit a6e8d0eb71
No known key found for this signature in database
GPG Key ID: 06BC317B515ACE7C
6 changed files with 138 additions and 60 deletions

View File

@ -471,6 +471,7 @@ class DB(object):
('uuid', False), ('comments', True), ('id', False), ('pubdate', False),
('last_modified', False), ('size', False), ('languages', False),
]
defs['popup_book_display_fields'] = [('title', True)] + [(f[0], True) for f in defs['book_display_fields'] if f[0] != 'title']
defs['qv_display_fields'] = [('title', True), ('authors', True), ('series', True)]
defs['virtual_libraries'] = {}
defs['virtual_lib_on_startup'] = defs['cs_virtual_lib_on_startup'] = ''

View File

@ -87,9 +87,14 @@ def init_manage_action(ac, field, value):
return ac
def render_html(mi, css, vertical, widget, all_fields=False, render_data_func=None): # {{{
table, comment_fields = (render_data_func or render_data)(mi, all_fields=all_fields,
use_roman_numbers=config['use_roman_numerals_for_series_number'])
def render_html(mi, css, vertical, widget, all_fields=False, render_data_func=None, pref_name='book_display_fields'): # {{{
func = render_data_func or render_data
try:
table, comment_fields = func(mi, all_fields=all_fields,
use_roman_numbers=config['use_roman_numerals_for_series_number'], pref_name=pref_name)
except TypeError:
table, comment_fields = func(mi, all_fields=all_fields,
use_roman_numbers=config['use_roman_numerals_for_series_number'])
def color_to_string(col):
ans = '#000000'
@ -145,29 +150,27 @@ def render_html(mi, css, vertical, widget, all_fields=False, render_data_func=No
return ans
def get_field_list(fm, use_defaults=False):
def get_field_list(fm, use_defaults=False, pref_name='book_display_fields'):
from calibre.gui2.ui import get_gui
db = get_gui().current_db
if use_defaults:
src = db.prefs.defaults
else:
old_val = gprefs.get('book_display_fields', None)
if old_val is not None and not db.prefs.has_setting(
'book_display_fields'):
old_val = gprefs.get(pref_name, None)
if old_val is not None and not db.prefs.has_setting(pref_name):
src = gprefs
else:
src = db.prefs
fieldlist = list(src['book_display_fields'])
names = frozenset([x[0] for x in fieldlist])
for field in fm.displayable_field_keys():
if field not in names:
fieldlist.append((field, True))
fieldlist = list(src[pref_name])
names = frozenset(x[0] for x in fieldlist)
available = frozenset(fm.displayable_field_keys())
for field in available - names:
fieldlist.append((field, True))
return [(f, d) for f, d in fieldlist if f in available]
def render_data(mi, use_roman_numbers=True, all_fields=False):
field_list = get_field_list(getattr(mi, 'field_metadata', field_metadata))
def render_data(mi, use_roman_numbers=True, all_fields=False, pref_name='book_display_fields'):
field_list = get_field_list(getattr(mi, 'field_metadata', field_metadata), pref_name=pref_name)
field_list = [(x, all_fields or display) for x, display in field_list]
return mi_to_html(mi, field_list=field_list, use_roman_numbers=use_roman_numbers, rtl=is_rtl(),
rating_font=rating_font(), default_author_link=default_author_link())

View File

@ -1,21 +1,71 @@
#!/usr/bin/env python2
from __future__ import (unicode_literals, division, absolute_import,
print_function)
__license__ = 'GPL v3'
__copyright__ = '2008, Kovid Goyal kovid@kovidgoyal.net'
__docformat__ = 'restructuredtext en'
# License: GPLv3 Copyright: 2008, Kovid Goyal <kovid at kovidgoyal.net>
from __future__ import absolute_import, division, print_function, unicode_literals
from functools import partial
from PyQt5.Qt import (
QCoreApplication, QModelIndex, QTimer, Qt, pyqtSignal, QWidget,
QGridLayout, QDialog, QPixmap, QSize, QPalette, QShortcut, QKeySequence,
QSplitter, QVBoxLayout, QCheckBox, QPushButton, QIcon, QBrush)
QBrush, QCheckBox, QCoreApplication, QDialog, QGridLayout, QHBoxLayout, QIcon,
QKeySequence, QLabel, QListView, QModelIndex, QPalette, QPixmap, QPushButton,
QShortcut, QSize, QSplitter, Qt, QTimer, QToolButton, QVBoxLayout, QWidget,
pyqtSignal
)
from PyQt5.QtWebKitWidgets import QWebView
from calibre.gui2 import gprefs, NO_URL_FORMATTING
from calibre import fit_image
from calibre.gui2.book_details import render_html, details_context_menu_event, css
from calibre.gui2 import NO_URL_FORMATTING, gprefs
from calibre.gui2.book_details import css, details_context_menu_event, render_html
from calibre.gui2.ui import get_gui
from calibre.gui2.widgets import CoverView
from calibre.gui2.widgets2 import Dialog
class Configure(Dialog):
def __init__(self, db, parent=None):
self.db = db
Dialog.__init__(self, _('Configure the book details window'), 'book-details-popup-conf', parent)
def setup_ui(self):
from calibre.gui2.preferences.look_feel import DisplayedFields, move_field_up, move_field_down
self.l = QVBoxLayout(self)
self.field_display_order = fdo = QListView(self)
self.model = DisplayedFields(self.db, fdo, pref_name='popup_book_display_fields')
self.model.initialize()
fdo.setModel(self.model)
fdo.setAlternatingRowColors(True)
del self.db
self.l.addWidget(QLabel('Select displayed metadata'))
h = QHBoxLayout()
h.addWidget(fdo)
v = QVBoxLayout()
self.mub = b = QToolButton(self)
b.clicked.connect(partial(move_field_up, fdo, self.model))
b.setIcon(QIcon(I('arrow-up.png')))
b.setToolTip(_('Move the selected field up'))
v.addWidget(b), v.addStretch(10)
self.mud = b = QToolButton(self)
b.setIcon(QIcon(I('arrow-down.png')))
b.setToolTip(_('Move the selected field down'))
b.clicked.connect(partial(move_field_down, fdo, self.model))
v.addWidget(b)
h.addLayout(v)
self.l.addLayout(h)
self.l.addWidget(QLabel('<p>' + _(
'Note that <b>comments</b> will always be displayed at the end, regardless of the order you assign here')))
b = self.bb.addButton(_('Restore &defaults'), self.bb.ActionRole)
b.clicked.connect(self.restore_defaults)
self.l.addWidget(self.bb)
self.setMinimumHeight(500)
def restore_defaults(self):
self.model.initialize(use_defaults=True)
def accept(self):
self.model.commit()
return Dialog.accept(self)
class Details(QWebView):
@ -74,7 +124,11 @@ class BookInfo(QDialog):
self.fit_cover = QCheckBox(_('Fit &cover within view'), self)
self.fit_cover.setChecked(gprefs.get('book_info_dialog_fit_cover', True))
l2.addWidget(self.fit_cover, l2.rowCount(), 0, 1, -1)
l2.addWidget(self.fit_cover, l2.rowCount(), 0, 1, 1)
self.clabel = QLabel('<div style="text-align: right"><a href="calibre:conf" title="{}" style="text-decoration: none">{}</a>'.format(
_('Configure this view'), _('Configure')))
self.clabel.linkActivated.connect(self.configure)
l2.addWidget(self.clabel, l2.rowCount() - 1, 1, 1, 1)
self.previous_button = QPushButton(QIcon(I('previous.png')), _('&Previous'), self)
self.previous_button.clicked.connect(self.previous)
l2.addWidget(self.previous_button, l2.rowCount(), 0)
@ -108,6 +162,14 @@ class BookInfo(QDialog):
except Exception:
pass
def configure(self):
d = Configure(get_gui().current_db, self)
if d.exec_() == d.Accepted:
if self.current_row is not None:
mi = self.view.model().get_book_display_info(self.current_row)
if mi is not None:
self.refresh(self.current_row, mi=mi)
def link_clicked(self, qurl):
link = unicode(qurl.toString(NO_URL_FORMATTING))
self.link_delegate(link)
@ -212,8 +274,20 @@ class BookInfo(QDialog):
dpr = self.devicePixelRatio()
self.cover_pixmap.setDevicePixelRatio(dpr)
self.resize_cover()
html = render_html(mi, self.css, True, self, all_fields=True)
html = render_html(mi, self.css, True, self, pref_name='popup_book_display_fields')
self.details.setHtml(html)
self.marked = mi.marked
self.cover.setBackgroundBrush(self.marked_brush if mi.marked else self.normal_brush)
self.update_cover_tooltip()
if __name__ == '__main__':
from calibre.gui2 import Application
from calibre.library import db
app = Application([])
app.current_db = db()
get_gui.ans = app
d = Configure(app.current_db)
d.exec_()
del d
del app

View File

@ -217,18 +217,20 @@ class IdLinksEditor(Dialog):
class DisplayedFields(QAbstractListModel): # {{{
def __init__(self, db, parent=None):
def __init__(self, db, parent=None, pref_name=None):
self.pref_name = pref_name or 'book_display_fields'
QAbstractListModel.__init__(self, parent)
self.fields = []
self.db = db
self.changed = False
def get_field_list(self, use_defaults=False):
return get_field_list(self.db.field_metadata, use_defaults=use_defaults, pref_name=self.pref_name)
def initialize(self, use_defaults=False):
self.beginResetModel()
self.fields = [[x[0], x[1]] for x in
get_field_list(self.db.field_metadata,
use_defaults=use_defaults)]
self.fields = [[x[0], x[1]] for x in self.get_field_list(use_defaults=use_defaults)]
self.endResetModel()
self.changed = True
@ -273,7 +275,7 @@ class DisplayedFields(QAbstractListModel): # {{{
def commit(self):
if self.changed:
self.db.new_api.set_pref('book_display_fields', self.fields)
self.db.new_api.set_pref(self.pref_name, self.fields)
def move(self, idx, delta):
row = idx.row() + delta
@ -287,6 +289,26 @@ class DisplayedFields(QAbstractListModel): # {{{
self.changed = True
return idx
def move_field_up(widget, model):
idx = widget.currentIndex()
if idx.isValid():
idx = model.move(idx, -1)
if idx is not None:
sm = widget.selectionModel()
sm.select(idx, sm.ClearAndSelect)
widget.setCurrentIndex(idx)
def move_field_down(widget, model):
idx = widget.currentIndex()
if idx.isValid():
idx = model.move(idx, 1)
if idx is not None:
sm = widget.selectionModel()
sm.select(idx, sm.ClearAndSelect)
widget.setCurrentIndex(idx)
# }}}
@ -478,18 +500,18 @@ class ConfigWidget(ConfigWidgetBase, Ui_Form):
self.field_display_order)
self.display_model.dataChanged.connect(self.changed_signal)
self.field_display_order.setModel(self.display_model)
self.df_up_button.clicked.connect(partial(self.move_field_up,
self.df_up_button.clicked.connect(partial(move_field_up,
self.field_display_order, self.display_model))
self.df_down_button.clicked.connect(partial(self.move_field_down,
self.df_down_button.clicked.connect(partial(move_field_down,
self.field_display_order, self.display_model))
self.qv_display_model = QVDisplayedFields(self.gui.current_db,
self.qv_display_order)
self.qv_display_model.dataChanged.connect(self.changed_signal)
self.qv_display_order.setModel(self.qv_display_model)
self.qv_up_button.clicked.connect(partial(self.move_field_up,
self.qv_up_button.clicked.connect(partial(move_field_up,
self.qv_display_order, self.qv_display_model))
self.qv_down_button.clicked.connect(partial(self.move_field_down,
self.qv_down_button.clicked.connect(partial(move_field_down,
self.qv_display_order, self.qv_display_model))
self.edit_rules = EditRules(self.tabWidget)
@ -702,24 +724,6 @@ class ConfigWidget(ConfigWidgetBase, Ui_Form):
self.font_display.setText(name +
' [%dpt]'%fi.pointSize())
def move_field_up(self, widget, model):
idx = widget.currentIndex()
if idx.isValid():
idx = model.move(idx, -1)
if idx is not None:
sm = widget.selectionModel()
sm.select(idx, sm.ClearAndSelect)
widget.setCurrentIndex(idx)
def move_field_down(self, widget, model):
idx = widget.currentIndex()
if idx.isValid():
idx = model.move(idx, 1)
if idx is not None:
sm = widget.selectionModel()
sm.select(idx, sm.ClearAndSelect)
widget.setCurrentIndex(idx)
def change_font(self, *args):
fd = QFontDialog(self.build_font_obj(), self)
if fd.exec_() == fd.Accepted:

View File

@ -87,11 +87,8 @@ class Listener(Thread): # {{{
# }}}
_gui = None
def get_gui():
return _gui
return getattr(get_gui, 'ans', None)
def add_quick_start_guide(library_view, refresh_cover_browser=None):
@ -138,7 +135,6 @@ class Main(MainWindow, MainWindowMixin, DeviceMixin, EmailMixin, # {{{
shutting_down = False
def __init__(self, opts, parent=None, gui_debug=None):
global _gui
MainWindow.__init__(self, opts, parent=parent, disable_automatic_gc=True)
self.setWindowIcon(QApplication.instance().windowIcon())
self.jobs_pointer = Pointer(self)
@ -147,7 +143,7 @@ class Main(MainWindow, MainWindowMixin, DeviceMixin, EmailMixin, # {{{
self.proceed_question = ProceedQuestion(self)
self.job_error_dialog = JobError(self)
self.keyboard = Manager(self)
_gui = self
get_gui.ans = self
self.opts = opts
self.device_connected = None
self.gui_debug = gui_debug

View File

@ -93,7 +93,7 @@ class Metadata(QWebView): # {{{
from calibre.gui2.book_details import render_html, css
from calibre.ebooks.metadata.book.render import mi_to_html
def render_data(mi, use_roman_numbers=True, all_fields=False):
def render_data(mi, use_roman_numbers=True, all_fields=False, pref_name='book_display_fields'):
return mi_to_html(
mi, use_roman_numbers=use_roman_numbers, rating_font=rating_font(), rtl=is_rtl(),
default_author_link=default_author_link()