mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-09 03:04:10 -04:00
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:
parent
e505743a25
commit
dc58e890bf
@ -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()
|
||||||
|
@ -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):
|
||||||
|
@ -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):
|
||||||
|
@ -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):
|
||||||
|
Loading…
x
Reference in New Issue
Block a user