You can now change the cover or add formats to the currently selected book by Drag and Drop onto the book information display panel at the bottom. Fixes #3601 (Drag and Drop cover editing in main GUI)

This commit is contained in:
Kovid Goyal 2009-10-08 14:46:54 -06:00
parent e505743a25
commit dc58e890bf
4 changed files with 84 additions and 12 deletions

View File

@ -124,17 +124,22 @@ class CopyButton(QPushButton):
def keyPressEvent(self, ev): def keyPressEvent(self, ev):
if ev.key() in self.ACTION_KEYS: try:
self.copied() if ev.key() in self.ACTION_KEYS:
else: self.copied()
QPushButton.event(self, ev) return
except:
pass
return QPushButton.event(self, ev)
def keyReleaseEvent(self, ev): def keyReleaseEvent(self, ev):
if ev.key() in self.ACTION_KEYS: try:
if ev.key() in self.ACTION_KEYS:
return
except:
pass pass
else: return QPushButton.event(self, ev)
QPushButton.event(self, ev)
def mouseReleaseEvent(self, ev): def mouseReleaseEvent(self, ev):
ev.accept() ev.accept()

View File

@ -30,7 +30,7 @@ from calibre.gui2 import APP_UID, warning_dialog, choose_files, error_dialog, \
max_available_height, config, info_dialog, \ max_available_height, config, info_dialog, \
available_width, GetMetadata available_width, GetMetadata
from calibre.gui2.cover_flow import CoverFlow, DatabaseImages, pictureflowerror from calibre.gui2.cover_flow import CoverFlow, DatabaseImages, pictureflowerror
from calibre.gui2.widgets import ProgressIndicator from calibre.gui2.widgets import ProgressIndicator, IMAGE_EXTENSIONS
from calibre.gui2.wizard import move_library from calibre.gui2.wizard import move_library
from calibre.gui2.dialogs.scheduler import Scheduler from calibre.gui2.dialogs.scheduler import Scheduler
from calibre.gui2.update import CheckForUpdates from calibre.gui2.update import CheckForUpdates
@ -220,6 +220,8 @@ class Main(MainWindow, Ui_MainWindow, DeviceGUI):
self.status_bar.job_done, Qt.QueuedConnection) self.status_bar.job_done, Qt.QueuedConnection)
QObject.connect(self.status_bar, SIGNAL('show_book_info()'), QObject.connect(self.status_bar, SIGNAL('show_book_info()'),
self.show_book_info) self.show_book_info)
QObject.connect(self.status_bar, SIGNAL('files_dropped(PyQt_PyObject,PyQt_PyObject)'),
self.files_dropped_on_book)
####################### Setup Toolbar ##################### ####################### Setup Toolbar #####################
md = QMenu() md = QMenu()
md.addAction(_('Edit metadata individually')) md.addAction(_('Edit metadata individually'))
@ -826,6 +828,31 @@ class Main(MainWindow, Ui_MainWindow, DeviceGUI):
to_device = self.stack.currentIndex() != 0 to_device = self.stack.currentIndex() != 0
self._add_books(paths, to_device) self._add_books(paths, to_device)
def files_dropped_on_book(self, event, paths):
accept = False
if self.current_view() is not self.library_view:
return
db = self.library_view.model().db
current_idx = self.library_view.currentIndex()
if not current_idx.isValid(): return
cid = db.id(current_idx.row())
for path in paths:
ext = os.path.splitext(path)[1].lower()
if ext:
ext = ext[1:]
if ext in IMAGE_EXTENSIONS:
pmap = QPixmap()
pmap.load(path)
if not pmap.isNull():
accept = True
db.set_cover(cid, pmap)
elif ext in BOOK_EXTENSIONS:
db.add_format_with_hooks(cid, ext, path, index_is_id=True)
accept = True
if accept:
event.accept()
self.cover_cache.refresh([cid])
self.library_view.model().current_changed(current_idx, current_idx)
def add_filesystem_book(self, path): def add_filesystem_book(self, path):
if os.access(path, os.R_OK): if os.access(path, os.R_OK):

View File

@ -1,14 +1,48 @@
__license__ = 'GPL v3' __license__ = 'GPL v3'
__copyright__ = '2008, Kovid Goyal <kovid at kovidgoyal.net>' __copyright__ = '2008, Kovid Goyal <kovid at kovidgoyal.net>'
import re, collections import os, re, collections
from PyQt4.QtGui import QStatusBar, QMovie, QLabel, QWidget, QHBoxLayout, QPixmap, \ from PyQt4.QtGui import QStatusBar, QMovie, QLabel, QWidget, QHBoxLayout, QPixmap, \
QVBoxLayout, QSizePolicy, QToolButton, QIcon, QScrollArea, QFrame QVBoxLayout, QSizePolicy, QToolButton, QIcon, QScrollArea, QFrame
from PyQt4.QtCore import Qt, QSize, SIGNAL, QCoreApplication from PyQt4.QtCore import Qt, QSize, SIGNAL, QCoreApplication
from calibre import fit_image, preferred_encoding, isosx from calibre import fit_image, preferred_encoding, isosx
from calibre.gui2 import qstring_to_unicode, config from calibre.gui2 import qstring_to_unicode, config
from calibre.gui2.widgets import IMAGE_EXTENSIONS
from calibre.ebooks import BOOK_EXTENSIONS
class BookInfoDisplay(QWidget): class BookInfoDisplay(QWidget):
DROPABBLE_EXTENSIONS = IMAGE_EXTENSIONS+BOOK_EXTENSIONS
@classmethod
def paths_from_event(cls, event):
'''
Accept a drop event and return a list of paths that can be read from
and represent files with extensions.
'''
if event.mimeData().hasFormat('text/uri-list'):
urls = [unicode(u.toLocalFile()) for u in event.mimeData().urls()]
urls = [u for u in urls if os.path.splitext(u)[1] and os.access(u, os.R_OK)]
return [u for u in urls if os.path.splitext(u)[1][1:].lower() in cls.DROPABBLE_EXTENSIONS]
def dragEnterEvent(self, event):
if int(event.possibleActions() & Qt.CopyAction) + \
int(event.possibleActions() & Qt.MoveAction) == 0:
return
paths = self.paths_from_event(event)
if paths:
event.acceptProposedAction()
def dropEvent(self, event):
paths = self.paths_from_event(event)
event.setDropAction(Qt.CopyAction)
self.emit(SIGNAL('files_dropped(PyQt_PyObject, PyQt_PyObject)'), event,
paths)
def dragMoveEvent(self, event):
event.acceptProposedAction()
class BookCoverDisplay(QLabel): class BookCoverDisplay(QLabel):
WIDTH = 81 WIDTH = 81
@ -184,15 +218,22 @@ class StatusBar(QStatusBar):
self.addPermanentWidget(self.tag_view_button) self.addPermanentWidget(self.tag_view_button)
self.addPermanentWidget(self.movie_button) self.addPermanentWidget(self.movie_button)
self.book_info = BookInfoDisplay(self.clearMessage) self.book_info = BookInfoDisplay(self.clearMessage)
self.book_info.setAcceptDrops(True)
self.scroll_area = QScrollArea() self.scroll_area = QScrollArea()
self.scroll_area.setWidget(self.book_info) self.scroll_area.setWidget(self.book_info)
self.scroll_area.setMaximumHeight(120) self.scroll_area.setMaximumHeight(120)
self.scroll_area.setWidgetResizable(True) self.scroll_area.setWidgetResizable(True)
self.connect(self.book_info, SIGNAL('show_book_info()'), self.show_book_info) self.connect(self.book_info, SIGNAL('show_book_info()'), self.show_book_info)
self.connect(self.book_info,
SIGNAL('files_dropped(PyQt_PyObject,PyQt_PyObject)'),
self.files_dropped, Qt.QueuedConnection)
self.addWidget(self.scroll_area, 100) self.addWidget(self.scroll_area, 100)
self.setMinimumHeight(120) self.setMinimumHeight(120)
self.setMaximumHeight(120) self.setMaximumHeight(120)
def files_dropped(self, event, paths):
self.emit(SIGNAL('files_dropped(PyQt_PyObject, PyQt_PyObject)'), event,
paths)
def reset_info(self): def reset_info(self):
self.book_info.show_data({}) self.book_info.show_data({})
@ -243,7 +284,6 @@ if __name__ == '__main__':
# Used to create the animated status icon # Used to create the animated status icon
from PyQt4.Qt import QApplication, QPainter, QSvgRenderer, QColor from PyQt4.Qt import QApplication, QPainter, QSvgRenderer, QColor
from subprocess import check_call from subprocess import check_call
import os
app = QApplication([]) app = QApplication([])
def create_pixmaps(path, size=16, delta=20): def create_pixmaps(path, size=16, delta=20):

View File

@ -105,13 +105,13 @@ class FilenamePattern(QWidget, Ui_Form):
return pat return pat
IMAGE_EXTENSIONS = ['jpg', 'jpeg', 'gif', 'png', 'bmp']
class ImageView(QLabel): class ImageView(QLabel):
MAX_WIDTH = 400 MAX_WIDTH = 400
MAX_HEIGHT = 300 MAX_HEIGHT = 300
DROPABBLE_EXTENSIONS = ('jpg', 'jpeg', 'gif', 'png', 'bmp') DROPABBLE_EXTENSIONS = IMAGE_EXTENSIONS
@classmethod @classmethod
def paths_from_event(cls, event): def paths_from_event(cls, event):