mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-09 03:04:10 -04:00
Migrate Fetch Annotations action and refactor plugins so as to delay load the gui components
This commit is contained in:
parent
82dc900a11
commit
206547021d
@ -353,4 +353,10 @@ class CatalogPlugin(Plugin):
|
|||||||
'method, should be overridden in subclass')
|
'method, should be overridden in subclass')
|
||||||
|
|
||||||
class InterfaceActionBase(Plugin):
|
class InterfaceActionBase(Plugin):
|
||||||
pass
|
|
||||||
|
supported_platforms = ['windows', 'osx', 'linux']
|
||||||
|
author = 'Kovid Goyal'
|
||||||
|
type = _('User Interface Action')
|
||||||
|
can_be_disabled = False
|
||||||
|
|
||||||
|
actual_plugin = None
|
||||||
|
@ -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 \
|
plugins += [x for x in list(locals().values()) if isinstance(x, type) and \
|
||||||
x.__name__.endswith('MetadataWriter')]
|
x.__name__.endswith('MetadataWriter')]
|
||||||
plugins += input_profiles + output_profiles
|
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]
|
||||||
|
@ -7,17 +7,14 @@ __docformat__ = 'restructuredtext en'
|
|||||||
|
|
||||||
from functools import partial
|
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
|
from calibre.gui2 import Dispatcher
|
||||||
|
|
||||||
class InterfaceAction(InterfaceActionBase):
|
class InterfaceAction(QObject):
|
||||||
|
|
||||||
supported_platforms = ['windows', 'osx', 'linux']
|
|
||||||
author = 'Kovid Goyal'
|
|
||||||
type = _('User Interface Action')
|
|
||||||
|
|
||||||
|
name = 'Implement me'
|
||||||
|
priority = 1
|
||||||
positions = frozenset([])
|
positions = frozenset([])
|
||||||
separators = frozenset([])
|
separators = frozenset([])
|
||||||
|
|
||||||
@ -28,15 +25,22 @@ class InterfaceAction(InterfaceActionBase):
|
|||||||
#: shortcut must be a translated string if not None
|
#: shortcut must be a translated string if not None
|
||||||
action_spec = ('text', 'icon', None, None)
|
action_spec = ('text', 'icon', None, None)
|
||||||
|
|
||||||
def do_genesis(self, gui):
|
def __init__(self, parent, site_customization):
|
||||||
self.gui = gui
|
QObject.__init__(self, parent)
|
||||||
self.Dispatcher = partial(Dispatcher, parent=gui)
|
self.gui = parent
|
||||||
|
self.site_customization = site_customization
|
||||||
|
|
||||||
|
def do_genesis(self):
|
||||||
|
self.Dispatcher = partial(Dispatcher, parent=self)
|
||||||
self.create_action()
|
self.create_action()
|
||||||
self.genesis()
|
self.genesis()
|
||||||
|
|
||||||
def create_action(self):
|
def create_action(self):
|
||||||
text, icon, tooltip, shortcut = self.action_spec
|
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
|
text = tooltip if tooltip else text
|
||||||
action.setToolTip(text)
|
action.setToolTip(text)
|
||||||
action.setStatusTip(text)
|
action.setStatusTip(text)
|
||||||
|
@ -9,19 +9,26 @@ import os, datetime
|
|||||||
|
|
||||||
from PyQt4.Qt import pyqtSignal, QModelIndex, QThread, Qt
|
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.ebooks.BeautifulSoup import BeautifulSoup, Tag, NavigableString
|
||||||
from calibre import strftime
|
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):
|
def fetch_annotations(self, *args):
|
||||||
# Generate a path_map from selected ids
|
# Generate a path_map from selected ids
|
||||||
def get_ids_from_selected_rows():
|
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:
|
if not rows or len(rows) < 2:
|
||||||
rows = xrange(self.library_view.model().rowCount(QModelIndex()))
|
rows = xrange(self.gui.library_view.model().rowCount(QModelIndex()))
|
||||||
ids = map(self.library_view.model().id, rows)
|
ids = map(self.gui.library_view.model().id, rows)
|
||||||
return ids
|
return ids
|
||||||
|
|
||||||
def get_formats(id):
|
def get_formats(id):
|
||||||
@ -42,18 +49,18 @@ class AnnotationsAction(object):
|
|||||||
path_map[id] = dict(path=a_path, fmts=get_formats(id))
|
path_map[id] = dict(path=a_path, fmts=get_formats(id))
|
||||||
return path_map
|
return path_map
|
||||||
|
|
||||||
device = self.device_manager.device
|
device = self.gui.device_manager.device
|
||||||
|
|
||||||
if self.current_view() is not self.library_view:
|
if self.gui.current_view() is not self.gui.library_view:
|
||||||
return error_dialog(self, _('Use library only'),
|
return error_dialog(self.gui, _('Use library only'),
|
||||||
_('User annotations generated from main library only'),
|
_('User annotations generated from main library only'),
|
||||||
show=True)
|
show=True)
|
||||||
db = self.library_view.model().db
|
db = self.gui.library_view.model().db
|
||||||
|
|
||||||
# Get the list of ids
|
# Get the list of ids
|
||||||
ids = get_ids_from_selected_rows()
|
ids = get_ids_from_selected_rows()
|
||||||
if not ids:
|
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'),
|
_('No books selected to fetch annotations from'),
|
||||||
show=True)
|
show=True)
|
||||||
|
|
||||||
@ -61,7 +68,7 @@ class AnnotationsAction(object):
|
|||||||
path_map = generate_annotation_paths(ids, db, device)
|
path_map = generate_annotation_paths(ids, db, device)
|
||||||
|
|
||||||
# Dispatch to devices.kindle.driver.get_annotations()
|
# 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)
|
path_map)
|
||||||
|
|
||||||
def annotations_fetched(self, job):
|
def annotations_fetched(self, job):
|
||||||
@ -70,7 +77,7 @@ class AnnotationsAction(object):
|
|||||||
from calibre.gui2.dialogs.progress import ProgressDialog
|
from calibre.gui2.dialogs.progress import ProgressDialog
|
||||||
from calibre.library.cli import do_add_format
|
from calibre.library.cli import do_add_format
|
||||||
|
|
||||||
class Updater(QThread):
|
class Updater(QThread): # {{{
|
||||||
|
|
||||||
update_progress = pyqtSignal(int)
|
update_progress = pyqtSignal(int)
|
||||||
update_done = pyqtSignal()
|
update_done = pyqtSignal()
|
||||||
@ -220,16 +227,18 @@ class AnnotationsAction(object):
|
|||||||
self.update_done.emit()
|
self.update_done.emit()
|
||||||
self.done_callback(self.am.keys())
|
self.done_callback(self.am.keys())
|
||||||
|
|
||||||
|
# }}}
|
||||||
|
|
||||||
if not job.result: return
|
if not job.result: return
|
||||||
|
|
||||||
if self.current_view() is not self.library_view:
|
if self.gui.current_view() is not self.gui.library_view:
|
||||||
return error_dialog(self, _('Use library only'),
|
return error_dialog(self.gui, _('Use library only'),
|
||||||
_('User annotations generated from main library only'),
|
_('User annotations generated from main library only'),
|
||||||
show=True)
|
show=True)
|
||||||
db = self.library_view.model().db
|
db = self.gui.library_view.model().db
|
||||||
|
|
||||||
self.__annotation_updater = Updater(self, db, job.result,
|
self.__annotation_updater = Updater(self.gui, db, job.result,
|
||||||
Dispatcher(self.library_view.model().refresh_ids))
|
self.Dispatcher(self.gui.library_view.model().refresh_ids))
|
||||||
self.__annotation_updater.start()
|
self.__annotation_updater.start()
|
||||||
|
|
||||||
|
|
||||||
|
@ -652,7 +652,8 @@ class DeviceMixin(object): # {{{
|
|||||||
self.connect(self._sync_menu,
|
self.connect(self._sync_menu,
|
||||||
SIGNAL('sync(PyQt_PyObject, PyQt_PyObject, PyQt_PyObject)'),
|
SIGNAL('sync(PyQt_PyObject, PyQt_PyObject, PyQt_PyObject)'),
|
||||||
self.dispatch_sync_event)
|
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)
|
self._sync_menu.disconnect_mounted_device.connect(self.disconnect_mounted_device)
|
||||||
if self.device_connected:
|
if self.device_connected:
|
||||||
self.share_conn_menu.connect_to_folder_action.setEnabled(False)
|
self.share_conn_menu.connect_to_folder_action.setEnabled(False)
|
||||||
|
@ -23,6 +23,8 @@ from calibre.constants import __appname__, isosx
|
|||||||
from calibre.ptempfile import PersistentTemporaryFile
|
from calibre.ptempfile import PersistentTemporaryFile
|
||||||
from calibre.utils.config import prefs, dynamic
|
from calibre.utils.config import prefs, dynamic
|
||||||
from calibre.utils.ipc.server import Server
|
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, \
|
from calibre.gui2 import error_dialog, GetMetadata, open_local_file, \
|
||||||
gprefs, max_available_height, config, info_dialog, Dispatcher
|
gprefs, max_available_height, config, info_dialog, Dispatcher
|
||||||
from calibre.gui2.cover_flow import CoverFlowMixin
|
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.device import DeviceMixin
|
||||||
from calibre.gui2.jobs import JobManager, JobsDialog, JobsButton
|
from calibre.gui2.jobs import JobManager, JobsDialog, JobsButton
|
||||||
from calibre.gui2.dialogs.config import ConfigDialog
|
from calibre.gui2.dialogs.config import ConfigDialog
|
||||||
|
|
||||||
from calibre.gui2.dialogs.book_info import BookInfo
|
from calibre.gui2.dialogs.book_info import BookInfo
|
||||||
from calibre.library.database2 import LibraryDatabase2
|
|
||||||
from calibre.gui2.init import LibraryViewMixin, LayoutMixin
|
from calibre.gui2.init import LibraryViewMixin, LayoutMixin
|
||||||
from calibre.gui2.search_box import SearchBoxMixin, SavedSearchBoxMixin
|
from calibre.gui2.search_box import SearchBoxMixin, SavedSearchBoxMixin
|
||||||
from calibre.gui2.search_restriction_mixin import SearchRestrictionMixin
|
from calibre.gui2.search_restriction_mixin import SearchRestrictionMixin
|
||||||
from calibre.gui2.tag_view import TagBrowserMixin
|
from calibre.gui2.tag_view import TagBrowserMixin
|
||||||
from calibre.gui2.actions import AnnotationsAction, AddAction, DeleteAction, \
|
|
||||||
EditMetadataAction, SaveToDiskAction, GenerateCatalogAction, FetchNewsAction, \
|
|
||||||
ConvertAction, ViewAction
|
|
||||||
|
|
||||||
|
|
||||||
class Listener(Thread): # {{{
|
class Listener(Thread): # {{{
|
||||||
@ -91,16 +88,26 @@ class SystemTrayIcon(QSystemTrayIcon): # {{{
|
|||||||
|
|
||||||
class Main(MainWindow, MainWindowMixin, DeviceMixin, # {{{
|
class Main(MainWindow, MainWindowMixin, DeviceMixin, # {{{
|
||||||
TagBrowserMixin, CoverFlowMixin, LibraryViewMixin, SearchBoxMixin,
|
TagBrowserMixin, CoverFlowMixin, LibraryViewMixin, SearchBoxMixin,
|
||||||
SavedSearchBoxMixin, SearchRestrictionMixin, LayoutMixin, UpdateMixin,
|
SavedSearchBoxMixin, SearchRestrictionMixin, LayoutMixin, UpdateMixin
|
||||||
AnnotationsAction, AddAction, DeleteAction,
|
):
|
||||||
EditMetadataAction, SaveToDiskAction, GenerateCatalogAction, FetchNewsAction,
|
|
||||||
ConvertAction, ViewAction):
|
|
||||||
'The main GUI'
|
'The main GUI'
|
||||||
|
|
||||||
|
|
||||||
def __init__(self, opts, parent=None):
|
def __init__(self, opts, parent=None):
|
||||||
MainWindow.__init__(self, opts, parent)
|
MainWindow.__init__(self, opts, parent)
|
||||||
self.opts = opts
|
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):
|
def initialize(self, library_path, db, listener, actions):
|
||||||
opts = self.opts
|
opts = self.opts
|
||||||
@ -120,6 +127,8 @@ class Main(MainWindow, MainWindowMixin, DeviceMixin, # {{{
|
|||||||
self.check_messages_timer.start(1000)
|
self.check_messages_timer.start(1000)
|
||||||
|
|
||||||
MainWindowMixin.__init__(self, db)
|
MainWindowMixin.__init__(self, db)
|
||||||
|
for ac in self.iactions.values():
|
||||||
|
ac.do_genesis()
|
||||||
|
|
||||||
# Jobs Button {{{
|
# Jobs Button {{{
|
||||||
self.job_manager = JobManager()
|
self.job_manager = JobManager()
|
||||||
@ -249,7 +258,6 @@ class Main(MainWindow, MainWindowMixin, DeviceMixin, # {{{
|
|||||||
self.start_content_server()
|
self.start_content_server()
|
||||||
|
|
||||||
self.keyboard_interrupt.connect(self.quit, type=Qt.QueuedConnection)
|
self.keyboard_interrupt.connect(self.quit, type=Qt.QueuedConnection)
|
||||||
AddAction.__init__(self)
|
|
||||||
|
|
||||||
self.read_settings()
|
self.read_settings()
|
||||||
self.finalize_layout()
|
self.finalize_layout()
|
||||||
|
Loading…
x
Reference in New Issue
Block a user