mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-09 03:04:10 -04:00
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:
parent
9daf8f7f7e
commit
a6e8d0eb71
@ -471,6 +471,7 @@ class DB(object):
|
|||||||
('uuid', False), ('comments', True), ('id', False), ('pubdate', False),
|
('uuid', False), ('comments', True), ('id', False), ('pubdate', False),
|
||||||
('last_modified', False), ('size', False), ('languages', 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['qv_display_fields'] = [('title', True), ('authors', True), ('series', True)]
|
||||||
defs['virtual_libraries'] = {}
|
defs['virtual_libraries'] = {}
|
||||||
defs['virtual_lib_on_startup'] = defs['cs_virtual_lib_on_startup'] = ''
|
defs['virtual_lib_on_startup'] = defs['cs_virtual_lib_on_startup'] = ''
|
||||||
|
@ -87,9 +87,14 @@ def init_manage_action(ac, field, value):
|
|||||||
return ac
|
return ac
|
||||||
|
|
||||||
|
|
||||||
def render_html(mi, css, vertical, widget, all_fields=False, render_data_func=None): # {{{
|
def render_html(mi, css, vertical, widget, all_fields=False, render_data_func=None, pref_name='book_display_fields'): # {{{
|
||||||
table, comment_fields = (render_data_func or render_data)(mi, all_fields=all_fields,
|
func = render_data_func or render_data
|
||||||
use_roman_numbers=config['use_roman_numerals_for_series_number'])
|
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):
|
def color_to_string(col):
|
||||||
ans = '#000000'
|
ans = '#000000'
|
||||||
@ -145,29 +150,27 @@ def render_html(mi, css, vertical, widget, all_fields=False, render_data_func=No
|
|||||||
return ans
|
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
|
from calibre.gui2.ui import get_gui
|
||||||
db = get_gui().current_db
|
db = get_gui().current_db
|
||||||
if use_defaults:
|
if use_defaults:
|
||||||
src = db.prefs.defaults
|
src = db.prefs.defaults
|
||||||
else:
|
else:
|
||||||
old_val = gprefs.get('book_display_fields', None)
|
old_val = gprefs.get(pref_name, None)
|
||||||
if old_val is not None and not db.prefs.has_setting(
|
if old_val is not None and not db.prefs.has_setting(pref_name):
|
||||||
'book_display_fields'):
|
|
||||||
src = gprefs
|
src = gprefs
|
||||||
else:
|
else:
|
||||||
src = db.prefs
|
src = db.prefs
|
||||||
fieldlist = list(src['book_display_fields'])
|
fieldlist = list(src[pref_name])
|
||||||
names = frozenset([x[0] for x in fieldlist])
|
names = frozenset(x[0] for x in fieldlist)
|
||||||
for field in fm.displayable_field_keys():
|
|
||||||
if field not in names:
|
|
||||||
fieldlist.append((field, True))
|
|
||||||
available = frozenset(fm.displayable_field_keys())
|
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]
|
return [(f, d) for f, d in fieldlist if f in available]
|
||||||
|
|
||||||
|
|
||||||
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'):
|
||||||
field_list = get_field_list(getattr(mi, 'field_metadata', field_metadata))
|
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]
|
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(),
|
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())
|
rating_font=rating_font(), default_author_link=default_author_link())
|
||||||
|
@ -1,21 +1,71 @@
|
|||||||
#!/usr/bin/env python2
|
#!/usr/bin/env python2
|
||||||
from __future__ import (unicode_literals, division, absolute_import,
|
# License: GPLv3 Copyright: 2008, Kovid Goyal <kovid at kovidgoyal.net>
|
||||||
print_function)
|
from __future__ import absolute_import, division, print_function, unicode_literals
|
||||||
__license__ = 'GPL v3'
|
|
||||||
__copyright__ = '2008, Kovid Goyal kovid@kovidgoyal.net'
|
|
||||||
__docformat__ = 'restructuredtext en'
|
|
||||||
|
|
||||||
|
from functools import partial
|
||||||
|
|
||||||
from PyQt5.Qt import (
|
from PyQt5.Qt import (
|
||||||
QCoreApplication, QModelIndex, QTimer, Qt, pyqtSignal, QWidget,
|
QBrush, QCheckBox, QCoreApplication, QDialog, QGridLayout, QHBoxLayout, QIcon,
|
||||||
QGridLayout, QDialog, QPixmap, QSize, QPalette, QShortcut, QKeySequence,
|
QKeySequence, QLabel, QListView, QModelIndex, QPalette, QPixmap, QPushButton,
|
||||||
QSplitter, QVBoxLayout, QCheckBox, QPushButton, QIcon, QBrush)
|
QShortcut, QSize, QSplitter, Qt, QTimer, QToolButton, QVBoxLayout, QWidget,
|
||||||
|
pyqtSignal
|
||||||
|
)
|
||||||
from PyQt5.QtWebKitWidgets import QWebView
|
from PyQt5.QtWebKitWidgets import QWebView
|
||||||
|
|
||||||
from calibre.gui2 import gprefs, NO_URL_FORMATTING
|
|
||||||
from calibre import fit_image
|
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.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):
|
class Details(QWebView):
|
||||||
@ -74,7 +124,11 @@ class BookInfo(QDialog):
|
|||||||
|
|
||||||
self.fit_cover = QCheckBox(_('Fit &cover within view'), self)
|
self.fit_cover = QCheckBox(_('Fit &cover within view'), self)
|
||||||
self.fit_cover.setChecked(gprefs.get('book_info_dialog_fit_cover', True))
|
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 = QPushButton(QIcon(I('previous.png')), _('&Previous'), self)
|
||||||
self.previous_button.clicked.connect(self.previous)
|
self.previous_button.clicked.connect(self.previous)
|
||||||
l2.addWidget(self.previous_button, l2.rowCount(), 0)
|
l2.addWidget(self.previous_button, l2.rowCount(), 0)
|
||||||
@ -108,6 +162,14 @@ class BookInfo(QDialog):
|
|||||||
except Exception:
|
except Exception:
|
||||||
pass
|
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):
|
def link_clicked(self, qurl):
|
||||||
link = unicode(qurl.toString(NO_URL_FORMATTING))
|
link = unicode(qurl.toString(NO_URL_FORMATTING))
|
||||||
self.link_delegate(link)
|
self.link_delegate(link)
|
||||||
@ -212,8 +274,20 @@ class BookInfo(QDialog):
|
|||||||
dpr = self.devicePixelRatio()
|
dpr = self.devicePixelRatio()
|
||||||
self.cover_pixmap.setDevicePixelRatio(dpr)
|
self.cover_pixmap.setDevicePixelRatio(dpr)
|
||||||
self.resize_cover()
|
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.details.setHtml(html)
|
||||||
self.marked = mi.marked
|
self.marked = mi.marked
|
||||||
self.cover.setBackgroundBrush(self.marked_brush if mi.marked else self.normal_brush)
|
self.cover.setBackgroundBrush(self.marked_brush if mi.marked else self.normal_brush)
|
||||||
self.update_cover_tooltip()
|
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
|
||||||
|
@ -217,18 +217,20 @@ class IdLinksEditor(Dialog):
|
|||||||
|
|
||||||
class DisplayedFields(QAbstractListModel): # {{{
|
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)
|
QAbstractListModel.__init__(self, parent)
|
||||||
|
|
||||||
self.fields = []
|
self.fields = []
|
||||||
self.db = db
|
self.db = db
|
||||||
self.changed = False
|
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):
|
def initialize(self, use_defaults=False):
|
||||||
self.beginResetModel()
|
self.beginResetModel()
|
||||||
self.fields = [[x[0], x[1]] for x in
|
self.fields = [[x[0], x[1]] for x in self.get_field_list(use_defaults=use_defaults)]
|
||||||
get_field_list(self.db.field_metadata,
|
|
||||||
use_defaults=use_defaults)]
|
|
||||||
self.endResetModel()
|
self.endResetModel()
|
||||||
self.changed = True
|
self.changed = True
|
||||||
|
|
||||||
@ -273,7 +275,7 @@ class DisplayedFields(QAbstractListModel): # {{{
|
|||||||
|
|
||||||
def commit(self):
|
def commit(self):
|
||||||
if self.changed:
|
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):
|
def move(self, idx, delta):
|
||||||
row = idx.row() + delta
|
row = idx.row() + delta
|
||||||
@ -287,6 +289,26 @@ class DisplayedFields(QAbstractListModel): # {{{
|
|||||||
self.changed = True
|
self.changed = True
|
||||||
return idx
|
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.field_display_order)
|
||||||
self.display_model.dataChanged.connect(self.changed_signal)
|
self.display_model.dataChanged.connect(self.changed_signal)
|
||||||
self.field_display_order.setModel(self.display_model)
|
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.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.field_display_order, self.display_model))
|
||||||
|
|
||||||
self.qv_display_model = QVDisplayedFields(self.gui.current_db,
|
self.qv_display_model = QVDisplayedFields(self.gui.current_db,
|
||||||
self.qv_display_order)
|
self.qv_display_order)
|
||||||
self.qv_display_model.dataChanged.connect(self.changed_signal)
|
self.qv_display_model.dataChanged.connect(self.changed_signal)
|
||||||
self.qv_display_order.setModel(self.qv_display_model)
|
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_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.qv_display_order, self.qv_display_model))
|
||||||
|
|
||||||
self.edit_rules = EditRules(self.tabWidget)
|
self.edit_rules = EditRules(self.tabWidget)
|
||||||
@ -702,24 +724,6 @@ class ConfigWidget(ConfigWidgetBase, Ui_Form):
|
|||||||
self.font_display.setText(name +
|
self.font_display.setText(name +
|
||||||
' [%dpt]'%fi.pointSize())
|
' [%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):
|
def change_font(self, *args):
|
||||||
fd = QFontDialog(self.build_font_obj(), self)
|
fd = QFontDialog(self.build_font_obj(), self)
|
||||||
if fd.exec_() == fd.Accepted:
|
if fd.exec_() == fd.Accepted:
|
||||||
|
@ -87,11 +87,8 @@ class Listener(Thread): # {{{
|
|||||||
# }}}
|
# }}}
|
||||||
|
|
||||||
|
|
||||||
_gui = None
|
|
||||||
|
|
||||||
|
|
||||||
def get_gui():
|
def get_gui():
|
||||||
return _gui
|
return getattr(get_gui, 'ans', None)
|
||||||
|
|
||||||
|
|
||||||
def add_quick_start_guide(library_view, refresh_cover_browser=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
|
shutting_down = False
|
||||||
|
|
||||||
def __init__(self, opts, parent=None, gui_debug=None):
|
def __init__(self, opts, parent=None, gui_debug=None):
|
||||||
global _gui
|
|
||||||
MainWindow.__init__(self, opts, parent=parent, disable_automatic_gc=True)
|
MainWindow.__init__(self, opts, parent=parent, disable_automatic_gc=True)
|
||||||
self.setWindowIcon(QApplication.instance().windowIcon())
|
self.setWindowIcon(QApplication.instance().windowIcon())
|
||||||
self.jobs_pointer = Pointer(self)
|
self.jobs_pointer = Pointer(self)
|
||||||
@ -147,7 +143,7 @@ class Main(MainWindow, MainWindowMixin, DeviceMixin, EmailMixin, # {{{
|
|||||||
self.proceed_question = ProceedQuestion(self)
|
self.proceed_question = ProceedQuestion(self)
|
||||||
self.job_error_dialog = JobError(self)
|
self.job_error_dialog = JobError(self)
|
||||||
self.keyboard = Manager(self)
|
self.keyboard = Manager(self)
|
||||||
_gui = self
|
get_gui.ans = self
|
||||||
self.opts = opts
|
self.opts = opts
|
||||||
self.device_connected = None
|
self.device_connected = None
|
||||||
self.gui_debug = gui_debug
|
self.gui_debug = gui_debug
|
||||||
|
@ -93,7 +93,7 @@ class Metadata(QWebView): # {{{
|
|||||||
from calibre.gui2.book_details import render_html, css
|
from calibre.gui2.book_details import render_html, css
|
||||||
from calibre.ebooks.metadata.book.render import mi_to_html
|
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(
|
return mi_to_html(
|
||||||
mi, use_roman_numbers=use_roman_numbers, rating_font=rating_font(), rtl=is_rtl(),
|
mi, use_roman_numbers=use_roman_numbers, rating_font=rating_font(), rtl=is_rtl(),
|
||||||
default_author_link=default_author_link()
|
default_author_link=default_author_link()
|
||||||
|
Loading…
x
Reference in New Issue
Block a user