mirror of
				https://github.com/kovidgoyal/calibre.git
				synced 2025-10-30 18:22:25 -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): | ||||||
|  |         try: | ||||||
|             if ev.key() in self.ACTION_KEYS: |             if ev.key() in self.ACTION_KEYS: | ||||||
|                 self.copied() |                 self.copied() | ||||||
|         else: |                 return | ||||||
|             QPushButton.event(self, ev) |         except: | ||||||
|  |             pass | ||||||
|  |         return QPushButton.event(self, ev) | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|     def keyReleaseEvent(self, ev): |     def keyReleaseEvent(self, ev): | ||||||
|  |         try: | ||||||
|             if ev.key() in self.ACTION_KEYS: |             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