When running the content server do not hide the main calibre window during shutdown until the content server has stopped. Show a shutting down message in the window so that the user knows what is happening.

Create a new type of plugin LibraryClosePlugin that is run every time
an open library is closed/switched from.

Merge branch 'master' of https://github.com/cbhaley/calibre
This commit is contained in:
Kovid Goyal 2016-03-29 09:00:50 +05:30
commit 8493f4ea15
5 changed files with 87 additions and 10 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.54 because that is when support was added
minimum_calibre_version = (2, 54, 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,23 @@ 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
def has_library_closed_plugins():
for plugin in _initialized_plugins:
if isinstance(plugin, LibraryClosedPlugin):
if not is_disabled(plugin):
return True
return False
# }}}
# 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 Exception:
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)
@ -304,10 +304,25 @@ class MainWindowMixin(object): # {{{
pass # PyQt5 seems to be missing this property
l = self.centralwidget.layout()
# Add in the widget for the shutdown messages. It is invisible until a
# message is shown
smw = self.shutdown_message_widget = QLabel('')
smw.setMinimumHeight(200)
smw.setAlignment(Qt.AlignCenter)
self.shutdown_message_widget.setVisible(False)
l.addWidget(smw)
# And now, start adding the real widgets
l.addWidget(self.search_bar)
def show_shutdown_message(self, message):
smw = self.shutdown_message_widget
smw.setVisible(True)
txt = smw.text()
txt += '\n' + message
smw.setText(txt)
# 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):
self.show_shutdown_message(_('Shutting down'))
from calibre.customize.ui import has_library_closed_plugins
if has_library_closed_plugins():
self.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,17 @@ class Main(MainWindow, MainWindowMixin, DeviceMixin, EmailMixin, # {{{
if mb is not None:
mb.stop()
self.hide_windows()
if db is not None:
db.close()
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.
self.show_shutdown_message(
_('Shutting down the content server. This could take a while ...'))
s = self.content_server
self.content_server = None
s.exit()
@ -919,15 +934,15 @@ class Main(MainWindow, MainWindowMixin, DeviceMixin, EmailMixin, # {{{
pass
except KeyboardInterrupt:
pass
self.hide_windows()
# Do not report any errors that happen after the shutdown
sys.excepthook = sys.__excepthook__
if self._spare_pool is not None:
self._spare_pool.shutdown()
from calibre.db.delete_service import shutdown
shutdown()
time.sleep(2)
self.istores.join()
self.hide_windows()
# Do not report any errors that happen after the shutdown
sys.excepthook = sys.__excepthook__
return True
def run_wizard(self, *args):