%PDF- %PDF-
| Direktori : /lib/calibre/calibre/gui2/convert/ |
| Current File : //lib/calibre/calibre/gui2/convert/__init__.py |
#!/usr/bin/env python3
__license__ = 'GPL v3'
__copyright__ = '2009, Kovid Goyal <kovid@kovidgoyal.net>'
__docformat__ = 'restructuredtext en'
import textwrap, codecs, importlib
from functools import partial
from qt.core import (QWidget, QSpinBox, QDoubleSpinBox, QLineEdit, QTextEdit,
QCheckBox, QComboBox, Qt, QIcon, pyqtSignal, QLabel, QFontComboBox, QFont,
QFontInfo, QPlainTextEdit)
from calibre.customize.conversion import OptionRecommendation
from calibre.ebooks.conversion.config import (
load_defaults, save_defaults as save_defaults_, load_specifics, GuiRecommendations)
from calibre import prepare_string_for_xml
from calibre.customize.ui import plugin_for_input_format
from calibre.gui2.font_family_chooser import FontFamilyChooser
def config_widget_for_input_plugin(plugin):
name = plugin.name.lower().replace(' ', '_')
try:
return importlib.import_module(
'calibre.gui2.convert.'+name).PluginWidget
except ImportError:
# If this is not a builtin plugin, we have to import it differently
if plugin.__module__ and plugin.__module__.startswith('calibre_plugins.'):
try:
ans = importlib.import_module(plugin.__module__+'.'+name).PluginWidget
except (ImportError, AttributeError, TypeError):
pass
else:
if issubclass(ans, Widget):
return ans
def bulk_defaults_for_input_format(fmt):
plugin = plugin_for_input_format(fmt)
if plugin is not None:
w = config_widget_for_input_plugin(plugin)
if w is not None:
return load_defaults(w.COMMIT_NAME)
return {}
class Widget(QWidget):
TITLE = _('Unknown')
ICON = I('config.png')
HELP = ''
COMMIT_NAME = None
# If True, leading and trailing spaces are removed from line and text edit
# fields
STRIP_TEXT_FIELDS = True
changed_signal = pyqtSignal()
set_help_signal = pyqtSignal(object)
def __init__(self, parent, options):
options = list(options)
QWidget.__init__(self, parent)
self.setupUi(self)
self._options = options
self._name = self.commit_name = self.COMMIT_NAME
assert self._name is not None
self._icon = QIcon(self.ICON)
for name in self._options:
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):
'''
:param get_option: A callable that takes one argument: the option name
and returns the corresponding OptionRecommendation.
:param get_help: A callable that takes the option name and return a help
string.
'''
defaults = load_defaults(self._name)
defaults.merge_recommendations(get_option, OptionRecommendation.LOW,
self._options)
if db is not None:
specifics = load_specifics(db, book_id)
specifics.merge_recommendations(get_option, OptionRecommendation.HIGH,
self._options, only_existing=True)
defaults.update(specifics)
self.apply_recommendations(defaults)
self.setup_help(get_help)
def process_child(child):
for g in child.children():
if isinstance(g, QLabel):
buddy = g.buddy()
if buddy is not None and hasattr(buddy, '_help'):
g._help = buddy._help
htext = str(buddy.toolTip()).strip()
g.setToolTip(htext)
g.setWhatsThis(htext)
g.__class__.enterEvent = lambda obj, event: self.set_help(getattr(obj, '_help', obj.toolTip()))
else:
process_child(g)
process_child(self)
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:
save_defaults_(self.commit_name, recs)
return recs
def create_recommendations(self):
recs = GuiRecommendations()
for name in self._options:
gui_opt = getattr(self, 'opt_'+name, None)
if gui_opt is None:
continue
recs[name] = self.get_value(gui_opt)
return recs
def apply_recommendations(self, recs):
for name, val in recs.items():
gui_opt = getattr(self, 'opt_'+name, None)
if gui_opt is None:
continue
self.set_value(gui_opt, val)
if name in getattr(recs, 'disabled_options', []):
gui_opt.setDisabled(True)
def get_value(self, g):
from calibre.gui2.convert.xpath_wizard import XPathEdit
from calibre.gui2.convert.regex_builder import RegexEdit
from calibre.gui2.widgets import EncodingComboBox
ret = self.get_value_handler(g)
if ret != 'this is a dummy return value, xcswx1avcx4x':
return ret
if hasattr(g, 'get_value_for_config'):
return g.get_value_for_config
if isinstance(g, (QSpinBox, QDoubleSpinBox)):
return g.value()
elif isinstance(g, (QLineEdit, QTextEdit, QPlainTextEdit)):
func = getattr(g, 'toPlainText', getattr(g, 'text', None))()
ans = str(func)
if self.STRIP_TEXT_FIELDS:
ans = ans.strip()
if not ans:
ans = None
return ans
elif isinstance(g, QFontComboBox):
return str(QFontInfo(g.currentFont()).family())
elif isinstance(g, FontFamilyChooser):
return g.font_family
elif isinstance(g, EncodingComboBox):
ans = str(g.currentText()).strip()
try:
codecs.lookup(ans)
except:
ans = ''
if not ans:
ans = None
return ans
elif isinstance(g, QComboBox):
return str(g.currentText())
elif isinstance(g, QCheckBox):
return bool(g.isChecked())
elif isinstance(g, XPathEdit):
return g.xpath if g.xpath else None
elif isinstance(g, RegexEdit):
return g.regex if g.regex else None
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, QPlainTextEdit)):
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)
elif isinstance(g, FontFamilyChooser):
g.family_changed.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
from calibre.gui2.convert.regex_builder import RegexEdit
from calibre.gui2.widgets import EncodingComboBox
if self.set_value_handler(g, val):
return
if hasattr(g, 'set_value_for_config'):
g.set_value_for_config = val
return
if isinstance(g, (QSpinBox, QDoubleSpinBox)):
g.setValue(val)
elif isinstance(g, (QLineEdit, QTextEdit, QPlainTextEdit)):
if not val:
val = ''
getattr(g, 'setPlainText', getattr(g, 'setText', None))(val)
getattr(g, 'setCursorPosition', lambda x: x)(0)
elif isinstance(g, QFontComboBox):
g.setCurrentFont(QFont(val or ''))
elif isinstance(g, FontFamilyChooser):
g.font_family = val
elif isinstance(g, EncodingComboBox):
if val:
g.setEditText(val)
else:
g.setCurrentIndex(0)
elif isinstance(g, QComboBox) and val:
idx = g.findText(val, Qt.MatchFlag.MatchFixedString)
if idx < 0:
g.addItem(val)
idx = g.findText(val, Qt.MatchFlag.MatchFixedString)
g.setCurrentIndex(idx)
elif isinstance(g, QCheckBox):
g.setCheckState(Qt.CheckState.Checked if bool(val) else Qt.CheckState.Unchecked)
elif isinstance(g, (XPathEdit, RegexEdit)):
g.edit.setText(val if val else '')
else:
raise Exception('Can\'t set value %s in %s'%(repr(val),
str(g.objectName())))
self.post_set_value(g, val)
def set_help(self, msg):
if msg and getattr(msg, 'strip', lambda:True)():
try:
self.set_help_signal.emit(msg)
except:
pass
def setup_help(self, help_provider):
for name in self._options:
g = getattr(self, 'opt_'+name, None)
if g is None:
continue
help = help_provider(name)
if not help:
continue
if self.setup_help_handler(g, help):
continue
g._help = help
self.setup_widget_help(g)
def setup_widget_help(self, g):
w = textwrap.TextWrapper(80)
htext = '<div>%s</div>'%prepare_string_for_xml('\n'.join(w.wrap(g._help)))
g.setToolTip(htext)
g.setWhatsThis(htext)
g.__class__.enterEvent = lambda obj, event: self.set_help(getattr(obj, '_help', obj.toolTip()))
def set_value_handler(self, g, val):
'Return True iff you handle setting the value for g'
return False
def post_set_value(self, g, val):
pass
def get_value_handler(self, g):
return 'this is a dummy return value, xcswx1avcx4x'
def post_get_value(self, g):
pass
def setup_help_handler(self, g, help):
return False
def break_cycles(self):
self.db = None
def pre_commit_check(self):
return True
def commit(self, save_defaults=False):
return self.commit_options(save_defaults)
def config_title(self):
return self.TITLE
def config_icon(self):
return self._icon