Migrate Fetch Annotations action and refactor plugins so as to delay load the gui components

This commit is contained in:
Kovid Goyal 2010-08-12 12:12:16 -06:00
parent 82dc900a11
commit 206547021d
6 changed files with 80 additions and 40 deletions

View File

@ -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

View File

@ -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]

View File

@ -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)

View File

@ -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()

View File

@ -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)

View File

@ -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()