mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-09 03:04:10 -04:00
ToC Editor: Allow creating ToC from links in the book
This commit is contained in:
parent
97e632168b
commit
1f93448791
@ -39,6 +39,10 @@ class TOC(object):
|
|||||||
c.parent = self
|
c.parent = self
|
||||||
return c
|
return c
|
||||||
|
|
||||||
|
def remove(self, child):
|
||||||
|
self.children.remove(child)
|
||||||
|
child.parent = None
|
||||||
|
|
||||||
def __iter__(self):
|
def __iter__(self):
|
||||||
for c in self.children:
|
for c in self.children:
|
||||||
yield c
|
yield c
|
||||||
@ -191,6 +195,8 @@ def elem_to_toc_text(elem):
|
|||||||
text = elem.get('alt', '')
|
text = elem.get('alt', '')
|
||||||
text = re.sub(r'\s+', ' ', text.strip())
|
text = re.sub(r'\s+', ' ', text.strip())
|
||||||
text = text[:1000].strip()
|
text = text[:1000].strip()
|
||||||
|
if not text:
|
||||||
|
text = _('(Untitled)')
|
||||||
return text
|
return text
|
||||||
|
|
||||||
def from_xpaths(container, xpaths):
|
def from_xpaths(container, xpaths):
|
||||||
@ -229,6 +235,33 @@ def from_xpaths(container, xpaths):
|
|||||||
|
|
||||||
return tocroot
|
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):
|
def add_id(container, name, loc):
|
||||||
root = container.parsed(name)
|
root = container.parsed(name)
|
||||||
body = root.xpath('//*[local-name()="body"]')[0]
|
body = root.xpath('//*[local-name()="body"]')[0]
|
||||||
|
@ -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.container import get_container, AZW3Container
|
||||||
from calibre.ebooks.oeb.polish.toc import (
|
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 import Application, error_dialog, gprefs
|
||||||
from calibre.gui2.progress_indicator import ProgressIndicator
|
from calibre.gui2.progress_indicator import ProgressIndicator
|
||||||
from calibre.gui2.toc.location import ItemEdit
|
from calibre.gui2.toc.location import ItemEdit
|
||||||
@ -33,6 +33,7 @@ class ItemView(QFrame): # {{{
|
|||||||
flatten_item = pyqtSignal()
|
flatten_item = pyqtSignal()
|
||||||
go_to_root = pyqtSignal()
|
go_to_root = pyqtSignal()
|
||||||
create_from_xpath = pyqtSignal(object)
|
create_from_xpath = pyqtSignal(object)
|
||||||
|
create_from_links = pyqtSignal()
|
||||||
|
|
||||||
def __init__(self, parent):
|
def __init__(self, parent):
|
||||||
QFrame.__init__(self, parent)
|
QFrame.__init__(self, parent)
|
||||||
@ -79,7 +80,15 @@ class ItemView(QFrame): # {{{
|
|||||||
' heading tags. Uses the <h1-6> tags.')))
|
' heading tags. Uses the <h1-6> tags.')))
|
||||||
l.addWidget(b)
|
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()
|
l.addStretch()
|
||||||
self.w1 = la = QLabel(_('<b>WARNING:</b> calibre only supports the '
|
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)
|
self.item_view.delete_item.connect(self.delete_current_item)
|
||||||
i.add_new_item.connect(self.add_new_item)
|
i.add_new_item.connect(self.add_new_item)
|
||||||
i.create_from_xpath.connect(self.create_from_xpath)
|
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.flatten_item.connect(self.flatten_item)
|
||||||
i.go_to_root.connect(self.go_to_root)
|
i.go_to_root.connect(self.go_to_root)
|
||||||
l.addWidget(i, 0, 4, col, 1)
|
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)
|
_('No items were found that could be added to the Table of Contents.'), show=True)
|
||||||
self.insert_toc_fragment(toc)
|
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): # {{{
|
class TOCEditor(QDialog): # {{{
|
||||||
|
Loading…
x
Reference in New Issue
Block a user