Add a LibraryClosed plugin type that is called when the library is closed (new_api). Add a way to provide a message during shutdown.

This commit is contained in:
Charles Haley 2016-03-28 12:50:15 +02:00
parent 9235097db2
commit 22ca6dcbba
5 changed files with 91 additions and 7 deletions

View File

@ -781,3 +781,25 @@ class EditBookToolPlugin(Plugin): # {{{
# }}}
class LibraryClosedPlugin(Plugin): # {{{
'''
LibraryClosedPlugins are run when a library is closed, either at shutdown,
when the library is changed, or when a library is used in some other way.
At the moment these plugins won't be called by the CLI functions.
'''
type = _('Library Closed')
# minimum version 2 because it requires the new db
minimum_calibre_version = (2, 0, 0)
def run(self, db):
'''
The db will be a reference to the new_api (db.cache.py).
The plugin must run to completion. It must not use the GUI, threads, or
any signals.
'''
raise NotImplementedError('LibraryClosedPlugin '
'run method must be overridden in subclass')
# }}}

View File

@ -9,7 +9,8 @@ from calibre.customize import (CatalogPlugin, FileTypePlugin, PluginNotFound,
MetadataReaderPlugin, MetadataWriterPlugin,
InterfaceActionBase as InterfaceAction,
PreferencesPlugin, platform, InvalidPlugin,
StoreBase as Store, ViewerPlugin, EditBookToolPlugin)
StoreBase as Store, ViewerPlugin, EditBookToolPlugin,
LibraryClosedPlugin)
from calibre.customize.conversion import InputFormatPlugin, OutputFormatPlugin
from calibre.customize.zipplugin import loader
from calibre.customize.profiles import InputProfile, OutputProfile
@ -246,6 +247,16 @@ def preferences_plugins():
yield plugin
# }}}
# Library Closed Plugins # {{{
def available_library_closed_plugins():
customization = config['plugin_customization']
for plugin in _initialized_plugins:
if isinstance(plugin, LibraryClosedPlugin):
if not is_disabled(plugin):
plugin.site_customization = customization.get(plugin.name, '')
yield plugin
# }}}
# Store Plugins # {{{
def store_plugins():

View File

@ -2013,6 +2013,13 @@ class Cache(object):
@write_api
def close(self):
from calibre.customize.ui import available_library_closed_plugins
for plugin in available_library_closed_plugins():
try:
plugin.run(self)
except:
import traceback
traceback.print_exc()
self.backend.close()
@write_api

View File

@ -8,7 +8,7 @@ __docformat__ = 'restructuredtext en'
from functools import partial
from PyQt5.Qt import (QIcon, Qt, QWidget, QSize,
pyqtSignal, QToolButton, QMenu, QAction,
pyqtSignal, QToolButton, QMenu, QAction, QCoreApplication,
QObject, QVBoxLayout, QSizePolicy, QLabel, QHBoxLayout, QActionGroup)
@ -306,8 +306,34 @@ class MainWindowMixin(object): # {{{
l = self.centralwidget.layout()
l.addWidget(self.search_bar)
def show_shutdown_message(self, message):
msgs = getattr(self, 'shutdown_messages', None)
if msgs is None:
msgs = self.shutdown_messages = []
msgs.append(message)
smw = QWidget()
sml = QVBoxLayout()
smw.setLayout(sml)
# Construct the widget containing all the messages to date. Add stretch
# to make it vertically centered.
sml.addStretch()
for msg in msgs:
sml.addWidget(QLabel(msg), alignment=Qt.AlignHCenter)
sml.addStretch()
# The next line is needed to prevent the main widget from being garbage
# collected just in case more processing is required (and it is). As we
# are shutting down, the memory leak isn't of concern
if getattr(self, 'saved_central_widget', None) is None:
self.saved_central_widget = self.centralWidget
# Show the shutdown messages
self.setCentralWidget(smw)
# Force processing the events needed to show the message
QCoreApplication.processEvents()
# }}}

View File

@ -878,7 +878,15 @@ class Main(MainWindow, MainWindowMixin, DeviceMixin, EmailMixin, # {{{
return True
def shutdown(self, write_settings=True):
get_gui().show_shutdown_message(_('Shutting down'))
from calibre.customize.ui import available_library_closed_plugins
if available_library_closed_plugins():
get_gui().show_shutdown_message(
_('Running database shutdown plugins. This could take a few seconds...'))
self.grid_view.shutdown()
db = None
try:
db = self.library_view.model().db
cf = db.clean
@ -908,10 +916,20 @@ class Main(MainWindow, MainWindowMixin, DeviceMixin, EmailMixin, # {{{
if mb is not None:
mb.stop()
self.hide_windows()
if db is not None:
db.close()
# This happens again later. Don't do it here because it hides the
# shutdown messages
# self.hide_windows()
try:
try:
if self.content_server is not None:
# If the content server has any sockets being closed then
# this can take quite a long time (minutes). Tell the user that it is
# happening.
get_gui().show_shutdown_message(
_('Shutting down the content server. This could take a while ...'))
s = self.content_server
self.content_server = None
s.exit()