ToC Editor: Allow creating ToC from links in the book

This commit is contained in:
Kovid Goyal 2013-03-20 17:00:41 +05:30
parent 97e632168b
commit 1f93448791
2 changed files with 52 additions and 2 deletions

View File

@ -39,6 +39,10 @@ class TOC(object):
c.parent = self
return c
def remove(self, child):
self.children.remove(child)
child.parent = None
def __iter__(self):
for c in self.children:
yield c
@ -191,6 +195,8 @@ def elem_to_toc_text(elem):
text = elem.get('alt', '')
text = re.sub(r'\s+', ' ', text.strip())
text = text[:1000].strip()
if not text:
text = _('(Untitled)')
return text
def from_xpaths(container, xpaths):
@ -229,6 +235,33 @@ def from_xpaths(container, xpaths):
return tocroot
def from_links(container):
toc = TOC()
link_path = XPath('//h:a[@href]')
seen_titles, seen_dests = set(), set()
for spinepath in container.spine_items:
name = container.abspath_to_name(spinepath)
root = container.parsed(name)
for a in link_path(root):
href = a.get('href')
if not href or not href.strip():
continue
dest = container.href_to_name(href, base=name)
frag = href.rpartition('#')[-1] or None
if (dest, frag) in seen_dests:
continue
seen_dests.add((dest, frag))
text = elem_to_toc_text(a)
if text in seen_titles:
continue
seen_titles.add(text)
toc.add(text, dest, frag=frag)
verify_toc_destinations(container, toc)
for child in toc:
if not child.dest_exists:
toc.remove(child)
return toc
def add_id(container, name, loc):
root = container.parsed(name)
body = root.xpath('//*[local-name()="body"]')[0]

View File

@ -18,7 +18,7 @@ from PyQt4.Qt import (QPushButton, QFrame, QVariant,
from calibre.ebooks.oeb.polish.container import get_container, AZW3Container
from calibre.ebooks.oeb.polish.toc import (
get_toc, add_id, TOC, commit_toc, from_xpaths)
get_toc, add_id, TOC, commit_toc, from_xpaths, from_links)
from calibre.gui2 import Application, error_dialog, gprefs
from calibre.gui2.progress_indicator import ProgressIndicator
from calibre.gui2.toc.location import ItemEdit
@ -33,6 +33,7 @@ class ItemView(QFrame): # {{{
flatten_item = pyqtSignal()
go_to_root = pyqtSignal()
create_from_xpath = pyqtSignal(object)
create_from_links = pyqtSignal()
def __init__(self, parent):
QFrame.__init__(self, parent)
@ -79,7 +80,15 @@ class ItemView(QFrame): # {{{
' heading tags. Uses the <h1-6> tags.')))
l.addWidget(b)
self.lb = b = QPushButton(_('Generate ToC from &links'))
b.clicked.connect(self.create_from_links)
b.setToolTip(textwrap.fill(_(
'Generate a Table of Contents from all the links in the book.'
' Links that point to destinations that do not exist in the book are'
' ignored. Also multiple links with the same destination or the same'
' text are ignored.'
)))
l.addWidget(b)
l.addStretch()
self.w1 = la = QLabel(_('<b>WARNING:</b> calibre only supports the '
@ -270,6 +279,7 @@ class TOCView(QWidget): # {{{
self.item_view.delete_item.connect(self.delete_current_item)
i.add_new_item.connect(self.add_new_item)
i.create_from_xpath.connect(self.create_from_xpath)
i.create_from_links.connect(self.create_from_links)
i.flatten_item.connect(self.flatten_item)
i.go_to_root.connect(self.go_to_root)
l.addWidget(i, 0, 4, col, 1)
@ -490,6 +500,13 @@ class TOCView(QWidget): # {{{
_('No items were found that could be added to the Table of Contents.'), show=True)
self.insert_toc_fragment(toc)
def create_from_links(self):
toc = from_links(self.ebook)
if len(toc) == 0:
return error_dialog(self, _('No items found'),
_('No links were found that could be added to the Table of Contents.'), show=True)
self.insert_toc_fragment(toc)
# }}}
class TOCEditor(QDialog): # {{{