mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-09 03:04:10 -04:00
Port the conversion preferences widgets to the new scheme
This commit is contained in:
parent
e7f2051c5a
commit
77f0ce8292
@ -404,9 +404,12 @@ class PreferencesPlugin(Plugin): # {{{
|
||||
The default implementation uses :attr:`config_widget` to instantiate
|
||||
the widget.
|
||||
'''
|
||||
base = __import__(self.config_widget, fromlist=[1])
|
||||
widget = base.ConfigWidget(parent)
|
||||
return widget
|
||||
base, _, wc = self.config_widget.partition(':')
|
||||
if not wc:
|
||||
wc = 'ConfigWidget'
|
||||
base = __import__(base, fromlist=[1])
|
||||
widget = getattr(base, wc)
|
||||
return widget(parent)
|
||||
|
||||
# }}}
|
||||
|
||||
|
@ -712,7 +712,35 @@ class Toolbar(PreferencesPlugin):
|
||||
name_order = 4
|
||||
config_widget = 'calibre.gui2.preferences.toolbar'
|
||||
|
||||
plugins += [LookAndFeel, Behavior, Columns, Toolbar]
|
||||
class InputOptions(PreferencesPlugin):
|
||||
name = 'Input Options'
|
||||
gui_name = _('Input Options')
|
||||
category = 'Conversion'
|
||||
gui_category = _('Conversion')
|
||||
category_order = 2
|
||||
name_order = 1
|
||||
config_widget = 'calibre.gui2.preferences.conversion:InputOptions'
|
||||
|
||||
class CommonOptions(PreferencesPlugin):
|
||||
name = 'Common Options'
|
||||
gui_name = _('Common Options')
|
||||
category = 'Conversion'
|
||||
gui_category = _('Conversion')
|
||||
category_order = 2
|
||||
name_order = 2
|
||||
config_widget = 'calibre.gui2.preferences.conversion:CommonOptions'
|
||||
|
||||
class OutputOptions(PreferencesPlugin):
|
||||
name = 'Output Options'
|
||||
gui_name = _('Output Options')
|
||||
category = 'Conversion'
|
||||
gui_category = _('Conversion')
|
||||
category_order = 2
|
||||
name_order = 3
|
||||
config_widget = 'calibre.gui2.preferences.conversion:OutputOptions'
|
||||
|
||||
plugins += [LookAndFeel, Behavior, Columns, Toolbar, InputOptions,
|
||||
CommonOptions, OutputOptions]
|
||||
|
||||
#}}}
|
||||
|
||||
|
@ -7,9 +7,10 @@ __copyright__ = '2009, Kovid Goyal <kovid@kovidgoyal.net>'
|
||||
__docformat__ = 'restructuredtext en'
|
||||
|
||||
import textwrap
|
||||
from functools import partial
|
||||
|
||||
from PyQt4.Qt import QWidget, QSpinBox, QDoubleSpinBox, QLineEdit, QTextEdit, \
|
||||
QCheckBox, QComboBox, Qt, QIcon, SIGNAL
|
||||
QCheckBox, QComboBox, Qt, QIcon, pyqtSignal
|
||||
|
||||
from calibre.customize.conversion import OptionRecommendation
|
||||
from calibre.ebooks.conversion.config import load_defaults, \
|
||||
@ -43,6 +44,9 @@ class Widget(QWidget):
|
||||
HELP = ''
|
||||
COMMIT_NAME = None
|
||||
|
||||
changed_signal = pyqtSignal()
|
||||
set_help = pyqtSignal(object)
|
||||
|
||||
def __init__(self, parent, options):
|
||||
QWidget.__init__(self, parent)
|
||||
self.setupUi(self)
|
||||
@ -54,6 +58,7 @@ class Widget(QWidget):
|
||||
if not hasattr(self, 'opt_'+name):
|
||||
raise Exception('Option %s missing in %s'%(name,
|
||||
self.__class__.__name__))
|
||||
self.connect_gui_obj(getattr(self, 'opt_'+name))
|
||||
|
||||
def initialize_options(self, get_option, get_help, db=None, book_id=None):
|
||||
'''
|
||||
@ -76,6 +81,12 @@ class Widget(QWidget):
|
||||
self.apply_recommendations(defaults)
|
||||
self.setup_help(get_help)
|
||||
|
||||
def restore_defaults(self, get_option):
|
||||
defaults = GuiRecommendations()
|
||||
defaults.merge_recommendations(get_option, OptionRecommendation.LOW,
|
||||
self._options)
|
||||
self.apply_recommendations(defaults)
|
||||
|
||||
def commit_options(self, save_defaults=False):
|
||||
recs = self.create_recommendations()
|
||||
if save_defaults:
|
||||
@ -124,6 +135,35 @@ class Widget(QWidget):
|
||||
else:
|
||||
raise Exception('Can\'t get value from %s'%type(g))
|
||||
|
||||
def gui_obj_changed(self, gui_obj, *args):
|
||||
self.changed_signal.emit()
|
||||
|
||||
def connect_gui_obj(self, g):
|
||||
f = partial(self.gui_obj_changed, g)
|
||||
try:
|
||||
self.connect_gui_obj_handler(g, f)
|
||||
return
|
||||
except NotImplementedError:
|
||||
pass
|
||||
from calibre.gui2.convert.xpath_wizard import XPathEdit
|
||||
from calibre.gui2.convert.regex_builder import RegexEdit
|
||||
if isinstance(g, (QSpinBox, QDoubleSpinBox)):
|
||||
g.valueChanged.connect(f)
|
||||
elif isinstance(g, (QLineEdit, QTextEdit)):
|
||||
g.textChanged.connect(f)
|
||||
elif isinstance(g, QComboBox):
|
||||
g.editTextChanged.connect(f)
|
||||
g.currentIndexChanged.connect(f)
|
||||
elif isinstance(g, QCheckBox):
|
||||
g.stateChanged.connect(f)
|
||||
elif isinstance(g, (XPathEdit, RegexEdit)):
|
||||
g.edit.editTextChanged.connect(f)
|
||||
g.edit.currentIndexChanged.connect(f)
|
||||
else:
|
||||
raise Exception('Can\'t connect %s'%type(g))
|
||||
|
||||
def connect_gui_obj_handler(self, gui_obj, slot):
|
||||
raise NotImplementedError()
|
||||
|
||||
def set_value(self, g, val):
|
||||
from calibre.gui2.convert.xpath_wizard import XPathEdit
|
||||
@ -154,7 +194,7 @@ class Widget(QWidget):
|
||||
def set_help(self, msg):
|
||||
if msg and getattr(msg, 'strip', lambda:True)():
|
||||
try:
|
||||
self.emit(SIGNAL('set_help(PyQt_PyObject)'), msg)
|
||||
self.set_help.emit(msg)
|
||||
except:
|
||||
pass
|
||||
|
||||
|
@ -36,6 +36,7 @@ class PageSetupWidget(Widget, Ui_Form):
|
||||
COMMIT_NAME = 'page_setup'
|
||||
|
||||
def __init__(self, parent, get_option, get_help, db=None, book_id=None):
|
||||
self.__connections = []
|
||||
Widget.__init__(self, parent,
|
||||
['margin_top', 'margin_left', 'margin_right', 'margin_bottom',
|
||||
'input_profile', 'output_profile']
|
||||
@ -46,6 +47,10 @@ class PageSetupWidget(Widget, Ui_Form):
|
||||
self.output_model = ProfileModel(output_profiles())
|
||||
self.opt_input_profile.setModel(self.input_model)
|
||||
self.opt_output_profile.setModel(self.output_model)
|
||||
for g, slot in self.__connections:
|
||||
g.selectionModel().currentChanged.connect(slot)
|
||||
del self.__connections
|
||||
|
||||
for x in (self.opt_input_profile, self.opt_output_profile):
|
||||
x.setMouseTracking(True)
|
||||
self.connect(x, SIGNAL('entered(QModelIndex)'), self.show_desc)
|
||||
@ -55,12 +60,15 @@ class PageSetupWidget(Widget, Ui_Form):
|
||||
it = unicode(self.opt_output_profile.toolTip())
|
||||
self.opt_output_profile.setToolTip('<p>'+it.replace('t.','ce.\n<br>'))
|
||||
|
||||
|
||||
|
||||
def show_desc(self, index):
|
||||
desc = index.model().data(index, Qt.StatusTipRole).toString()
|
||||
self.profile_description.setText(desc)
|
||||
|
||||
def connect_gui_obj_handler(self, g, slot):
|
||||
if g not in (self.opt_input_profile, self.opt_output_profile):
|
||||
raise NotImplementedError()
|
||||
self.__connections.append((g, slot))
|
||||
|
||||
def set_value_handler(self, g, val):
|
||||
if g in (self.opt_input_profile, self.opt_output_profile):
|
||||
g.clearSelection()
|
||||
|
@ -10,6 +10,9 @@ from PyQt4.Qt import QWidget, pyqtSignal, QCheckBox, QAbstractSpinBox, \
|
||||
|
||||
from calibre.customize.ui import preferences_plugins
|
||||
|
||||
class AbortCommit(Exception):
|
||||
pass
|
||||
|
||||
class ConfigWidgetInterface(object):
|
||||
|
||||
changed_signal = None
|
||||
@ -24,7 +27,13 @@ class ConfigWidgetInterface(object):
|
||||
pass
|
||||
|
||||
def commit(self):
|
||||
pass
|
||||
'''
|
||||
Save any changed settings. Return True if the changes require a
|
||||
restart, False otherwise. Raise an :class:`AbortCommit` exception
|
||||
to indicate that an error occurred. You are responsible for giving the
|
||||
suer feedback about what the error is and how to correct it.
|
||||
'''
|
||||
return False
|
||||
|
||||
class Setting(object):
|
||||
|
||||
@ -184,8 +193,17 @@ def get_plugin(category, name):
|
||||
|
||||
def test_widget(category, name, gui=None): # {{{
|
||||
from PyQt4.Qt import QDialog, QVBoxLayout, QDialogButtonBox
|
||||
class Dialog(QDialog):
|
||||
def set_widget(self, w): self.w = w
|
||||
def accept(self):
|
||||
try:
|
||||
self.w.commit()
|
||||
except AbortCommit:
|
||||
return
|
||||
QDialog.accept(self)
|
||||
|
||||
pl = get_plugin(category, name)
|
||||
d = QDialog()
|
||||
d = Dialog()
|
||||
d.resize(750, 550)
|
||||
d.setWindowTitle(category + " - " + name)
|
||||
bb = QDialogButtonBox(d)
|
||||
@ -193,6 +211,7 @@ def test_widget(category, name, gui=None): # {{{
|
||||
bb.accepted.connect(d.accept)
|
||||
bb.rejected.connect(d.reject)
|
||||
w = pl.create_widget(d)
|
||||
d.set_widget(w)
|
||||
bb.button(bb.RestoreDefaults).clicked.connect(w.restore_defaults)
|
||||
bb.button(bb.Apply).setEnabled(False)
|
||||
bb.button(bb.Apply).clicked.connect(d.accept)
|
||||
|
114
src/calibre/gui2/preferences/conversion.py
Normal file
114
src/calibre/gui2/preferences/conversion.py
Normal file
@ -0,0 +1,114 @@
|
||||
#!/usr/bin/env python
|
||||
# vim:fileencoding=UTF-8:ts=4:sw=4:sta:et:sts=4:ai
|
||||
|
||||
__license__ = 'GPL v3'
|
||||
__copyright__ = '2010, Kovid Goyal <kovid@kovidgoyal.net>'
|
||||
__docformat__ = 'restructuredtext en'
|
||||
|
||||
from PyQt4.Qt import QIcon, Qt, QStringListModel, QVariant
|
||||
|
||||
from calibre.gui2.preferences import ConfigWidgetBase, test_widget, AbortCommit
|
||||
from calibre.ebooks.conversion.plumber import Plumber
|
||||
from calibre.utils.logging import Log
|
||||
from calibre.gui2.preferences.conversion_ui import Ui_Form
|
||||
from calibre.gui2.convert.look_and_feel import LookAndFeelWidget
|
||||
from calibre.gui2.convert.page_setup import PageSetupWidget
|
||||
from calibre.gui2.convert.structure_detection import StructureDetectionWidget
|
||||
from calibre.gui2.convert.toc import TOCWidget
|
||||
from calibre.customize.ui import input_format_plugins, output_format_plugins
|
||||
from calibre.gui2.convert import config_widget_for_input_plugin
|
||||
|
||||
class Model(QStringListModel):
|
||||
|
||||
def __init__(self, widgets):
|
||||
QStringListModel.__init__(self)
|
||||
self.widgets = widgets
|
||||
self.setStringList([w.TITLE for w in widgets])
|
||||
|
||||
def data(self, index, role):
|
||||
if role == Qt.DecorationRole:
|
||||
w = self.widgets[index.row()]
|
||||
if w.ICON:
|
||||
return QVariant(QIcon(w.ICON))
|
||||
return QStringListModel.data(self, index, role)
|
||||
|
||||
class Base(ConfigWidgetBase, Ui_Form):
|
||||
|
||||
HAS_ICONS = False
|
||||
|
||||
def genesis(self, gui):
|
||||
log = Log()
|
||||
log.outputs = []
|
||||
|
||||
self.plumber = Plumber('dummy.epub', 'dummy.epub', log, dummy=True,
|
||||
merge_plugin_recs=False)
|
||||
|
||||
def widget_factory(cls):
|
||||
return cls(self, self.plumber.get_option_by_name,
|
||||
self.plumber.get_option_help, None, None)
|
||||
|
||||
self.load_conversion_widgets()
|
||||
widgets = list(map(widget_factory, self.conversion_widgets))
|
||||
self.model = Model(widgets)
|
||||
self.list.setModel(self.model)
|
||||
|
||||
for w in widgets:
|
||||
w.changed_signal.connect(self.changed_signal)
|
||||
self.stack.addWidget(w)
|
||||
|
||||
|
||||
#self.list.currentRowChanged.connect(self.stack.setCurrentIndex)
|
||||
#self.list.setCurrentRow(0)
|
||||
|
||||
|
||||
def initialize(self):
|
||||
ConfigWidgetBase.initialize(self)
|
||||
|
||||
def restore_defaults(self):
|
||||
ConfigWidgetBase.restore_defaults(self)
|
||||
self.stack.currentWidget().restore_defaults(self.plumber.get_option_by_name)
|
||||
self.changed_signal.emit()
|
||||
|
||||
def commit(self):
|
||||
for widget in self.conversion_widgets:
|
||||
if not widget.pre_commit_check():
|
||||
raise AbortCommit('abort')
|
||||
widget.commit(save_defaults=True)
|
||||
return ConfigWidgetBase.commit(self)
|
||||
|
||||
class CommonOptions(Base):
|
||||
|
||||
HAS_ICONS = True
|
||||
|
||||
def load_conversion_widgets(self):
|
||||
self.conversion_widgets = [LookAndFeelWidget, PageSetupWidget,
|
||||
StructureDetectionWidget, TOCWidget]
|
||||
|
||||
class InputOptions(Base):
|
||||
|
||||
def load_conversion_widgets(self):
|
||||
self.conversion_widgets = []
|
||||
for plugin in input_format_plugins():
|
||||
pw = config_widget_for_input_plugin(plugin)
|
||||
if pw is not None:
|
||||
self.conversion_widgets.append(pw)
|
||||
|
||||
class OutputOptions(Base):
|
||||
|
||||
def load_conversion_widgets(self):
|
||||
self.conversion_widgets = []
|
||||
for plugin in output_format_plugins():
|
||||
name = plugin.name.lower().replace(' ', '_')
|
||||
try:
|
||||
output_widget = __import__('calibre.gui2.convert.'+name,
|
||||
fromlist=[1])
|
||||
pw = output_widget.PluginWidget
|
||||
self.conversion_widgets.append(pw)
|
||||
except ImportError:
|
||||
continue
|
||||
|
||||
if __name__ == '__main__':
|
||||
from PyQt4.Qt import QApplication
|
||||
app = QApplication([])
|
||||
test_widget('Conversion', 'Common Options')
|
||||
|
82
src/calibre/gui2/preferences/conversion.ui
Normal file
82
src/calibre/gui2/preferences/conversion.ui
Normal file
@ -0,0 +1,82 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>Form</class>
|
||||
<widget class="QWidget" name="Form">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>720</width>
|
||||
<height>603</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Form</string>
|
||||
</property>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<item>
|
||||
<widget class="QListView" name="list">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Expanding">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>180</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>180</width>
|
||||
<height>16777215</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="font">
|
||||
<font>
|
||||
<weight>75</weight>
|
||||
<bold>true</bold>
|
||||
</font>
|
||||
</property>
|
||||
<property name="editTriggers">
|
||||
<set>QAbstractItemView::NoEditTriggers</set>
|
||||
</property>
|
||||
<property name="tabKeyNavigation">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="showDropIndicator" stdset="0">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="iconSize">
|
||||
<size>
|
||||
<width>48</width>
|
||||
<height>48</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="verticalScrollMode">
|
||||
<enum>QAbstractItemView::ScrollPerItem</enum>
|
||||
</property>
|
||||
<property name="horizontalScrollMode">
|
||||
<enum>QAbstractItemView::ScrollPerPixel</enum>
|
||||
</property>
|
||||
<property name="flow">
|
||||
<enum>QListView::TopToBottom</enum>
|
||||
</property>
|
||||
<property name="spacing">
|
||||
<number>20</number>
|
||||
</property>
|
||||
<property name="viewMode">
|
||||
<enum>QListView::ListMode</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QStackedWidget" name="stack"/>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
Loading…
x
Reference in New Issue
Block a user