diff --git a/src/calibre/gui2/toc/main.py b/src/calibre/gui2/toc/main.py index a9c160a0d4..06ddc37eaa 100644 --- a/src/calibre/gui2/toc/main.py +++ b/src/calibre/gui2/toc/main.py @@ -22,10 +22,52 @@ from calibre.ebooks.oeb.polish.toc import ( from calibre.gui2 import Application, error_dialog, gprefs from calibre.gui2.progress_indicator import ProgressIndicator from calibre.gui2.toc.location import ItemEdit +from calibre.gui2.convert.xpath_wizard import XPathEdit from calibre.utils.logging import GUILog ICON_SIZE = 24 +class XPathDialog(QDialog): # {{{ + + def __init__(self, parent): + QDialog.__init__(self, parent) + self.setWindowTitle(_('Create ToC from XPath')) + self.l = l = QVBoxLayout() + self.setLayout(l) + self.la = la = QLabel(_( + 'Specify a series of XPath expressions for the different levels of' + ' the Table of Contents. You can use the wizard buttons to help' + ' you create XPath expressions.')) + la.setWordWrap(True) + l.addWidget(la) + self.widgets = [] + for i in xrange(5): + la = _('Level %s ToC:')%('&%d'%(i+1)) + xp = XPathEdit(self) + xp.set_msg(la) + self.widgets.append(xp) + l.addWidget(xp) + + self.bb = bb = QDialogButtonBox(QDialogButtonBox.Ok|QDialogButtonBox.Cancel) + bb.accepted.connect(self.accept) + bb.rejected.connect(self.reject) + l.addStretch() + l.addWidget(bb) + self.resize(self.sizeHint() + QSize(50, 75)) + + def accept(self): + for w in self.widgets: + if not w.check(): + return error_dialog(self, _('Invalid XPath'), + _('The XPath expression %s is not valid.')%w.xpath, + show=True) + super(XPathDialog, self).accept() + + @property + def xpaths(self): + return [w.xpath for w in self.widgets if w.xpath.strip()] +# }}} + class ItemView(QFrame): # {{{ add_new_item = pyqtSignal(object, object) @@ -90,6 +132,14 @@ class ItemView(QFrame): # {{{ ))) l.addWidget(b) + self.xpb = b = QPushButton(_('Generate ToC from &XPath')) + b.clicked.connect(self.create_from_user_xpath) + b.setToolTip(textwrap.fill(_( + 'Generate a Table of Contents from arbitrary XPath expressions.' + ))) + l.addWidget(b) + + l.addStretch() self.w1 = la = QLabel(_('WARNING: calibre only supports the ' 'creation of linear ToCs in AZW3 files. In a ' @@ -151,18 +201,20 @@ class ItemView(QFrame): # {{{ ip.b5 = b = QPushButton(QIcon(I('plus.png')), _('New entry &below this entry')) b.clicked.connect(partial(self.add_new, 'after')) l.addWidget(b, l.rowCount(), 0, 1, 2) - ip.hl4 = hl = QFrame() - hl.setFrameShape(hl.HLine) - l.addWidget(hl, l.rowCount(), 0, 1, 2) - l.setRowMinimumHeight(rs, 20) - # Flatten entry - rs = l.rowCount() ip.b3 = b = QPushButton(QIcon(I('heuristics.png')), _('&Flatten this entry')) b.clicked.connect(self.flatten_item) b.setToolTip(_('All children of this entry are brought to the same ' 'level as this entry.')) l.addWidget(b, l.rowCount()+1, 0, 1, 2) + + ip.hl4 = hl = QFrame() + hl.setFrameShape(hl.HLine) + l.addWidget(hl, l.rowCount(), 0, 1, 2) + l.setRowMinimumHeight(rs, 20) + + # Return to welcome + rs = l.rowCount() ip.b4 = b = QPushButton(QIcon(I('back.png')), _('&Return to welcome screen')) b.clicked.connect(self.go_to_root) b.setToolTip(_('Go back to the top level view')) @@ -183,6 +235,11 @@ class ItemView(QFrame): # {{{ def create_from_all_headings(self): self.create_from_xpath.emit(['//h:h%d'%i for i in xrange(1, 7)]) + def create_from_user_xpath(self): + d = XPathDialog(self) + if d.exec_() == d.Accepted and d.xpaths: + self.create_from_xpath.emit(d.xpaths) + def hide_azw3_warning(self): self.w1.setVisible(False), self.w2.setVisible(False)