From f628964592de086e984f6793e9b9cc84e35f7263 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Sun, 10 Apr 2011 21:15:20 -0600 Subject: [PATCH] ... --- src/calibre/ebooks/metadata/sources/base.py | 36 +++++++++- .../ebooks/metadata/sources/openlibrary.py | 2 +- .../gui2/preferences/metadata_sources.py | 69 +++++++++++++++++-- 3 files changed, 99 insertions(+), 8 deletions(-) diff --git a/src/calibre/ebooks/metadata/sources/base.py b/src/calibre/ebooks/metadata/sources/base.py index 67a80d5785..5089d8951b 100644 --- a/src/calibre/ebooks/metadata/sources/base.py +++ b/src/calibre/ebooks/metadata/sources/base.py @@ -131,7 +131,22 @@ def fixcase(x): x = titlecase(x) return x +class Option(object): + __slots__ = ['type', 'default', 'label', 'desc', 'name', 'choices'] + def __init__(self, name, type_, default, label, desc, choices=None): + ''' + :param name: The name of this option. Must be a valid python identifier + :param type_: The type of this option, one of ('number', 'string', + 'bool', 'choices') + :param default: The default value for this option + :param label: A short (few words) description of this option + :param desc: A longer description of this option + :param choices: A list of possible values, used only if type='choices' + ''' + self.name, self.type, self.default, self.label, self.desc = (name, + type_, default, label, desc) + self.choices = choices class Source(Plugin): @@ -158,10 +173,14 @@ class Source(Plugin): supports_gzip_transfer_encoding = False #: Cached cover URLs can sometimes be unreliable (i.e. the download could - #: fail or the returned image could be bogus. If that is the case set this to - #: False + #: fail or the returned image could be bogus. If that is often the case + #: with this source set to False cached_cover_url_is_reliable = True + #: A list of :class:`Option` objects. They will be used to automatically + #: construct the configuration widget for this plugin + options = () + def __init__(self, *args, **kwargs): Plugin.__init__(self, *args, **kwargs) @@ -170,6 +189,9 @@ class Source(Plugin): self.cache_lock = threading.RLock() self._config_obj = None self._browser = None + self.prefs.defaults['ignore_fields'] = [] + for opt in self.options: + self.prefs.defaults[opt.name] = opt.default # Configuration {{{ @@ -180,6 +202,16 @@ class Source(Plugin): ''' return True + def is_customizable(self): + return True + + def config_widget(self): + from calibre.gui2.metadata.config import ConfigWidget + return ConfigWidget(self) + + def save_settings(self, config_widget): + config_widget.commit() + @property def prefs(self): if self._config_obj is None: diff --git a/src/calibre/ebooks/metadata/sources/openlibrary.py b/src/calibre/ebooks/metadata/sources/openlibrary.py index 19b8747265..4645d2a18a 100644 --- a/src/calibre/ebooks/metadata/sources/openlibrary.py +++ b/src/calibre/ebooks/metadata/sources/openlibrary.py @@ -12,7 +12,7 @@ from calibre.ebooks.metadata.sources.base import Source class OpenLibrary(Source): name = 'Open Library' - description = _('Downloads metadata from The Open Library') + description = _('Downloads covers from The Open Library') capabilities = frozenset(['cover']) diff --git a/src/calibre/gui2/preferences/metadata_sources.py b/src/calibre/gui2/preferences/metadata_sources.py index 8324684bc8..4500a03b30 100644 --- a/src/calibre/gui2/preferences/metadata_sources.py +++ b/src/calibre/gui2/preferences/metadata_sources.py @@ -9,14 +9,15 @@ __docformat__ = 'restructuredtext en' from operator import attrgetter -from PyQt4.Qt import (QAbstractTableModel, Qt, QAbstractListModel) +from PyQt4.Qt import (QAbstractTableModel, Qt, QAbstractListModel, QWidget, + pyqtSignal, QVBoxLayout, QDialogButtonBox, QFrame, QLabel) from calibre.gui2.preferences import ConfigWidgetBase, test_widget from calibre.gui2.preferences.metadata_sources_ui import Ui_Form from calibre.ebooks.metadata.sources.base import msprefs from calibre.customize.ui import (all_metadata_plugins, is_disabled, enable_plugin, disable_plugin, default_disabled_plugins) -from calibre.gui2 import NONE +from calibre.gui2 import NONE, error_dialog class SourcesModel(QAbstractTableModel): # {{{ @@ -64,7 +65,8 @@ class SourcesModel(QAbstractTableModel): # {{{ elif role == Qt.CheckStateRole and col == 0: orig = Qt.Unchecked if is_disabled(plugin) else Qt.Checked return self.enabled_overrides.get(plugin, orig) - + elif role == Qt.UserRole: + return plugin return NONE def setData(self, index, val, role): @@ -127,6 +129,7 @@ class SourcesModel(QAbstractTableModel): # {{{ class FieldsModel(QAbstractListModel): # {{{ + def __init__(self, parent=None): QAbstractTableModel.__init__(self, parent) @@ -143,6 +146,7 @@ class FieldsModel(QAbstractListModel): # {{{ 'language': _('Language'), } self.overrides = {} + self.exclude = frozenset(['series_index']) def rowCount(self, parent=None): return len(self.fields) @@ -153,7 +157,7 @@ class FieldsModel(QAbstractListModel): # {{{ fields |= p.touched_fields self.fields = [] for x in fields: - if not x.startswith('identifier:') and x not in ('series_index',): + if not x.startswith('identifier:') and x not in self.exclude: self.fields.append(x) self.fields.sort(key=lambda x:self.descs.get(x, x)) self.reset() @@ -204,6 +208,41 @@ class FieldsModel(QAbstractListModel): # {{{ # }}} +class PluginConfig(QWidget): # {{{ + + finished = pyqtSignal() + + def __init__(self, plugin, parent): + QWidget.__init__(self, parent) + + self.plugin = plugin + + self.l = l = QVBoxLayout() + self.setLayout(l) + self.c = c = QLabel(_('Configure %s
%s') % (plugin.name, + plugin.description)) + c.setAlignment(Qt.AlignHCenter) + l.addWidget(c) + + self.config_widget = plugin.config_widget() + self.l.addWidget(self.config_widget) + + self.bb = QDialogButtonBox( + QDialogButtonBox.Save|QDialogButtonBox.Cancel, + parent=self) + self.bb.accepted.connect(self.finished) + self.bb.rejected.connect(self.finished) + self.bb.accepted.connect(self.commit) + l.addWidget(self.bb) + + self.f = QFrame(self) + self.f.setFrameShape(QFrame.HLine) + l.addWidget(self.f) + + def commit(self): + self.plugin.save_settings(self.config_widget) +# }}} + class ConfigWidget(ConfigWidgetBase, Ui_Form): def genesis(self, gui): @@ -223,7 +262,27 @@ class ConfigWidget(ConfigWidgetBase, Ui_Form): self.fields_model.dataChanged.connect(self.changed_signal) def configure_plugin(self): - pass + for index in self.sources_view.selectionModel().selectedRows(): + plugin = self.sources_model.data(index, Qt.UserRole) + if plugin is not NONE: + return self.do_config(plugin) + error_dialog(self, _('No source selected'), + _('No source selected, cannot configure.'), show=True) + + def do_config(self, plugin): + self.pc = PluginConfig(plugin, self) + self.stack.insertWidget(1, self.pc) + self.stack.setCurrentIndex(1) + self.pc.finished.connect(self.pc_finished) + + def pc_finished(self): + try: + self.pc.finished.diconnect() + except: + pass + self.stack.setCurrentIndex(0) + self.stack.removeWidget(self.pc) + self.pc = None def initialize(self): ConfigWidgetBase.initialize(self)