From 37d4946e972b342976214605fc5d12ac6f84e56a Mon Sep 17 00:00:00 2001 From: un-pogaz <46523284+un-pogaz@users.noreply.github.com> Date: Sun, 18 Feb 2024 20:43:07 +0100 Subject: [PATCH] Create subclass InterfaceActionWithLibraryDrop (DRY) All actual implementation of `accepts_drops` for built-in InterfaceAction are a "from_library" drag-and-drop. Create a subclass that implement the relatives methods. --- src/calibre/gui2/actions/__init__.py | 37 +++++++++++++++++-- src/calibre/gui2/actions/convert.py | 26 ++------------ src/calibre/gui2/actions/delete.py | 24 ++----------- src/calibre/gui2/actions/edit_metadata.py | 24 ++----------- src/calibre/gui2/actions/embed.py | 24 ++----------- src/calibre/gui2/actions/mark_books.py | 26 ++------------ src/calibre/gui2/actions/polish.py | 23 ++---------- src/calibre/gui2/actions/toc_edit.py | 23 ++---------- src/calibre/gui2/actions/tweak_epub.py | 26 ++------------ src/calibre/gui2/actions/unpack_book.py | 44 +++++++---------------- 10 files changed, 67 insertions(+), 210 deletions(-) diff --git a/src/calibre/gui2/actions/__init__.py b/src/calibre/gui2/actions/__init__.py index bc38118a14..1c216c48b5 100644 --- a/src/calibre/gui2/actions/__init__.py +++ b/src/calibre/gui2/actions/__init__.py @@ -8,8 +8,9 @@ __docformat__ = 'restructuredtext en' from functools import partial from zipfile import ZipFile -from qt.core import (QToolButton, QAction, QIcon, QObject, QMenu, QPoint, - QKeySequence) +from qt.core import ( + QAction, QIcon, QKeySequence, QMenu, QObject, QPoint, QTimer, QToolButton, +) from calibre import prints from calibre.constants import ismacos @@ -438,3 +439,35 @@ class InterfaceAction(QObject): long periods of time. ''' pass + +class InterfaceActionWithLibraryDrop(InterfaceAction): + ''' + Subclass of InterfaceAction that implemente methods to execute the default action + by drop some books from the library. + + Inside the do_drop() method, the ids of the droped books are provided + by the attribute self.dropped_ids + ''' + + accepts_drops = True + mime = 'application/calibre+from_library' + + def accept_enter_event(self, event, mime_data): + if mime_data.hasFormat(self.mime): + return True + return False + + def accept_drag_move_event(self, event, mime_data): + if mime_data.hasFormat(self.mime): + return True + return False + + def drop_event(self, event, mime_data): + if mime_data.hasFormat(self.mime): + self.dropped_ids = tuple(map(int, mime_data.data(self.mime).data().split())) + QTimer.singleShot(1, self.do_drop) + return True + return False + + def do_drop(self): + raise NotImplementedError() diff --git a/src/calibre/gui2/actions/convert.py b/src/calibre/gui2/actions/convert.py index bedd359ea5..6278b38c49 100644 --- a/src/calibre/gui2/actions/convert.py +++ b/src/calibre/gui2/actions/convert.py @@ -7,17 +7,17 @@ __docformat__ = 'restructuredtext en' import os from functools import partial -from qt.core import QModelIndex, QTimer +from qt.core import QModelIndex from calibre.customize.ui import plugin_for_input_format, run_plugins_on_postconvert from calibre.gui2 import Dispatcher, error_dialog, gprefs -from calibre.gui2.actions import InterfaceAction +from calibre.gui2.actions import InterfaceActionWithLibraryDrop from calibre.gui2.tools import convert_bulk_ebook, convert_single_ebook from calibre.utils.config import prefs, tweaks from calibre.utils.localization import ngettext -class ConvertAction(InterfaceAction): +class ConvertAction(InterfaceActionWithLibraryDrop): name = 'Convert Books' action_spec = (_('Convert books'), 'convert.png', _('Convert books between different e-book formats'), _('C')) @@ -25,26 +25,6 @@ class ConvertAction(InterfaceAction): action_type = 'current' action_add_menu = True - accepts_drops = True - - def accept_enter_event(self, event, mime_data): - if mime_data.hasFormat("application/calibre+from_library"): - return True - return False - - def accept_drag_move_event(self, event, mime_data): - if mime_data.hasFormat("application/calibre+from_library"): - return True - return False - - def drop_event(self, event, mime_data): - mime = 'application/calibre+from_library' - if mime_data.hasFormat(mime): - self.dropped_ids = tuple(map(int, mime_data.data(mime).data().split())) - QTimer.singleShot(1, self.do_drop) - return True - return False - def do_drop(self): book_ids = self.dropped_ids del self.dropped_ids diff --git a/src/calibre/gui2/actions/delete.py b/src/calibre/gui2/actions/delete.py index 52af7717a5..f761453e43 100644 --- a/src/calibre/gui2/actions/delete.py +++ b/src/calibre/gui2/actions/delete.py @@ -11,7 +11,7 @@ from qt.core import QDialog, QModelIndex, QObject, QTimer from calibre.constants import ismacos from calibre.gui2 import Aborted, error_dialog -from calibre.gui2.actions import InterfaceAction +from calibre.gui2.actions import InterfaceActionWithLibraryDrop from calibre.gui2.dialogs.confirm_delete import confirm from calibre.gui2.dialogs.confirm_delete_location import confirm_location from calibre.gui2.dialogs.delete_matching_from_device import ( @@ -77,7 +77,7 @@ class MultiDeleter(QObject): # {{{ # }}} -class DeleteAction(InterfaceAction): +class DeleteAction(InterfaceActionWithLibraryDrop): name = 'Remove Books' action_spec = (_('Remove books'), 'remove_books.png', _('Delete books'), 'Backspace' if ismacos else 'Del') @@ -85,26 +85,6 @@ class DeleteAction(InterfaceAction): action_add_menu = True action_menu_clone_qaction = _('Remove selected books') - accepts_drops = True - - def accept_enter_event(self, event, mime_data): - if mime_data.hasFormat("application/calibre+from_library"): - return True - return False - - def accept_drag_move_event(self, event, mime_data): - if mime_data.hasFormat("application/calibre+from_library"): - return True - return False - - def drop_event(self, event, mime_data): - mime = 'application/calibre+from_library' - if mime_data.hasFormat(mime): - self.dropped_ids = tuple(map(int, mime_data.data(mime).data().split())) - QTimer.singleShot(1, self.do_drop) - return True - return False - def do_drop(self): book_ids = self.dropped_ids del self.dropped_ids diff --git a/src/calibre/gui2/actions/edit_metadata.py b/src/calibre/gui2/actions/edit_metadata.py index 388b71d902..c42de10e91 100644 --- a/src/calibre/gui2/actions/edit_metadata.py +++ b/src/calibre/gui2/actions/edit_metadata.py @@ -21,7 +21,7 @@ from calibre.ebooks.metadata.book.base import Metadata from calibre.ebooks.metadata.opf2 import OPF, metadata_to_opf from calibre.ebooks.metadata.sources.prefs import msprefs from calibre.gui2 import Dispatcher, error_dialog, gprefs, question_dialog -from calibre.gui2.actions import InterfaceAction +from calibre.gui2.actions import InterfaceActionWithLibraryDrop from calibre.gui2.actions.show_quickview import get_quickview_action_plugin from calibre.gui2.dialogs.confirm_delete import confirm from calibre.gui2.dialogs.device_category_editor import DeviceCategoryEditor @@ -35,33 +35,13 @@ from polyglot.builtins import iteritems DATA_FILES_ICON_NAME = 'unpack-book.png' -class EditMetadataAction(InterfaceAction): +class EditMetadataAction(InterfaceActionWithLibraryDrop): name = 'Edit Metadata' action_spec = (_('Edit metadata'), 'edit_input.png', _('Change the title/author/cover etc. of books'), _('E')) action_type = 'current' action_add_menu = True - accepts_drops = True - - def accept_enter_event(self, event, mime_data): - if mime_data.hasFormat("application/calibre+from_library"): - return True - return False - - def accept_drag_move_event(self, event, mime_data): - if mime_data.hasFormat("application/calibre+from_library"): - return True - return False - - def drop_event(self, event, mime_data): - mime = 'application/calibre+from_library' - if mime_data.hasFormat(mime): - self.dropped_ids = tuple(map(int, mime_data.data(mime).data().split())) - QTimer.singleShot(1, self.do_drop) - return True - return False - def do_drop(self): book_ids = self.dropped_ids del self.dropped_ids diff --git a/src/calibre/gui2/actions/embed.py b/src/calibre/gui2/actions/embed.py index 1f5b01f467..cd7f574ae0 100644 --- a/src/calibre/gui2/actions/embed.py +++ b/src/calibre/gui2/actions/embed.py @@ -9,11 +9,11 @@ from qt.core import QProgressDialog, Qt, QTimer from calibre import force_unicode from calibre.gui2 import gprefs -from calibre.gui2.actions import InterfaceAction +from calibre.gui2.actions import InterfaceActionWithLibraryDrop from calibre.utils.localization import ngettext -class EmbedAction(InterfaceAction): +class EmbedAction(InterfaceActionWithLibraryDrop): name = 'Embed Metadata' action_spec = (_('Embed metadata'), 'modified.png', _('Embed metadata into book files'), None) @@ -21,26 +21,6 @@ class EmbedAction(InterfaceAction): action_add_menu = True action_menu_clone_qaction = _('Embed metadata into book files') - accepts_drops = True - - def accept_enter_event(self, event, mime_data): - if mime_data.hasFormat("application/calibre+from_library"): - return True - return False - - def accept_drag_move_event(self, event, mime_data): - if mime_data.hasFormat("application/calibre+from_library"): - return True - return False - - def drop_event(self, event, mime_data): - mime = 'application/calibre+from_library' - if mime_data.hasFormat(mime): - self.dropped_ids = tuple(map(int, mime_data.data(mime).data().split())) - QTimer.singleShot(1, self.do_drop) - return True - return False - def do_drop(self): book_ids = self.dropped_ids del self.dropped_ids diff --git a/src/calibre/gui2/actions/mark_books.py b/src/calibre/gui2/actions/mark_books.py index 619fffcf9d..1733253707 100644 --- a/src/calibre/gui2/actions/mark_books.py +++ b/src/calibre/gui2/actions/mark_books.py @@ -7,11 +7,11 @@ __copyright__ = '2013, Kovid Goyal ' from functools import partial from qt.core import ( QApplication, QDialog, QDialogButtonBox, QEvent, QGridLayout, QIcon, QLabel, QMenu, - QPushButton, Qt, QTimer, + QPushButton, Qt, ) from calibre.gui2 import error_dialog -from calibre.gui2.actions import InterfaceAction +from calibre.gui2.actions import InterfaceActionWithLibraryDrop from calibre.gui2.widgets2 import HistoryComboBox from calibre.startup import connect_lambda from calibre.utils.icu import sort_key @@ -81,7 +81,7 @@ class MarkWithTextDialog(QDialog): mark_books_with_text = None -class MarkBooksAction(InterfaceAction): +class MarkBooksAction(InterfaceActionWithLibraryDrop): name = 'Mark Books' action_spec = (_('Mark books'), 'marked.png', _('Temporarily mark books for easy access'), 'Ctrl+M') @@ -91,26 +91,6 @@ class MarkBooksAction(InterfaceAction): 'context-menu-device', 'menubar-device', 'context-menu-cover-browser']) action_menu_clone_qaction = _('Toggle mark for selected books') - accepts_drops = True - - def accept_enter_event(self, event, mime_data): - if mime_data.hasFormat("application/calibre+from_library"): - return True - return False - - def accept_drag_move_event(self, event, mime_data): - if mime_data.hasFormat("application/calibre+from_library"): - return True - return False - - def drop_event(self, event, mime_data): - mime = 'application/calibre+from_library' - if mime_data.hasFormat(mime): - self.dropped_ids = tuple(map(int, mime_data.data(mime).data().split())) - QTimer.singleShot(1, self.do_drop) - return True - return False - def do_drop(self): book_ids = self.dropped_ids del self.dropped_ids diff --git a/src/calibre/gui2/actions/polish.py b/src/calibre/gui2/actions/polish.py index 883702986d..71a9e28bf1 100644 --- a/src/calibre/gui2/actions/polish.py +++ b/src/calibre/gui2/actions/polish.py @@ -18,7 +18,7 @@ from qt.core import ( ) from calibre.gui2 import Dispatcher, error_dialog, gprefs, question_dialog -from calibre.gui2.actions import InterfaceAction +from calibre.gui2.actions import InterfaceActionWithLibraryDrop from calibre.gui2.convert.metadata import create_opf_file from calibre.gui2.dialogs.progress import ProgressDialog from calibre.ptempfile import PersistentTemporaryDirectory @@ -409,32 +409,13 @@ class Report(QDialog): # {{{ # }}} -class PolishAction(InterfaceAction): +class PolishAction(InterfaceActionWithLibraryDrop): name = 'Polish Books' action_spec = (_('Polish books'), 'polish.png', _('Apply the shine of perfection to your books'), _('P')) dont_add_to = frozenset(['context-menu-device']) action_type = 'current' - accepts_drops = True - - def accept_enter_event(self, event, mime_data): - if mime_data.hasFormat("application/calibre+from_library"): - return True - return False - - def accept_drag_move_event(self, event, mime_data): - if mime_data.hasFormat("application/calibre+from_library"): - return True - return False - - def drop_event(self, event, mime_data): - mime = 'application/calibre+from_library' - if mime_data.hasFormat(mime): - self.dropped_ids = tuple(map(int, mime_data.data(mime).data().split())) - QTimer.singleShot(1, self.do_drop) - return True - return False def do_drop(self): book_id_map = self.get_supported_books(self.dropped_ids) diff --git a/src/calibre/gui2/actions/toc_edit.py b/src/calibre/gui2/actions/toc_edit.py index 3ff9503c15..1f235b22af 100644 --- a/src/calibre/gui2/actions/toc_edit.py +++ b/src/calibre/gui2/actions/toc_edit.py @@ -13,7 +13,7 @@ from qt.core import ( ) from calibre.gui2 import error_dialog, gprefs, question_dialog -from calibre.gui2.actions import InterfaceAction +from calibre.gui2.actions import InterfaceActionWithLibraryDrop from calibre.startup import connect_lambda from calibre.utils.monotonic import monotonic from polyglot.builtins import iteritems @@ -68,32 +68,13 @@ class ChooseFormat(QDialog): # {{{ # }}} -class ToCEditAction(InterfaceAction): +class ToCEditAction(InterfaceActionWithLibraryDrop): name = 'Edit ToC' action_spec = (_('Edit ToC'), 'toc.png', _('Edit the Table of Contents in your books'), _('K')) dont_add_to = frozenset(['context-menu-device']) action_type = 'current' - accepts_drops = True - - def accept_enter_event(self, event, mime_data): - if mime_data.hasFormat("application/calibre+from_library"): - return True - return False - - def accept_drag_move_event(self, event, mime_data): - if mime_data.hasFormat("application/calibre+from_library"): - return True - return False - - def drop_event(self, event, mime_data): - mime = 'application/calibre+from_library' - if mime_data.hasFormat(mime): - self.dropped_ids = tuple(map(int, mime_data.data(mime).data().split())) - QTimer.singleShot(1, self.do_drop) - return True - return False def do_drop(self): book_id_map = self.get_supported_books(self.dropped_ids) diff --git a/src/calibre/gui2/actions/tweak_epub.py b/src/calibre/gui2/actions/tweak_epub.py index 9ca4c6cafe..ac2087429e 100644 --- a/src/calibre/gui2/actions/tweak_epub.py +++ b/src/calibre/gui2/actions/tweak_epub.py @@ -7,11 +7,11 @@ __docformat__ = 'restructuredtext en' import time from qt.core import ( - QCheckBox, QDialog, QDialogButtonBox, QLabel, Qt, QTimer, QVBoxLayout, + QCheckBox, QDialog, QDialogButtonBox, QLabel, Qt, QVBoxLayout, ) from calibre.gui2 import error_dialog, question_dialog -from calibre.gui2.actions import InterfaceAction +from calibre.gui2.actions import InterfaceActionWithLibraryDrop from calibre.startup import connect_lambda @@ -54,33 +54,13 @@ class Choose(QDialog): QDialog.accept(self) -class TweakEpubAction(InterfaceAction): +class TweakEpubAction(InterfaceActionWithLibraryDrop): name = 'Tweak ePub' action_spec = (_('Edit book'), 'edit_book.png', _('Edit books in the EPUB or AZW formats'), _('T')) dont_add_to = frozenset(('context-menu-device',)) action_type = 'current' - accepts_drops = True - - def accept_enter_event(self, event, mime_data): - if mime_data.hasFormat("application/calibre+from_library"): - return True - return False - - def accept_drag_move_event(self, event, mime_data): - if mime_data.hasFormat("application/calibre+from_library"): - return True - return False - - def drop_event(self, event, mime_data): - mime = 'application/calibre+from_library' - if mime_data.hasFormat(mime): - self.dropped_ids = tuple(map(int, mime_data.data(mime).data().split())) - QTimer.singleShot(1, self.do_drop) - return True - return False - def do_drop(self): book_ids = self.dropped_ids del self.dropped_ids diff --git a/src/calibre/gui2/actions/unpack_book.py b/src/calibre/gui2/actions/unpack_book.py index d729542d6e..908736729a 100644 --- a/src/calibre/gui2/actions/unpack_book.py +++ b/src/calibre/gui2/actions/unpack_book.py @@ -5,17 +5,19 @@ __license__ = 'GPL v3' __copyright__ = '2010, Kovid Goyal ' __docformat__ = 'restructuredtext en' -import os, weakref, shutil - -from qt.core import (QDialog, QVBoxLayout, QHBoxLayout, QRadioButton, QFrame, - QPushButton, QLabel, QGroupBox, QGridLayout, QIcon, QSize, QTimer) +import os +import shutil +import weakref +from qt.core import ( + QDialog, QFrame, QGridLayout, QGroupBox, QHBoxLayout, QIcon, QLabel, QPushButton, + QRadioButton, QSize, QTimer, QVBoxLayout, +) from calibre import as_unicode from calibre.constants import ismacos -from calibre.gui2 import error_dialog, question_dialog, open_local_file, gprefs -from calibre.gui2.actions import InterfaceAction -from calibre.ptempfile import (PersistentTemporaryDirectory, - PersistentTemporaryFile) +from calibre.gui2 import error_dialog, gprefs, open_local_file, question_dialog +from calibre.gui2.actions import InterfaceActionWithLibraryDrop +from calibre.ptempfile import PersistentTemporaryDirectory, PersistentTemporaryFile from calibre.utils.config import prefs, tweaks @@ -163,7 +165,7 @@ class UnpackBook(QDialog): return question_dialog(self, _('Are you sure?'), msg) def do_explode(self): - from calibre.ebooks.tweak import get_tools, Error, WorkerError + from calibre.ebooks.tweak import Error, WorkerError, get_tools tdir = PersistentTemporaryDirectory('_tweak_explode') self._cleanup_dirs.append(tdir) det_msg = None @@ -201,7 +203,7 @@ class UnpackBook(QDialog): open_local_file(tdir) def rebuild_it(self): - from calibre.ebooks.tweak import get_tools, WorkerError + from calibre.ebooks.tweak import WorkerError, get_tools src_dir = self._exploded det_msg = None of = PersistentTemporaryFile('_tweak_rebuild.'+self.current_format.lower()) @@ -284,7 +286,7 @@ class UnpackBook(QDialog): return str(b.text()) -class UnpackBookAction(InterfaceAction): +class UnpackBookAction(InterfaceActionWithLibraryDrop): name = 'Unpack Book' action_spec = (_('Unpack book'), 'unpack-book.png', @@ -292,26 +294,6 @@ class UnpackBookAction(InterfaceAction): dont_add_to = frozenset(['context-menu-device']) action_type = 'current' - accepts_drops = True - - def accept_enter_event(self, event, mime_data): - if mime_data.hasFormat("application/calibre+from_library"): - return True - return False - - def accept_drag_move_event(self, event, mime_data): - if mime_data.hasFormat("application/calibre+from_library"): - return True - return False - - def drop_event(self, event, mime_data): - mime = 'application/calibre+from_library' - if mime_data.hasFormat(mime): - self.dropped_ids = tuple(map(int, mime_data.data(mime).data().split())) - QTimer.singleShot(1, self.do_drop) - return True - return False - def do_drop(self): book_ids = self.dropped_ids del self.dropped_ids