mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-09 03:04:10 -04:00
Widget for strucutre detection settings
This commit is contained in:
parent
2ac2aed136
commit
9765d91570
@ -304,6 +304,7 @@ class ComicInput(InputFormatPlugin):
|
||||
('chapter', None, OptionRecommendation.HIGH),
|
||||
('page_breaks_brefore', None, OptionRecommendation.HIGH),
|
||||
('use_auto_toc', False, OptionRecommendation.HIGH),
|
||||
('page_breaks_before', None, OptionRecommendation.HIGH),
|
||||
])
|
||||
|
||||
def get_comics_from_collection(self, stream):
|
||||
|
@ -154,6 +154,7 @@ class Widget(QWidget):
|
||||
|
||||
|
||||
def get_value(self, g):
|
||||
from calibre.gui2.convert.xpath_wizard import XPathEdit
|
||||
ret = self.get_value_handler(g)
|
||||
if ret != 'this is a dummy return value, xcswx1avcx4x':
|
||||
return ret
|
||||
@ -169,11 +170,14 @@ class Widget(QWidget):
|
||||
return unicode(g.currentText())
|
||||
elif isinstance(g, QCheckBox):
|
||||
return bool(g.isChecked())
|
||||
elif isinstance(g, XPathEdit):
|
||||
return g.xpath
|
||||
else:
|
||||
raise Exception('Can\'t get value from %s'%type(g))
|
||||
|
||||
|
||||
def set_value(self, g, val):
|
||||
from calibre.gui2.convert.xpath_wizard import XPathEdit
|
||||
if self.set_value_handler(g, val):
|
||||
return
|
||||
if isinstance(g, (QSpinBox, QDoubleSpinBox)):
|
||||
@ -190,6 +194,8 @@ class Widget(QWidget):
|
||||
g.setCurrentIndex(idx)
|
||||
elif isinstance(g, QCheckBox):
|
||||
g.setCheckState(Qt.Checked if bool(val) else Qt.Unchecked)
|
||||
elif isinstance(g, XPathEdit):
|
||||
g.edit.setText(val if val else '')
|
||||
else:
|
||||
raise Exception('Can\'t set value %s in %s'%(repr(val), type(g)))
|
||||
self.post_set_value(g, val)
|
||||
@ -223,6 +229,9 @@ class Widget(QWidget):
|
||||
def post_get_value(self, g):
|
||||
pass
|
||||
|
||||
def pre_commit_check(self):
|
||||
return True
|
||||
|
||||
def commit(self, save_defaults=False):
|
||||
return self.commit_options(save_defaults)
|
||||
|
||||
|
@ -17,6 +17,8 @@ from calibre.gui2.convert.single_ui import Ui_Dialog
|
||||
from calibre.gui2.convert.metadata import MetadataWidget
|
||||
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.ebooks.conversion.plumber import Plumber, supported_input_formats, \
|
||||
INPUT_FORMAT_PREFERENCES, OUTPUT_FORMAT_PREFERENCES
|
||||
@ -115,6 +117,7 @@ class Config(ResizableDialog, Ui_Dialog):
|
||||
|
||||
|
||||
def setup_pipeline(self, *args):
|
||||
oidx = self.groups.currentIndex().row()
|
||||
input_format = self.input_format
|
||||
output_format = self.output_format
|
||||
input_path = self.db.format_abspath(self.book_id, input_format,
|
||||
@ -134,6 +137,7 @@ class Config(ResizableDialog, Ui_Dialog):
|
||||
self.setWindowTitle(_('Convert')+ ' ' + unicode(self.mw.title.text()))
|
||||
lf = widget_factory(LookAndFeelWidget)
|
||||
ps = widget_factory(PageSetupWidget)
|
||||
sd = widget_factory(StructureDetectionWidget)
|
||||
|
||||
output_widget = None
|
||||
name = 'calibre.gui2.convert.%s' % self.plumber.output_plugin.name.lower().replace(' ', '_')
|
||||
@ -162,7 +166,7 @@ class Config(ResizableDialog, Ui_Dialog):
|
||||
if not c: break
|
||||
self.stack.removeWidget(c)
|
||||
|
||||
widgets = [self.mw, lf, ps]
|
||||
widgets = [self.mw, lf, ps, sd]
|
||||
if input_widget is not None:
|
||||
widgets.append(input_widget)
|
||||
if output_widget is not None:
|
||||
@ -175,7 +179,8 @@ class Config(ResizableDialog, Ui_Dialog):
|
||||
self._groups_model = GroupModel(widgets)
|
||||
self.groups.setModel(self._groups_model)
|
||||
|
||||
self.groups.setCurrentIndex(self._groups_model.index(0))
|
||||
idx = oidx if -1 < oidx < self._groups_model.rowCount() else 0
|
||||
self.groups.setCurrentIndex(self._groups_model.index(idx))
|
||||
|
||||
|
||||
def setup_input_output_formats(self, db, book_id, preferred_input_format,
|
||||
@ -213,6 +218,8 @@ class Config(ResizableDialog, Ui_Dialog):
|
||||
def accept(self):
|
||||
recs = GuiRecommendations()
|
||||
for w in self._groups_model.widgets:
|
||||
if not w.pre_commit_check():
|
||||
return
|
||||
x = w.commit(save_defaults=False)
|
||||
recs.update(x)
|
||||
self.opf_path, self.cover_path = self.mw.opf_file, self.mw.cover_file
|
||||
|
42
src/calibre/gui2/convert/structure_detection.py
Normal file
42
src/calibre/gui2/convert/structure_detection.py
Normal file
@ -0,0 +1,42 @@
|
||||
#!/usr/bin/env python
|
||||
# vim:fileencoding=UTF-8:ts=4:sw=4:sta:et:sts=4:ai
|
||||
from __future__ import with_statement
|
||||
|
||||
__license__ = 'GPL v3'
|
||||
__copyright__ = '2009, Kovid Goyal <kovid@kovidgoyal.net>'
|
||||
__docformat__ = 'restructuredtext en'
|
||||
|
||||
|
||||
from calibre.gui2.convert.structure_detection_ui import Ui_Form
|
||||
from calibre.gui2.convert import Widget
|
||||
from calibre.gui2 import error_dialog
|
||||
|
||||
class StructureDetectionWidget(Widget, Ui_Form):
|
||||
|
||||
TITLE = _('Structure\nDetection')
|
||||
ICON = ':/images/chapters.svg'
|
||||
HELP = _('Fine tune the detection of chapter headings and '
|
||||
'other document structure.')
|
||||
|
||||
def __init__(self, parent, get_option, get_help, db=None, book_id=None):
|
||||
Widget.__init__(self, parent, 'structure_detection',
|
||||
['chapter', 'chapter_mark',
|
||||
'remove_first_image',
|
||||
'insert_metadata', 'page_breaks_before',
|
||||
'preprocess_html']
|
||||
)
|
||||
self.db, self.book_id = db, book_id
|
||||
self.initialize_options(get_option, get_help, db, book_id)
|
||||
self.opt_chapter.set_msg(_('Detect chapters at (XPath expression):'))
|
||||
self.opt_page_breaks_before.set_msg(_('Insert page breaks before '
|
||||
'(XPath expression):'))
|
||||
|
||||
|
||||
def pre_commit_check(self):
|
||||
for x in ('chapter', 'page_breaks_before'):
|
||||
x = getattr(self, 'opt_'+x)
|
||||
if not x.check():
|
||||
error_dialog(self, _('Invalid XPath'),
|
||||
_('The XPath expression %s is invalid.')%x.xpath).exec_()
|
||||
return False
|
||||
return True
|
103
src/calibre/gui2/convert/structure_detection.ui
Normal file
103
src/calibre/gui2/convert/structure_detection.ui
Normal file
@ -0,0 +1,103 @@
|
||||
<?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>657</width>
|
||||
<height>479</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Form</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="text">
|
||||
<string>Chapter &mark:</string>
|
||||
</property>
|
||||
<property name="buddy">
|
||||
<cstring>opt_chapter_mark</cstring>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QComboBox" name="opt_chapter_mark">
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>pagebreak</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>rule</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>both</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>none</string>
|
||||
</property>
|
||||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QCheckBox" name="opt_remove_first_image">
|
||||
<property name="text">
|
||||
<string>Remove first &image</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="0">
|
||||
<widget class="QCheckBox" name="opt_insert_metadata">
|
||||
<property name="text">
|
||||
<string>Insert &metadata as page at start of book</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="0" colspan="2">
|
||||
<widget class="QCheckBox" name="opt_preprocess_html">
|
||||
<property name="text">
|
||||
<string>&Preprocess input file to possibly improve structure detection</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="0" colspan="2">
|
||||
<widget class="XPathEdit" name="opt_page_breaks_before" native="true"/>
|
||||
</item>
|
||||
<item row="0" column="0" colspan="2">
|
||||
<widget class="XPathEdit" name="opt_chapter" native="true"/>
|
||||
</item>
|
||||
<item row="6" column="0">
|
||||
<spacer name="verticalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>40</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<customwidgets>
|
||||
<customwidget>
|
||||
<class>XPathEdit</class>
|
||||
<extends>QWidget</extends>
|
||||
<header>convert/xpath_wizard.h</header>
|
||||
<container>1</container>
|
||||
</customwidget>
|
||||
</customwidgets>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
59
src/calibre/gui2/convert/xpath_edit.ui
Normal file
59
src/calibre/gui2/convert/xpath_edit.ui
Normal file
@ -0,0 +1,59 @@
|
||||
<ui version="4.0" >
|
||||
<class>Form</class>
|
||||
<widget class="QWidget" name="Form" >
|
||||
<property name="geometry" >
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>400</width>
|
||||
<height>64</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle" >
|
||||
<string>Form</string>
|
||||
</property>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout" >
|
||||
<item>
|
||||
<layout class="QVBoxLayout" name="verticalLayout" >
|
||||
<item>
|
||||
<widget class="QLabel" name="msg" >
|
||||
<property name="text" >
|
||||
<string>TextLabel</string>
|
||||
</property>
|
||||
<property name="wordWrap" >
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLineEdit" name="edit" />
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QToolButton" name="button" >
|
||||
<property name="toolTip" >
|
||||
<string>Use a wizard to help construct the XPath expression</string>
|
||||
</property>
|
||||
<property name="text" >
|
||||
<string>...</string>
|
||||
</property>
|
||||
<property name="icon" >
|
||||
<iconset resource="../images.qrc" >
|
||||
<normaloff>:/images/wizard.svg</normaloff>:/images/wizard.svg</iconset>
|
||||
</property>
|
||||
<property name="iconSize" >
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>40</height>
|
||||
</size>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources>
|
||||
<include location="../images.qrc" />
|
||||
</resources>
|
||||
<connections/>
|
||||
</ui>
|
89
src/calibre/gui2/convert/xpath_wizard.py
Normal file
89
src/calibre/gui2/convert/xpath_wizard.py
Normal file
@ -0,0 +1,89 @@
|
||||
#!/usr/bin/env python
|
||||
# vim:fileencoding=UTF-8:ts=4:sw=4:sta:et:sts=4:ai
|
||||
from __future__ import with_statement
|
||||
|
||||
__license__ = 'GPL v3'
|
||||
__copyright__ = '2009, Kovid Goyal <kovid@kovidgoyal.net>'
|
||||
__docformat__ = 'restructuredtext en'
|
||||
|
||||
from PyQt4.Qt import QDialog, QWidget, SIGNAL, Qt, QDialogButtonBox, QVBoxLayout
|
||||
|
||||
from calibre.gui2.convert.xpath_wizard_ui import Ui_Form
|
||||
from calibre.gui2.convert.xpath_edit_ui import Ui_Form as Ui_Edit
|
||||
|
||||
|
||||
class WizardWidget(QWidget, Ui_Form):
|
||||
|
||||
def __init__(self, parent=None):
|
||||
QWidget.__init__(self, parent)
|
||||
self.setupUi(self)
|
||||
|
||||
@property
|
||||
def xpath(self):
|
||||
tag = unicode(self.tag.currentText()).strip()
|
||||
if tag != '*':
|
||||
tag = 'h:'+tag
|
||||
attr, val = map(unicode, (self.attribute.text(), self.value.text()))
|
||||
attr, val = attr.strip(), val.strip()
|
||||
q = ''
|
||||
if attr:
|
||||
if val:
|
||||
q = '[re:test(@%s, "%s", "i")]'%(attr, val)
|
||||
else:
|
||||
q = '[@%s]'%attr
|
||||
expr = '//'+tag + q
|
||||
return expr
|
||||
|
||||
class Wizard(QDialog):
|
||||
|
||||
def __init__(self, parent=None):
|
||||
QDialog.__init__(self, parent)
|
||||
self.resize(400, 300)
|
||||
self.verticalLayout = QVBoxLayout(self)
|
||||
self.widget = WizardWidget(self)
|
||||
self.verticalLayout.addWidget(self.widget)
|
||||
self.buttonBox = QDialogButtonBox(self)
|
||||
self.buttonBox.setOrientation(Qt.Horizontal)
|
||||
self.buttonBox.setStandardButtons(QDialogButtonBox.Cancel|QDialogButtonBox.Ok)
|
||||
self.verticalLayout.addWidget(self.buttonBox)
|
||||
|
||||
self.connect(self.buttonBox, SIGNAL("accepted()"), self.accept)
|
||||
self.connect(self.buttonBox, SIGNAL("rejected()"), self.reject)
|
||||
self.setModal(Qt.WindowModal)
|
||||
|
||||
@property
|
||||
def xpath(self):
|
||||
return self.widget.xpath
|
||||
|
||||
|
||||
class XPathEdit(QWidget, Ui_Edit):
|
||||
|
||||
def __init__(self, parent=None):
|
||||
QWidget.__init__(self, parent)
|
||||
self.setupUi(self)
|
||||
self.connect(self.button, SIGNAL('clicked()'), self.wizard)
|
||||
|
||||
def wizard(self):
|
||||
wiz = Wizard(self)
|
||||
if wiz.exec_() == wiz.Accepted:
|
||||
self.edit.setText(wiz.xpath)
|
||||
|
||||
|
||||
def set_msg(self, msg):
|
||||
self.msg.setText(msg)
|
||||
|
||||
@property
|
||||
def text(self):
|
||||
return unicode(self.edit.text())
|
||||
|
||||
def check(self):
|
||||
from calibre.ebooks.oeb.base import XPNSMAP
|
||||
from lxml.etree import XPath
|
||||
try:
|
||||
XPath(self.text, namespace=XPNSMAP)
|
||||
except:
|
||||
return False
|
||||
return True
|
||||
|
||||
|
||||
|
143
src/calibre/gui2/convert/xpath_wizard.ui
Normal file
143
src/calibre/gui2/convert/xpath_wizard.ui
Normal file
@ -0,0 +1,143 @@
|
||||
<ui version="4.0" >
|
||||
<class>Form</class>
|
||||
<widget class="QWidget" name="Form" >
|
||||
<property name="geometry" >
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>400</width>
|
||||
<height>381</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle" >
|
||||
<string>Form</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout" >
|
||||
<item row="0" column="0" colspan="2" >
|
||||
<widget class="QLabel" name="label" >
|
||||
<property name="text" >
|
||||
<string>Match HTML &tags with tag name:</string>
|
||||
</property>
|
||||
<property name="buddy" >
|
||||
<cstring>tag</cstring>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0" >
|
||||
<widget class="QComboBox" name="tag" >
|
||||
<property name="editable" >
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<item>
|
||||
<property name="text" >
|
||||
<string>*</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text" >
|
||||
<string>a</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text" >
|
||||
<string>br</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text" >
|
||||
<string>div</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text" >
|
||||
<string>h1</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text" >
|
||||
<string>h2</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text" >
|
||||
<string>h3</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text" >
|
||||
<string>h4</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text" >
|
||||
<string>h5</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text" >
|
||||
<string>h6</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text" >
|
||||
<string>hr</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text" >
|
||||
<string>span</string>
|
||||
</property>
|
||||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0" colspan="2" >
|
||||
<widget class="QLabel" name="label_2" >
|
||||
<property name="text" >
|
||||
<string>Having the &attribute:</string>
|
||||
</property>
|
||||
<property name="buddy" >
|
||||
<cstring>attribute</cstring>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="0" colspan="2" >
|
||||
<widget class="QLineEdit" name="attribute" />
|
||||
</item>
|
||||
<item row="4" column="0" >
|
||||
<widget class="QLabel" name="label_3" >
|
||||
<property name="text" >
|
||||
<string>With &value:</string>
|
||||
</property>
|
||||
<property name="buddy" >
|
||||
<cstring>value</cstring>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="0" >
|
||||
<widget class="QLineEdit" name="value" />
|
||||
</item>
|
||||
<item row="5" column="1" >
|
||||
<widget class="QLabel" name="label_4" >
|
||||
<property name="text" >
|
||||
<string>(A regular expression)</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="6" column="0" colspan="2" >
|
||||
<widget class="QLabel" name="label_5" >
|
||||
<property name="text" >
|
||||
<string><p>For example, to match all h2 tags that have class="chapter", set tag to <i>h2</i>, attribute to <i>class</i> and value to <i>chapter</i>.</p><p>Leaving attribute blank will match any attribute and leaving value blank will match any value. Setting tag to * will match any tag.</p><p>To learn more advanced usage of XPath see the <a href="http://calibre.kovidgoyal.net/user_manual/xpath.html">XPath Tutorial</a>.</string>
|
||||
</property>
|
||||
<property name="wordWrap" >
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="openExternalLinks" >
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
1385
src/calibre/gui2/images/wizard.svg
Normal file
1385
src/calibre/gui2/images/wizard.svg
Normal file
File diff suppressed because one or more lines are too long
After Width: | Height: | Size: 98 KiB |
@ -312,6 +312,8 @@ class gui(OptionlessCommand):
|
||||
dat = dat.replace('import images_rc', 'from calibre.gui2 import images_rc')
|
||||
dat = dat.replace('from library import', 'from calibre.gui2.library import')
|
||||
dat = dat.replace('from widgets import', 'from calibre.gui2.widgets import')
|
||||
dat = dat.replace('from convert.xpath_wizard import',
|
||||
'from calibre.gui2.convert.xpath_wizard import')
|
||||
dat = re.compile(r'QtGui.QApplication.translate\(.+?,\s+"(.+?)(?<!\\)",.+?\)', re.DOTALL).sub(r'_("\1")', dat)
|
||||
|
||||
# Workaround bug in Qt 4.4 on Windows
|
||||
|
Loading…
x
Reference in New Issue
Block a user