mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-09 03:04:10 -04:00
Framework for plugin based preferences dialog
This commit is contained in:
parent
81f081527d
commit
19bcbb713f
@ -8,7 +8,7 @@ from calibre.constants import numeric_version
|
|||||||
from calibre.ptempfile import PersistentTemporaryFile
|
from calibre.ptempfile import PersistentTemporaryFile
|
||||||
|
|
||||||
|
|
||||||
class Plugin(object):
|
class Plugin(object): # {{{
|
||||||
'''
|
'''
|
||||||
A calibre plugin. Useful members include:
|
A calibre plugin. Useful members include:
|
||||||
|
|
||||||
@ -147,9 +147,9 @@ class Plugin(object):
|
|||||||
if hasattr(it, '__exit__'):
|
if hasattr(it, '__exit__'):
|
||||||
it.__exit__(*args)
|
it.__exit__(*args)
|
||||||
|
|
||||||
|
# }}}
|
||||||
|
|
||||||
|
class FileTypePlugin(Plugin): # {{{
|
||||||
class FileTypePlugin(Plugin):
|
|
||||||
'''
|
'''
|
||||||
A plugin that is associated with a particular set of file types.
|
A plugin that is associated with a particular set of file types.
|
||||||
'''
|
'''
|
||||||
@ -191,7 +191,9 @@ class FileTypePlugin(Plugin):
|
|||||||
# Default implementation does nothing
|
# Default implementation does nothing
|
||||||
return path_to_ebook
|
return path_to_ebook
|
||||||
|
|
||||||
class MetadataReaderPlugin(Plugin):
|
# }}}
|
||||||
|
|
||||||
|
class MetadataReaderPlugin(Plugin): # {{{
|
||||||
'''
|
'''
|
||||||
A plugin that implements reading metadata from a set of file types.
|
A plugin that implements reading metadata from a set of file types.
|
||||||
'''
|
'''
|
||||||
@ -219,8 +221,9 @@ class MetadataReaderPlugin(Plugin):
|
|||||||
:return: A :class:`calibre.ebooks.metadata.MetaInformation` object
|
:return: A :class:`calibre.ebooks.metadata.MetaInformation` object
|
||||||
'''
|
'''
|
||||||
return None
|
return None
|
||||||
|
# }}}
|
||||||
|
|
||||||
class MetadataWriterPlugin(Plugin):
|
class MetadataWriterPlugin(Plugin): # {{{
|
||||||
'''
|
'''
|
||||||
A plugin that implements reading metadata from a set of file types.
|
A plugin that implements reading metadata from a set of file types.
|
||||||
'''
|
'''
|
||||||
@ -249,7 +252,9 @@ class MetadataWriterPlugin(Plugin):
|
|||||||
'''
|
'''
|
||||||
pass
|
pass
|
||||||
|
|
||||||
class CatalogPlugin(Plugin):
|
# }}}
|
||||||
|
|
||||||
|
class CatalogPlugin(Plugin): # {{{
|
||||||
'''
|
'''
|
||||||
A plugin that implements a catalog generator.
|
A plugin that implements a catalog generator.
|
||||||
'''
|
'''
|
||||||
@ -352,7 +357,9 @@ class CatalogPlugin(Plugin):
|
|||||||
raise NotImplementedError('CatalogPlugin.generate_catalog() default '
|
raise NotImplementedError('CatalogPlugin.generate_catalog() default '
|
||||||
'method, should be overridden in subclass')
|
'method, should be overridden in subclass')
|
||||||
|
|
||||||
class InterfaceActionBase(Plugin):
|
# }}}
|
||||||
|
|
||||||
|
class InterfaceActionBase(Plugin): # {{{
|
||||||
|
|
||||||
supported_platforms = ['windows', 'osx', 'linux']
|
supported_platforms = ['windows', 'osx', 'linux']
|
||||||
author = 'Kovid Goyal'
|
author = 'Kovid Goyal'
|
||||||
@ -360,3 +367,44 @@ class InterfaceActionBase(Plugin):
|
|||||||
can_be_disabled = False
|
can_be_disabled = False
|
||||||
|
|
||||||
actual_plugin = None
|
actual_plugin = None
|
||||||
|
# }}}
|
||||||
|
|
||||||
|
class PreferencesPlugin(Plugin): # {{{
|
||||||
|
|
||||||
|
supported_platforms = ['windows', 'osx', 'linux']
|
||||||
|
author = 'Kovid Goyal'
|
||||||
|
type = _('Preferences')
|
||||||
|
can_be_disabled = False
|
||||||
|
|
||||||
|
#: Import path to module that contains a class named ConfigWidget
|
||||||
|
#: which implements the ConfigWidgetInterface. Used by
|
||||||
|
#: :meth:`create_widget`.
|
||||||
|
config_widget = None
|
||||||
|
|
||||||
|
#: Where in the list of categories the :attr:`category` of this plugin should be.
|
||||||
|
category_order = 100
|
||||||
|
|
||||||
|
#: Where in the list of names in a category, the :attr:`gui_name` of this
|
||||||
|
#: plugin should be
|
||||||
|
name_order = 100
|
||||||
|
|
||||||
|
#: The category this plugin should be in
|
||||||
|
category = None
|
||||||
|
|
||||||
|
#: The name displayed to the user for this plugin
|
||||||
|
gui_name = None
|
||||||
|
|
||||||
|
def create_widget(self, parent=None):
|
||||||
|
'''
|
||||||
|
Create and return the actual Qt widget used for setting this group of
|
||||||
|
preferences. The widget must implement the ConfigWidgetInterface.
|
||||||
|
|
||||||
|
The default implementation uses :attr:`config_widget` to instantiate
|
||||||
|
the widget.
|
||||||
|
'''
|
||||||
|
base = __import__(self.config_widget, fromlist=[1])
|
||||||
|
widget = base.ConfigWidget(parent)
|
||||||
|
return widget
|
||||||
|
|
||||||
|
# }}}
|
||||||
|
|
||||||
|
@ -7,7 +7,8 @@ from contextlib import closing
|
|||||||
|
|
||||||
from calibre.customize import Plugin, CatalogPlugin, FileTypePlugin, \
|
from calibre.customize import Plugin, CatalogPlugin, FileTypePlugin, \
|
||||||
MetadataReaderPlugin, MetadataWriterPlugin, \
|
MetadataReaderPlugin, MetadataWriterPlugin, \
|
||||||
InterfaceActionBase as InterfaceAction
|
InterfaceActionBase as InterfaceAction, \
|
||||||
|
PreferencesPlugin
|
||||||
from calibre.customize.conversion import InputFormatPlugin, OutputFormatPlugin
|
from calibre.customize.conversion import InputFormatPlugin, OutputFormatPlugin
|
||||||
from calibre.customize.profiles import InputProfile, OutputProfile
|
from calibre.customize.profiles import InputProfile, OutputProfile
|
||||||
from calibre.customize.builtins import plugins as builtin_plugins
|
from calibre.customize.builtins import plugins as builtin_plugins
|
||||||
@ -257,6 +258,17 @@ def interface_actions():
|
|||||||
yield plugin
|
yield plugin
|
||||||
# }}}
|
# }}}
|
||||||
|
|
||||||
|
# Preferences Plugins # {{{
|
||||||
|
|
||||||
|
def preferences_plugins():
|
||||||
|
customization = config['plugin_customization']
|
||||||
|
for plugin in _initialized_plugins:
|
||||||
|
if isinstance(plugin, PreferencesPlugin):
|
||||||
|
if not is_disabled(plugin):
|
||||||
|
plugin.site_customization = customization.get(plugin.name, '')
|
||||||
|
yield plugin
|
||||||
|
# }}}
|
||||||
|
|
||||||
# Metadata read/write {{{
|
# Metadata read/write {{{
|
||||||
_metadata_readers = {}
|
_metadata_readers = {}
|
||||||
_metadata_writers = {}
|
_metadata_writers = {}
|
||||||
|
@ -7,28 +7,67 @@ __docformat__ = 'restructuredtext en'
|
|||||||
|
|
||||||
from PyQt4.Qt import QWidget, pyqtSignal
|
from PyQt4.Qt import QWidget, pyqtSignal
|
||||||
|
|
||||||
class PreferenceWidget(QWidget):
|
from calibre.customize.ui import preferences_plugins
|
||||||
|
|
||||||
category = None
|
class ConfigWidgetInterface(object):
|
||||||
name = None
|
|
||||||
|
|
||||||
changed_signal = pyqtSignal()
|
changed_signal = None
|
||||||
|
|
||||||
def __init__(self, parent=None):
|
|
||||||
QWidget.__init__(self, parent)
|
|
||||||
|
|
||||||
self.has_changed = False
|
|
||||||
self.changed.connect(lambda : setattr(self, 'has_changed', True))
|
|
||||||
self.setupUi(self)
|
|
||||||
|
|
||||||
def genesis(self, gui):
|
def genesis(self, gui):
|
||||||
raise NotImplementedError()
|
raise NotImplementedError()
|
||||||
|
|
||||||
def reset_to_defaults(self):
|
def restore_defaults(self):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def commit(self):
|
def commit(self):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def add_boolean(self, widget_name, preference_interface, pref_name):
|
|
||||||
pass
|
class ConfigWidgetBase(QWidget, ConfigWidgetInterface):
|
||||||
|
|
||||||
|
changed_signal = pyqtSignal()
|
||||||
|
|
||||||
|
def __init__(self, parent=None):
|
||||||
|
QWidget.__init__(self, parent)
|
||||||
|
if hasattr(self, 'setupUi'):
|
||||||
|
self.setupUi(self)
|
||||||
|
|
||||||
|
def get_plugin(category, name):
|
||||||
|
for plugin in preferences_plugins():
|
||||||
|
if plugin.category == category and plugin.name == name:
|
||||||
|
return plugin
|
||||||
|
raise ValueError(
|
||||||
|
'No Preferences PLugin with category: %s and name: %s found' %
|
||||||
|
(category, name))
|
||||||
|
|
||||||
|
def test_widget(category, name, gui=None): # {{{
|
||||||
|
from PyQt4.Qt import QDialog, QVBoxLayout, QDialogButtonBox
|
||||||
|
pl = get_plugin(category, name)
|
||||||
|
d = QDialog()
|
||||||
|
d.resize(750, 550)
|
||||||
|
bb = QDialogButtonBox(d)
|
||||||
|
bb.setStandardButtons(bb.Apply|bb.Cancel|bb.RestoreDefaults)
|
||||||
|
bb.accepted.connect(d.accept)
|
||||||
|
bb.rejected.connect(d.reject)
|
||||||
|
w = pl.create_widget(d)
|
||||||
|
bb.button(bb.RestoreDefaults).clicked.connect(w.restore_defaults)
|
||||||
|
bb.button(bb.Apply).setEnabled(False)
|
||||||
|
w.changed_signal.connect(lambda : bb.button(bb.Apply).setEnable(True))
|
||||||
|
l = QVBoxLayout()
|
||||||
|
pl.setLayout(l)
|
||||||
|
l.addWidget(w)
|
||||||
|
if gui is None:
|
||||||
|
from calibre.gui2.ui import Main
|
||||||
|
from calibre.gui2.main import option_parser
|
||||||
|
from calibre.library.db import db
|
||||||
|
parser = option_parser()
|
||||||
|
opts, args = parser.parse_args([])
|
||||||
|
actions = tuple(Main.create_application_menubar())
|
||||||
|
db = db()
|
||||||
|
gui = Main(opts)
|
||||||
|
gui.initialize(db.library_path, db, None, actions)
|
||||||
|
w.genesis(gui)
|
||||||
|
if d.exec_() == QDialog.Accepted:
|
||||||
|
w.commit()
|
||||||
|
# }}}
|
||||||
|
|
||||||
|
@ -50,6 +50,8 @@ class Listener(Thread): # {{{
|
|||||||
self.start()
|
self.start()
|
||||||
|
|
||||||
def run(self):
|
def run(self):
|
||||||
|
if self.listener is None:
|
||||||
|
return
|
||||||
while self._run:
|
while self._run:
|
||||||
try:
|
try:
|
||||||
conn = self.listener.accept()
|
conn = self.listener.accept()
|
||||||
|
Loading…
x
Reference in New Issue
Block a user