From 206547021d8f1bf69b67a78d1111023f2fdfb861 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Thu, 12 Aug 2010 12:12:16 -0600 Subject: [PATCH] Migrate Fetch Annotations action and refactor plugins so as to delay load the gui components --- src/calibre/customize/__init__.py | 8 +++++- src/calibre/customize/builtins.py | 12 ++++++++ src/calibre/gui2/actions/__init__.py | 26 ++++++++++------- src/calibre/gui2/actions/annotate.py | 43 +++++++++++++++++----------- src/calibre/gui2/device.py | 3 +- src/calibre/gui2/ui.py | 28 +++++++++++------- 6 files changed, 80 insertions(+), 40 deletions(-) diff --git a/src/calibre/customize/__init__.py b/src/calibre/customize/__init__.py index ea11259da2..88c9324239 100644 --- a/src/calibre/customize/__init__.py +++ b/src/calibre/customize/__init__.py @@ -353,4 +353,10 @@ class CatalogPlugin(Plugin): 'method, should be overridden in subclass') class InterfaceActionBase(Plugin): - pass + + supported_platforms = ['windows', 'osx', 'linux'] + author = 'Kovid Goyal' + type = _('User Interface Action') + can_be_disabled = False + + actual_plugin = None diff --git a/src/calibre/customize/builtins.py b/src/calibre/customize/builtins.py index 998bfa7b1e..d71d934e2c 100644 --- a/src/calibre/customize/builtins.py +++ b/src/calibre/customize/builtins.py @@ -574,3 +574,15 @@ plugins += [x for x in list(locals().values()) if isinstance(x, type) and \ plugins += [x for x in list(locals().values()) if isinstance(x, type) and \ x.__name__.endswith('MetadataWriter')] plugins += input_profiles + output_profiles + +from calibre.customize import InterfaceActionBase + +class ActionAdd(InterfaceActionBase): + name = 'action_add' + actual_plugin = 'calibre.gui2.actions.add:AddAction' + +class ActionFetchAnnotations(InterfaceActionBase): + name = 'action_fetch_annotations' + actual_plugin = 'calibre.gui2.actions.annotate:FetchAnnotationsAction' + +plugins += [ActionAdd, ActionFetchAnnotations] diff --git a/src/calibre/gui2/actions/__init__.py b/src/calibre/gui2/actions/__init__.py index fc5f3bd9b8..74a8cbe5f5 100644 --- a/src/calibre/gui2/actions/__init__.py +++ b/src/calibre/gui2/actions/__init__.py @@ -7,17 +7,14 @@ __docformat__ = 'restructuredtext en' from functools import partial -from PyQt4.Qt import QToolButton, QAction, QIcon +from PyQt4.Qt import QToolButton, QAction, QIcon, QObject -from calibre.customize import InterfaceActionBase from calibre.gui2 import Dispatcher -class InterfaceAction(InterfaceActionBase): - - supported_platforms = ['windows', 'osx', 'linux'] - author = 'Kovid Goyal' - type = _('User Interface Action') +class InterfaceAction(QObject): + name = 'Implement me' + priority = 1 positions = frozenset([]) separators = frozenset([]) @@ -28,15 +25,22 @@ class InterfaceAction(InterfaceActionBase): #: shortcut must be a translated string if not None action_spec = ('text', 'icon', None, None) - def do_genesis(self, gui): - self.gui = gui - self.Dispatcher = partial(Dispatcher, parent=gui) + def __init__(self, parent, site_customization): + QObject.__init__(self, parent) + self.gui = parent + self.site_customization = site_customization + + def do_genesis(self): + self.Dispatcher = partial(Dispatcher, parent=self) self.create_action() self.genesis() def create_action(self): text, icon, tooltip, shortcut = self.action_spec - action = QAction(QIcon(I(icon)), text, self) + if icon is not None: + action = QAction(QIcon(I(icon)), text, self.gui) + else: + action = QAction(text, self.gui) text = tooltip if tooltip else text action.setToolTip(text) action.setStatusTip(text) diff --git a/src/calibre/gui2/actions/annotate.py b/src/calibre/gui2/actions/annotate.py index 22f42156dd..e4c45742c2 100644 --- a/src/calibre/gui2/actions/annotate.py +++ b/src/calibre/gui2/actions/annotate.py @@ -9,19 +9,26 @@ import os, datetime from PyQt4.Qt import pyqtSignal, QModelIndex, QThread, Qt -from calibre.gui2 import error_dialog, Dispatcher, gprefs +from calibre.gui2 import error_dialog, gprefs from calibre.ebooks.BeautifulSoup import BeautifulSoup, Tag, NavigableString from calibre import strftime +from calibre.gui2.actions import InterfaceAction -class AnnotationsAction(object): +class FetchAnnotationsAction(InterfaceAction): + + name = 'Fetch Annotations' + action_spec = (_('Fetch Annotations'), None, None, None) + + def genesis(self): + pass def fetch_annotations(self, *args): # Generate a path_map from selected ids def get_ids_from_selected_rows(): - rows = self.library_view.selectionModel().selectedRows() + rows = self.gui.library_view.selectionModel().selectedRows() if not rows or len(rows) < 2: - rows = xrange(self.library_view.model().rowCount(QModelIndex())) - ids = map(self.library_view.model().id, rows) + rows = xrange(self.gui.library_view.model().rowCount(QModelIndex())) + ids = map(self.gui.library_view.model().id, rows) return ids def get_formats(id): @@ -42,18 +49,18 @@ class AnnotationsAction(object): path_map[id] = dict(path=a_path, fmts=get_formats(id)) return path_map - device = self.device_manager.device + device = self.gui.device_manager.device - if self.current_view() is not self.library_view: - return error_dialog(self, _('Use library only'), + if self.gui.current_view() is not self.gui.library_view: + return error_dialog(self.gui, _('Use library only'), _('User annotations generated from main library only'), show=True) - db = self.library_view.model().db + db = self.gui.library_view.model().db # Get the list of ids ids = get_ids_from_selected_rows() if not ids: - return error_dialog(self, _('No books selected'), + return error_dialog(self.gui, _('No books selected'), _('No books selected to fetch annotations from'), show=True) @@ -61,7 +68,7 @@ class AnnotationsAction(object): path_map = generate_annotation_paths(ids, db, device) # Dispatch to devices.kindle.driver.get_annotations() - self.device_manager.annotations(Dispatcher(self.annotations_fetched), + self.gui.device_manager.annotations(self.Dispatcher(self.annotations_fetched), path_map) def annotations_fetched(self, job): @@ -70,7 +77,7 @@ class AnnotationsAction(object): from calibre.gui2.dialogs.progress import ProgressDialog from calibre.library.cli import do_add_format - class Updater(QThread): + class Updater(QThread): # {{{ update_progress = pyqtSignal(int) update_done = pyqtSignal() @@ -220,16 +227,18 @@ class AnnotationsAction(object): self.update_done.emit() self.done_callback(self.am.keys()) + # }}} + if not job.result: return - if self.current_view() is not self.library_view: - return error_dialog(self, _('Use library only'), + if self.gui.current_view() is not self.gui.library_view: + return error_dialog(self.gui, _('Use library only'), _('User annotations generated from main library only'), show=True) - db = self.library_view.model().db + db = self.gui.library_view.model().db - self.__annotation_updater = Updater(self, db, job.result, - Dispatcher(self.library_view.model().refresh_ids)) + self.__annotation_updater = Updater(self.gui, db, job.result, + self.Dispatcher(self.gui.library_view.model().refresh_ids)) self.__annotation_updater.start() diff --git a/src/calibre/gui2/device.py b/src/calibre/gui2/device.py index 789ae68723..0f83afa6dd 100644 --- a/src/calibre/gui2/device.py +++ b/src/calibre/gui2/device.py @@ -652,7 +652,8 @@ class DeviceMixin(object): # {{{ self.connect(self._sync_menu, SIGNAL('sync(PyQt_PyObject, PyQt_PyObject, PyQt_PyObject)'), self.dispatch_sync_event) - self._sync_menu.fetch_annotations.connect(self.fetch_annotations) + self._sync_menu.fetch_annotations.connect( + self.iactions['Fetch Annotations'].fetch_annotations) self._sync_menu.disconnect_mounted_device.connect(self.disconnect_mounted_device) if self.device_connected: self.share_conn_menu.connect_to_folder_action.setEnabled(False) diff --git a/src/calibre/gui2/ui.py b/src/calibre/gui2/ui.py index cca6a378d1..63b1e72de4 100644 --- a/src/calibre/gui2/ui.py +++ b/src/calibre/gui2/ui.py @@ -23,6 +23,8 @@ from calibre.constants import __appname__, isosx from calibre.ptempfile import PersistentTemporaryFile from calibre.utils.config import prefs, dynamic from calibre.utils.ipc.server import Server +from calibre.library.database2 import LibraryDatabase2 +from calibre.customize import interface_actions from calibre.gui2 import error_dialog, GetMetadata, open_local_file, \ gprefs, max_available_height, config, info_dialog, Dispatcher from calibre.gui2.cover_flow import CoverFlowMixin @@ -33,16 +35,11 @@ from calibre.gui2.layout import MainWindowMixin from calibre.gui2.device import DeviceMixin from calibre.gui2.jobs import JobManager, JobsDialog, JobsButton from calibre.gui2.dialogs.config import ConfigDialog - from calibre.gui2.dialogs.book_info import BookInfo -from calibre.library.database2 import LibraryDatabase2 from calibre.gui2.init import LibraryViewMixin, LayoutMixin from calibre.gui2.search_box import SearchBoxMixin, SavedSearchBoxMixin from calibre.gui2.search_restriction_mixin import SearchRestrictionMixin from calibre.gui2.tag_view import TagBrowserMixin -from calibre.gui2.actions import AnnotationsAction, AddAction, DeleteAction, \ - EditMetadataAction, SaveToDiskAction, GenerateCatalogAction, FetchNewsAction, \ - ConvertAction, ViewAction class Listener(Thread): # {{{ @@ -91,16 +88,26 @@ class SystemTrayIcon(QSystemTrayIcon): # {{{ class Main(MainWindow, MainWindowMixin, DeviceMixin, # {{{ TagBrowserMixin, CoverFlowMixin, LibraryViewMixin, SearchBoxMixin, - SavedSearchBoxMixin, SearchRestrictionMixin, LayoutMixin, UpdateMixin, - AnnotationsAction, AddAction, DeleteAction, - EditMetadataAction, SaveToDiskAction, GenerateCatalogAction, FetchNewsAction, - ConvertAction, ViewAction): + SavedSearchBoxMixin, SearchRestrictionMixin, LayoutMixin, UpdateMixin + ): 'The main GUI' def __init__(self, opts, parent=None): MainWindow.__init__(self, opts, parent) self.opts = opts + acmap = {} + for action in interface_actions(): + mod, cls = action.actual_plugin.split(':') + ac = getattr(__import__(mod, fromlist=['1'], level=0), cls)(self, + action.site_customization) + if ac.name in acmap: + if ac.priority >= acmap[ac.name].priority: + acmap[ac.name] = ac + else: + acmap[ac.name] = ac + + self.iactions = acmap def initialize(self, library_path, db, listener, actions): opts = self.opts @@ -120,6 +127,8 @@ class Main(MainWindow, MainWindowMixin, DeviceMixin, # {{{ self.check_messages_timer.start(1000) MainWindowMixin.__init__(self, db) + for ac in self.iactions.values(): + ac.do_genesis() # Jobs Button {{{ self.job_manager = JobManager() @@ -249,7 +258,6 @@ class Main(MainWindow, MainWindowMixin, DeviceMixin, # {{{ self.start_content_server() self.keyboard_interrupt.connect(self.quit, type=Qt.QueuedConnection) - AddAction.__init__(self) self.read_settings() self.finalize_layout()