mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-09 03:04:10 -04:00
Refactor BookInfo dialog
Make the book information dialog user resizable, with a splitter between the cover and the info panel. Also change the background of the cover panel for books that have been marked using the Temp marker plugin. Fixes #1209057 [[ENHANCEMENTS] Book Information window](https://bugs.launchpad.net/calibre/+bug/1209057)
This commit is contained in:
parent
9f7637778a
commit
ee1142105b
@ -1,31 +1,56 @@
|
||||
#!/usr/bin/env python
|
||||
from __future__ import (unicode_literals, division, absolute_import,
|
||||
print_function)
|
||||
__license__ = 'GPL v3'
|
||||
__copyright__ = '2008, Kovid Goyal kovid@kovidgoyal.net'
|
||||
__docformat__ = 'restructuredtext en'
|
||||
|
||||
|
||||
from PyQt4.Qt import (QCoreApplication, QModelIndex, QTimer, Qt, pyqtSignal,
|
||||
QDialog, QPixmap, QIcon, QSize, QPalette, QShortcut, QKeySequence)
|
||||
from PyQt4.Qt import (
|
||||
QCoreApplication, QModelIndex, QTimer, Qt, pyqtSignal, QWidget,
|
||||
QGridLayout, QDialog, QPixmap, QSize, QPalette, QShortcut, QKeySequence,
|
||||
QSplitter, QVBoxLayout, QCheckBox, QPushButton, QIcon, QBrush)
|
||||
from PyQt4.QtWebKit import QWebView
|
||||
|
||||
from calibre.gui2.dialogs.book_info_ui import Ui_BookInfo
|
||||
from calibre.gui2 import dynamic
|
||||
from calibre.gui2 import gprefs
|
||||
from calibre import fit_image
|
||||
from calibre.gui2.book_details import render_html
|
||||
from calibre.gui2.widgets import CoverView
|
||||
|
||||
class BookInfo(QDialog, Ui_BookInfo):
|
||||
_css = None
|
||||
def css():
|
||||
global _css
|
||||
if _css is None:
|
||||
_css = P('templates/book_details.css', data=True).decode('utf-8')
|
||||
return _css
|
||||
|
||||
class BookInfo(QDialog):
|
||||
|
||||
closed = pyqtSignal(object)
|
||||
|
||||
def __init__(self, parent, view, row, link_delegate):
|
||||
QDialog.__init__(self, parent)
|
||||
Ui_BookInfo.__init__(self)
|
||||
self.setupUi(self)
|
||||
self.normal_brush = QBrush(Qt.white)
|
||||
self.marked_brush = QBrush(Qt.lightGray)
|
||||
self.marked = None
|
||||
self.gui = parent
|
||||
self.splitter = QSplitter(self)
|
||||
self._l = l = QVBoxLayout(self)
|
||||
self.setLayout(l)
|
||||
l.addWidget(self.splitter)
|
||||
|
||||
self.cover = CoverView(self)
|
||||
self.cover.resizeEvent = self.cover_view_resized
|
||||
self.cover.cover_changed.connect(self.cover_changed)
|
||||
self.cover_pixmap = None
|
||||
self.cover.sizeHint = self.details_size_hint
|
||||
self.splitter.addWidget(self.cover)
|
||||
|
||||
self.details = QWebView(self)
|
||||
self.details.sizeHint = self.details_size_hint
|
||||
self.details.page().setLinkDelegationPolicy(self.details.page().DelegateAllLinks)
|
||||
self.details.linkClicked.connect(self.link_clicked)
|
||||
self.css = P('templates/book_details.css', data=True).decode('utf-8')
|
||||
self.css = css()
|
||||
self.link_delegate = link_delegate
|
||||
self.details.setAttribute(Qt.WA_OpaquePaintEvent, False)
|
||||
palette = self.details.palette()
|
||||
@ -33,17 +58,27 @@ class BookInfo(QDialog, Ui_BookInfo):
|
||||
palette.setBrush(QPalette.Base, Qt.transparent)
|
||||
self.details.page().setPalette(palette)
|
||||
|
||||
self.c = QWidget(self)
|
||||
self.c.l = l2 = QGridLayout(self.c)
|
||||
self.c.setLayout(l2)
|
||||
l2.addWidget(self.details, 0, 0, 1, -1)
|
||||
self.splitter.addWidget(self.c)
|
||||
|
||||
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)
|
||||
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)
|
||||
self.next_button = QPushButton(QIcon(I('next.png')), _('&Next'), self)
|
||||
self.next_button.clicked.connect(self.next)
|
||||
l2.addWidget(self.next_button, l2.rowCount() - 1, 1)
|
||||
|
||||
self.view = view
|
||||
self.current_row = None
|
||||
self.fit_cover.setChecked(dynamic.get('book_info_dialog_fit_cover',
|
||||
True))
|
||||
self.refresh(row)
|
||||
self.view.selectionModel().currentChanged.connect(self.slave)
|
||||
self.next_button.clicked.connect(self.next)
|
||||
self.previous_button.clicked.connect(self.previous)
|
||||
self.fit_cover.stateChanged.connect(self.toggle_cover_fit)
|
||||
self.cover.resizeEvent = self.cover_view_resized
|
||||
self.cover.cover_changed.connect(self.cover_changed)
|
||||
self.ns = QShortcut(QKeySequence('Alt+Right'), self)
|
||||
self.ns.activated.connect(self.next)
|
||||
self.ps = QShortcut(QKeySequence('Alt+Left'), self)
|
||||
@ -53,15 +88,25 @@ class BookInfo(QDialog, Ui_BookInfo):
|
||||
self.previous_button.setToolTip(_('Previous [%s]')%
|
||||
unicode(self.ps.key().toString(QKeySequence.NativeText)))
|
||||
|
||||
desktop = QCoreApplication.instance().desktop()
|
||||
screen_height = desktop.availableGeometry().height() - 100
|
||||
self.resize(self.size().width(), screen_height)
|
||||
geom = QCoreApplication.instance().desktop().availableGeometry(self)
|
||||
screen_height = geom.height() - 100
|
||||
screen_width = geom.width() - 100
|
||||
self.resize(max(int(screen_width/2), 700), screen_height)
|
||||
saved_layout = gprefs.get('book_info_dialog_layout', None)
|
||||
if saved_layout is not None:
|
||||
try:
|
||||
self.restoreGeometry(saved_layout[0])
|
||||
self.splitter.restoreState(saved_layout[1])
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
def link_clicked(self, qurl):
|
||||
link = unicode(qurl.toString())
|
||||
self.link_delegate(link)
|
||||
|
||||
def done(self, r):
|
||||
saved_layout = (bytearray(self.saveGeometry()), bytearray(self.splitter.saveState()))
|
||||
gprefs.set('book_info_dialog_layout', saved_layout)
|
||||
ret = QDialog.done(self, r)
|
||||
self.view.selectionModel().currentChanged.disconnect(self.slave)
|
||||
self.view = self.link_delegate = self.gui = None
|
||||
@ -86,7 +131,7 @@ class BookInfo(QDialog, Ui_BookInfo):
|
||||
return QSize(350, 550)
|
||||
|
||||
def toggle_cover_fit(self, state):
|
||||
dynamic.set('book_info_dialog_fit_cover', self.fit_cover.isChecked())
|
||||
gprefs.set('book_info_dialog_fit_cover', self.fit_cover.isChecked())
|
||||
self.resize_cover()
|
||||
|
||||
def cover_view_resized(self, event):
|
||||
@ -121,7 +166,6 @@ class BookInfo(QDialog, Ui_BookInfo):
|
||||
def resize_cover(self):
|
||||
if self.cover_pixmap is None:
|
||||
return
|
||||
self.setWindowIcon(QIcon(self.cover_pixmap))
|
||||
pixmap = self.cover_pixmap
|
||||
if self.fit_cover.isChecked():
|
||||
scaled, new_width, new_height = fit_image(pixmap.width(),
|
||||
@ -131,9 +175,18 @@ class BookInfo(QDialog, Ui_BookInfo):
|
||||
pixmap = pixmap.scaled(new_width, new_height,
|
||||
Qt.KeepAspectRatio, Qt.SmoothTransformation)
|
||||
self.cover.set_pixmap(pixmap)
|
||||
sz = pixmap.size()
|
||||
self.cover.setToolTip(_('Cover size: %(width)d x %(height)d')%dict(
|
||||
width=sz.width(), height=sz.height()))
|
||||
self.update_cover_tooltip()
|
||||
|
||||
def update_cover_tooltip(self):
|
||||
tt = ''
|
||||
if self.marked:
|
||||
tt = _('This book is marked') if self.marked in {True, 'true'} else _(
|
||||
'This book is marked as: %s') % self.marked
|
||||
tt += '\n\n'
|
||||
if self.cover_pixmap is not None:
|
||||
sz = self.cover_pixmap.size()
|
||||
tt += _('Cover size: %(width)d x %(height)d')%dict(width=sz.width(), height=sz.height())
|
||||
self.cover.setToolTip(tt)
|
||||
|
||||
def refresh(self, row):
|
||||
if isinstance(row, QModelIndex):
|
||||
@ -150,9 +203,10 @@ class BookInfo(QDialog, Ui_BookInfo):
|
||||
self.next_button.setEnabled(False if row == self.view.model().rowCount(QModelIndex())-1 else True)
|
||||
self.current_row = row
|
||||
self.setWindowTitle(mi.title)
|
||||
self.title.setText('<b>'+mi.title)
|
||||
mi.title = _('Unknown')
|
||||
self.cover_pixmap = QPixmap.fromImage(mi.cover_data[1])
|
||||
self.resize_cover()
|
||||
html = render_html(mi, self.css, True, self, all_fields=True)
|
||||
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()
|
||||
|
@ -1,106 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>BookInfo</class>
|
||||
<widget class="QDialog" name="BookInfo">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>917</width>
|
||||
<height>492</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Dialog</string>
|
||||
</property>
|
||||
<property name="windowIcon">
|
||||
<iconset resource="../../../../resources/images.qrc">
|
||||
<normaloff>:/images/metadata.png</normaloff>:/images/metadata.png</iconset>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<item row="0" column="0" colspan="2">
|
||||
<widget class="QLabel" name="title">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Maximum">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="font">
|
||||
<font>
|
||||
<weight>75</weight>
|
||||
<bold>true</bold>
|
||||
</font>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>TextLabel</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0" rowspan="3">
|
||||
<widget class="CoverView" name="cover"/>
|
||||
</item>
|
||||
<item row="3" column="1">
|
||||
<widget class="QCheckBox" name="fit_cover">
|
||||
<property name="text">
|
||||
<string>Fit &cover within view</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="1">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<item>
|
||||
<widget class="QPushButton" name="previous_button">
|
||||
<property name="text">
|
||||
<string>&Previous</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset resource="../../../../resources/images.qrc">
|
||||
<normaloff>:/images/previous.png</normaloff>:/images/previous.png</iconset>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="next_button">
|
||||
<property name="text">
|
||||
<string>&Next</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset resource="../../../../resources/images.qrc">
|
||||
<normaloff>:/images/next.png</normaloff>:/images/next.png</iconset>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<widget class="QWebView" name="details">
|
||||
<property name="url">
|
||||
<url>
|
||||
<string>about:blank</string>
|
||||
</url>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<customwidgets>
|
||||
<customwidget>
|
||||
<class>QWebView</class>
|
||||
<extends>QWidget</extends>
|
||||
<header>QtWebKit/QWebView</header>
|
||||
</customwidget>
|
||||
<customwidget>
|
||||
<class>CoverView</class>
|
||||
<extends>QGraphicsView</extends>
|
||||
<header>calibre/gui2/widgets.h</header>
|
||||
</customwidget>
|
||||
</customwidgets>
|
||||
<resources>
|
||||
<include location="../../../../resources/images.qrc"/>
|
||||
</resources>
|
||||
<connections/>
|
||||
</ui>
|
@ -463,6 +463,10 @@ class BooksModel(QAbstractTableModel): # {{{
|
||||
mi.id = self.db.id(idx)
|
||||
mi.field_metadata = self.db.field_metadata
|
||||
mi.path = self.db.abspath(idx, create_dirs=False)
|
||||
try:
|
||||
mi.marked = self.db.data.get_marked(idx, index_is_id=False)
|
||||
except:
|
||||
mi.marked = None
|
||||
return mi
|
||||
|
||||
def current_changed(self, current, previous, emit_signal=True):
|
||||
|
@ -916,6 +916,10 @@ class ResultCache(SearchQueryParser): # {{{
|
||||
except:
|
||||
pass
|
||||
|
||||
def get_marked(self, idx, index_is_id=True, default_value=None):
|
||||
id_ = idx if index_is_id else self[idx][0]
|
||||
return self.marked_ids_dict.get(id_, default_value)
|
||||
|
||||
# }}}
|
||||
|
||||
def remove(self, id):
|
||||
|
Loading…
x
Reference in New Issue
Block a user