diff --git a/src/calibre/gui2/dialogs/book_info.py b/src/calibre/gui2/dialogs/book_info.py
index 4da897920c..523974e4f2 100644
--- a/src/calibre/gui2/dialogs/book_info.py
+++ b/src/calibre/gui2/dialogs/book_info.py
@@ -6,7 +6,7 @@ __docformat__ = 'restructuredtext en'
import textwrap, os, re
from PyQt4.Qt import QCoreApplication, SIGNAL, QModelIndex, QTimer, Qt, \
- QDialog, QPixmap, QGraphicsScene, QIcon, QSize
+ QDialog, QPixmap, QIcon, QSize
from calibre.gui2.dialogs.book_info_ui import Ui_BookInfo
from calibre.gui2 import dynamic, open_local_file, open_url
@@ -14,12 +14,14 @@ from calibre import fit_image
from calibre.library.comments import comments_to_html
from calibre.utils.icu import sort_key
+
class BookInfo(QDialog, Ui_BookInfo):
def __init__(self, parent, view, row, view_func):
QDialog.__init__(self, parent)
Ui_BookInfo.__init__(self)
self.setupUi(self)
+ self.gui = parent
self.cover_pixmap = None
self.comments.sizeHint = self.comments_size_hint
self.comments.page().setLinkDelegationPolicy(self.comments.page().DelegateAllLinks)
@@ -38,11 +40,22 @@ class BookInfo(QDialog, Ui_BookInfo):
self.connect(self.text, SIGNAL('linkActivated(QString)'), self.open_book_path)
self.fit_cover.stateChanged.connect(self.toggle_cover_fit)
self.cover.resizeEvent = self.cover_view_resized
+ self.cover.cover_changed.connect(self.cover_changed)
desktop = QCoreApplication.instance().desktop()
screen_height = desktop.availableGeometry().height() - 100
self.resize(self.size().width(), screen_height)
+ def cover_changed(self, data):
+ if self.current_row is not None:
+ id_ = self.view.model().id(self.current_row)
+ self.view.model().db.set_cover(id_, data)
+ if self.gui.cover_flow:
+ self.gui.cover_flow.dataChanged()
+ ci = self.view.currentIndex()
+ if ci.isValid():
+ self.view.model().current_changed(ci, ci)
+
def link_clicked(self, url):
open_url(url)
@@ -83,7 +96,6 @@ class BookInfo(QDialog, Ui_BookInfo):
if self.cover_pixmap is None:
return
self.setWindowIcon(QIcon(self.cover_pixmap))
- self.scene = QGraphicsScene()
pixmap = self.cover_pixmap
if self.fit_cover.isChecked():
scaled, new_width, new_height = fit_image(pixmap.width(),
@@ -92,8 +104,7 @@ class BookInfo(QDialog, Ui_BookInfo):
if scaled:
pixmap = pixmap.scaled(new_width, new_height,
Qt.KeepAspectRatio, Qt.SmoothTransformation)
- self.scene.addPixmap(pixmap)
- self.cover.setScene(self.scene)
+ self.cover.set_pixmap(pixmap)
def refresh(self, row):
if isinstance(row, QModelIndex):
diff --git a/src/calibre/gui2/dialogs/book_info.ui b/src/calibre/gui2/dialogs/book_info.ui
index 2902a2c917..412126a610 100644
--- a/src/calibre/gui2/dialogs/book_info.ui
+++ b/src/calibre/gui2/dialogs/book_info.ui
@@ -25,7 +25,7 @@
-
-
+
-
@@ -115,6 +115,11 @@
QWidget
+
+ CoverView
+ QGraphicsView
+
+
diff --git a/src/calibre/gui2/widgets.py b/src/calibre/gui2/widgets.py
index 3622cc6c39..5cacf32bb2 100644
--- a/src/calibre/gui2/widgets.py
+++ b/src/calibre/gui2/widgets.py
@@ -11,9 +11,9 @@ from PyQt4.Qt import QIcon, QFont, QLabel, QListWidget, QAction, \
QPixmap, QSplitterHandle, QToolButton, \
QAbstractListModel, QVariant, Qt, SIGNAL, pyqtSignal, \
QRegExp, QSettings, QSize, QSplitter, \
- QPainter, QLineEdit, QComboBox, QPen, \
+ QPainter, QLineEdit, QComboBox, QPen, QGraphicsScene, \
QMenu, QStringListModel, QCompleter, QStringList, \
- QTimer, QRect, QFontDatabase
+ QTimer, QRect, QFontDatabase, QGraphicsView
from calibre.gui2 import NONE, error_dialog, pixmap_to_data, gprefs
from calibre.gui2.filename_pattern_ui import Ui_Form
@@ -181,22 +181,16 @@ class FormatList(QListWidget):
else:
return QListWidget.keyPressEvent(self, event)
-
-class ImageView(QWidget):
-
- BORDER_WIDTH = 1
- cover_changed = pyqtSignal(object)
-
- def __init__(self, parent=None):
- QWidget.__init__(self, parent)
- self._pixmap = QPixmap(self)
- self.setMinimumSize(QSize(150, 200))
- self.setAcceptDrops(True)
- self.draw_border = True
-
- # Drag 'n drop {{{
+class ImageDropMixin(object): # {{{
+ '''
+ Adds support for dropping images onto widgets and a contect menu for
+ copy/pasting images.
+ '''
DROPABBLE_EXTENSIONS = IMAGE_EXTENSIONS
+ def __init__(self):
+ self.setAcceptDrops(True)
+
@classmethod
def paths_from_event(cls, event):
'''
@@ -223,14 +217,58 @@ class ImageView(QWidget):
pmap = QPixmap()
pmap.load(path)
if not pmap.isNull():
- self.setPixmap(pmap)
+ self.handle_image_drop(path, pmap)
event.accept()
- self.cover_changed.emit(open(path, 'rb').read())
break
+ def handle_image_drop(self, path, pmap):
+ self.set_pixmap(pmap)
+ self.cover_changed.emit(open(path, 'rb').read())
+
def dragMoveEvent(self, event):
event.acceptProposedAction()
- # }}}
+
+ def get_pixmap(self):
+ return self.pixmap()
+
+ def set_pixmap(self, pmap):
+ self.setPixmap(pmap)
+
+ def contextMenuEvent(self, ev):
+ cm = QMenu(self)
+ copy = cm.addAction(_('Copy Image'))
+ paste = cm.addAction(_('Paste Image'))
+ if not QApplication.instance().clipboard().mimeData().hasImage():
+ paste.setEnabled(False)
+ copy.triggered.connect(self.copy_to_clipboard)
+ paste.triggered.connect(self.paste_from_clipboard)
+ cm.exec_(ev.globalPos())
+
+ def copy_to_clipboard(self):
+ QApplication.instance().clipboard().setPixmap(self.get_pixmap())
+
+ def paste_from_clipboard(self):
+ cb = QApplication.instance().clipboard()
+ pmap = cb.pixmap()
+ if pmap.isNull() and cb.supportsSelection():
+ pmap = cb.pixmap(cb.Selection)
+ if not pmap.isNull():
+ self.set_pixmap(pmap)
+ self.cover_changed.emit(
+ pixmap_to_data(pmap))
+# }}}
+
+class ImageView(QWidget, ImageDropMixin):
+
+ BORDER_WIDTH = 1
+ cover_changed = pyqtSignal(object)
+
+ def __init__(self, parent=None):
+ QWidget.__init__(self, parent)
+ self._pixmap = QPixmap(self)
+ self.setMinimumSize(QSize(150, 200))
+ ImageDropMixin.__init__(self)
+ self.draw_border = True
def setPixmap(self, pixmap):
if not isinstance(pixmap, QPixmap):
@@ -272,32 +310,23 @@ class ImageView(QWidget):
p.drawRect(target)
p.end()
+class CoverView(QGraphicsView, ImageDropMixin):
- # Clipboard copy/paste # {{{
- def contextMenuEvent(self, ev):
- cm = QMenu(self)
- copy = cm.addAction(_('Copy Image'))
- paste = cm.addAction(_('Paste Image'))
- if not QApplication.instance().clipboard().mimeData().hasImage():
- paste.setEnabled(False)
- copy.triggered.connect(self.copy_to_clipboard)
- paste.triggered.connect(self.paste_from_clipboard)
- cm.exec_(ev.globalPos())
+ cover_changed = pyqtSignal(object)
- def copy_to_clipboard(self):
- QApplication.instance().clipboard().setPixmap(self.pixmap())
+ def __init__(self, *args, **kwargs):
+ QGraphicsView.__init__(self, *args, **kwargs)
+ ImageDropMixin.__init__(self)
- def paste_from_clipboard(self):
- cb = QApplication.instance().clipboard()
- pmap = cb.pixmap()
- if pmap.isNull() and cb.supportsSelection():
- pmap = cb.pixmap(cb.Selection)
- if not pmap.isNull():
- self.setPixmap(pmap)
- self.cover_changed.emit(
- pixmap_to_data(pmap))
- # }}}
+ def get_pixmap(self):
+ for item in self.scene().items():
+ if hasattr(item, 'pixmap'):
+ return item.pixmap()
+ def set_pixmap(self, pmap):
+ self.scene = QGraphicsScene()
+ self.scene.addPixmap(pmap)
+ self.setScene(self.scene)
class FontFamilyModel(QAbstractListModel):