mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-08-11 09:13:57 -04:00
Adding new entries to the ToC implemented
This commit is contained in:
parent
086ede3705
commit
4928433f75
@ -222,6 +222,10 @@ class Container(object):
|
|||||||
self.encoding_map[name] = self.used_encoding
|
self.encoding_map[name] = self.used_encoding
|
||||||
return ans
|
return ans
|
||||||
|
|
||||||
|
def replace(self, name, obj):
|
||||||
|
self.parsed_cache[name] = obj
|
||||||
|
self.dirty(name)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def opf(self):
|
def opf(self):
|
||||||
return self.parsed(self.opf_name)
|
return self.parsed(self.opf_name)
|
||||||
@ -417,12 +421,13 @@ class Container(object):
|
|||||||
data = re.sub(br'(<[/]{0,1})opf:', r'\1', data)
|
data = re.sub(br'(<[/]{0,1})opf:', r'\1', data)
|
||||||
return data
|
return data
|
||||||
|
|
||||||
def commit_item(self, name):
|
def commit_item(self, name, keep_parsed=False):
|
||||||
if name not in self.parsed_cache:
|
if name not in self.parsed_cache:
|
||||||
return
|
return
|
||||||
data = self.serialize_item(name)
|
data = self.serialize_item(name)
|
||||||
self.dirtied.remove(name)
|
self.dirtied.discard(name)
|
||||||
self.parsed_cache.pop(name)
|
if not keep_parsed:
|
||||||
|
self.parsed_cache.pop(name)
|
||||||
with open(self.name_path_map[name], 'wb') as f:
|
with open(self.name_path_map[name], 'wb') as f:
|
||||||
f.write(data)
|
f.write(data)
|
||||||
|
|
||||||
|
@ -7,17 +7,23 @@ __license__ = 'GPL v3'
|
|||||||
__copyright__ = '2013, Kovid Goyal <kovid at kovidgoyal.net>'
|
__copyright__ = '2013, Kovid Goyal <kovid at kovidgoyal.net>'
|
||||||
__docformat__ = 'restructuredtext en'
|
__docformat__ = 'restructuredtext en'
|
||||||
|
|
||||||
|
import re
|
||||||
from urlparse import urlparse
|
from urlparse import urlparse
|
||||||
|
from collections import deque
|
||||||
|
from functools import partial
|
||||||
|
|
||||||
from lxml import etree
|
from lxml import etree
|
||||||
|
|
||||||
from calibre.ebooks.oeb.base import XPath
|
from calibre import __version__
|
||||||
|
from calibre.ebooks.oeb.base import XPath, uuid_id, xml2text, NCX, NCX_NS, XML
|
||||||
from calibre.ebooks.oeb.polish.container import guess_type
|
from calibre.ebooks.oeb.polish.container import guess_type
|
||||||
|
from calibre.utils.localization import get_lang, canonicalize_lang, lang_as_iso639_1
|
||||||
|
|
||||||
ns = etree.FunctionNamespace('calibre_xpath_extensions')
|
ns = etree.FunctionNamespace('calibre_xpath_extensions')
|
||||||
ns.prefix = 'calibre'
|
ns.prefix = 'calibre'
|
||||||
ns['lower-case'] = lambda c, x: x.lower() if hasattr(x, 'lower') else x
|
ns['lower-case'] = lambda c, x: x.lower() if hasattr(x, 'lower') else x
|
||||||
|
|
||||||
|
|
||||||
class TOC(object):
|
class TOC(object):
|
||||||
|
|
||||||
def __init__(self, title=None, dest=None, frag=None):
|
def __init__(self, title=None, dest=None, frag=None):
|
||||||
@ -43,9 +49,18 @@ class TOC(object):
|
|||||||
for gc in child.iterdescendants():
|
for gc in child.iterdescendants():
|
||||||
yield gc
|
yield gc
|
||||||
|
|
||||||
|
@property
|
||||||
|
def depth(self):
|
||||||
|
"""The maximum depth of the navigation tree rooted at this node."""
|
||||||
|
try:
|
||||||
|
return max(node.depth for node in self) + 1
|
||||||
|
except ValueError:
|
||||||
|
return 1
|
||||||
|
|
||||||
def child_xpath(tag, name):
|
def child_xpath(tag, name):
|
||||||
return tag.xpath('./*[calibre:lower-case(local-name()) = "%s"]'%name)
|
return tag.xpath('./*[calibre:lower-case(local-name()) = "%s"]'%name)
|
||||||
|
|
||||||
|
|
||||||
def add_from_navpoint(container, navpoint, parent, ncx_name):
|
def add_from_navpoint(container, navpoint, parent, ncx_name):
|
||||||
dest = frag = text = None
|
dest = frag = text = None
|
||||||
nl = child_xpath(navpoint, 'navlabel')
|
nl = child_xpath(navpoint, 'navlabel')
|
||||||
@ -64,20 +79,32 @@ def add_from_navpoint(container, navpoint, parent, ncx_name):
|
|||||||
frag = urlparse(href).fragment or None
|
frag = urlparse(href).fragment or None
|
||||||
return parent.add(text or None, dest or None, frag or None)
|
return parent.add(text or None, dest or None, frag or None)
|
||||||
|
|
||||||
|
|
||||||
def process_ncx_node(container, node, toc_parent, ncx_name):
|
def process_ncx_node(container, node, toc_parent, ncx_name):
|
||||||
for navpoint in node.xpath('./*[calibre:lower-case(local-name()) = "navpoint"]'):
|
for navpoint in node.xpath('./*[calibre:lower-case(local-name()) = "navpoint"]'):
|
||||||
child = add_from_navpoint(container, navpoint, toc_parent, ncx_name)
|
child = add_from_navpoint(container, navpoint, toc_parent, ncx_name)
|
||||||
if child is not None:
|
if child is not None:
|
||||||
process_ncx_node(container, navpoint, child, ncx_name)
|
process_ncx_node(container, navpoint, child, ncx_name)
|
||||||
|
|
||||||
|
|
||||||
def parse_ncx(container, ncx_name):
|
def parse_ncx(container, ncx_name):
|
||||||
root = container.parsed(ncx_name)
|
root = container.parsed(ncx_name)
|
||||||
toc_root = TOC()
|
toc_root = TOC()
|
||||||
navmaps = root.xpath('//*[calibre:lower-case(local-name()) = "navmap"]')
|
navmaps = root.xpath('//*[calibre:lower-case(local-name()) = "navmap"]')
|
||||||
if navmaps:
|
if navmaps:
|
||||||
process_ncx_node(container, navmaps[0], toc_root, ncx_name)
|
process_ncx_node(container, navmaps[0], toc_root, ncx_name)
|
||||||
|
toc_root.lang = toc_root.uid = None
|
||||||
|
for attr, val in root.attrib.iteritems():
|
||||||
|
if attr.endswith('lang'):
|
||||||
|
toc_root.lang = unicode(val)
|
||||||
|
break
|
||||||
|
for uid in root.xpath('//*[calibre:lower-case(local-name()) = "meta" and @name="dtb:uid"]/@content'):
|
||||||
|
if uid:
|
||||||
|
toc_root.uid = unicode(uid)
|
||||||
|
break
|
||||||
return toc_root
|
return toc_root
|
||||||
|
|
||||||
|
|
||||||
def verify_toc_destinations(container, toc):
|
def verify_toc_destinations(container, toc):
|
||||||
anchor_map = {}
|
anchor_map = {}
|
||||||
anchor_xpath = XPath('//*/@id|//h:a/@name')
|
anchor_xpath = XPath('//*/@id|//h:a/@name')
|
||||||
@ -108,7 +135,8 @@ def verify_toc_destinations(container, toc):
|
|||||||
'The anchor %(a)s does not exist in file %(f)s')%dict(
|
'The anchor %(a)s does not exist in file %(f)s')%dict(
|
||||||
a=item.frag, f=name)
|
a=item.frag, f=name)
|
||||||
|
|
||||||
def get_toc(container, verify_destinations=True):
|
|
||||||
|
def find_existing_toc(container):
|
||||||
toc = container.opf_xpath('//opf:spine/@toc')
|
toc = container.opf_xpath('//opf:spine/@toc')
|
||||||
if toc:
|
if toc:
|
||||||
toc = container.manifest_id_map.get(toc[0], None)
|
toc = container.manifest_id_map.get(toc[0], None)
|
||||||
@ -117,9 +145,107 @@ def get_toc(container, verify_destinations=True):
|
|||||||
toc = container.manifest_type_map.get(ncx, [None])[0]
|
toc = container.manifest_type_map.get(ncx, [None])[0]
|
||||||
if not toc:
|
if not toc:
|
||||||
return None
|
return None
|
||||||
|
return toc
|
||||||
|
|
||||||
|
|
||||||
|
def get_toc(container, verify_destinations=True):
|
||||||
|
toc = find_existing_toc(container)
|
||||||
|
if toc is None:
|
||||||
|
ans = TOC()
|
||||||
|
ans.lang = ans.uid = None
|
||||||
|
return ans
|
||||||
ans = parse_ncx(container, toc)
|
ans = parse_ncx(container, toc)
|
||||||
if verify_destinations:
|
if verify_destinations:
|
||||||
verify_toc_destinations(container, ans)
|
verify_toc_destinations(container, ans)
|
||||||
return ans
|
return ans
|
||||||
|
|
||||||
|
|
||||||
|
def add_id(container, name, loc):
|
||||||
|
root = container.parsed(name)
|
||||||
|
body = root.xpath('//*[local-name()="body"]')[0]
|
||||||
|
locs = deque(loc)
|
||||||
|
node = body
|
||||||
|
while locs:
|
||||||
|
children = tuple(node.iterchildren(etree.Element))
|
||||||
|
node = children[locs[0]]
|
||||||
|
locs.popleft()
|
||||||
|
node.set('id', node.get('id', uuid_id()))
|
||||||
|
container.commit_item(name, keep_parsed=True)
|
||||||
|
return node.get('id')
|
||||||
|
|
||||||
|
|
||||||
|
def create_ncx(toc, to_href, btitle, lang, uid):
|
||||||
|
lang = lang.replace('_', '-')
|
||||||
|
ncx = etree.Element(NCX('ncx'),
|
||||||
|
attrib={'version': '2005-1', XML('lang'): lang},
|
||||||
|
nsmap={None: NCX_NS})
|
||||||
|
head = etree.SubElement(ncx, NCX('head'))
|
||||||
|
etree.SubElement(head, NCX('meta'),
|
||||||
|
name='dtb:uid', content=unicode(uid))
|
||||||
|
etree.SubElement(head, NCX('meta'),
|
||||||
|
name='dtb:depth', content=str(toc.depth))
|
||||||
|
generator = ''.join(['calibre (', __version__, ')'])
|
||||||
|
etree.SubElement(head, NCX('meta'),
|
||||||
|
name='dtb:generator', content=generator)
|
||||||
|
etree.SubElement(head, NCX('meta'), name='dtb:totalPageCount', content='0')
|
||||||
|
etree.SubElement(head, NCX('meta'), name='dtb:maxPageNumber', content='0')
|
||||||
|
title = etree.SubElement(ncx, NCX('docTitle'))
|
||||||
|
text = etree.SubElement(title, NCX('text'))
|
||||||
|
text.text = btitle
|
||||||
|
navmap = etree.SubElement(ncx, NCX('navMap'))
|
||||||
|
spat = re.compile(r'\s+')
|
||||||
|
|
||||||
|
def process_node(xml_parent, toc_parent, play_order=0):
|
||||||
|
for child in toc_parent:
|
||||||
|
play_order += 1
|
||||||
|
point = etree.SubElement(xml_parent, NCX('navPoint'), id=uuid_id(),
|
||||||
|
playOrder=str(play_order))
|
||||||
|
label = etree.SubElement(point, NCX('navLabel'))
|
||||||
|
title = child.title
|
||||||
|
if title:
|
||||||
|
title = spat.sub(' ', title)
|
||||||
|
etree.SubElement(label, NCX('text')).text = title
|
||||||
|
if child.dest:
|
||||||
|
href = to_href(child.dest)
|
||||||
|
if child.frag:
|
||||||
|
href += '#'+child.frag
|
||||||
|
etree.SubElement(point, NCX('content'), src=href)
|
||||||
|
process_node(point, child, play_order)
|
||||||
|
|
||||||
|
process_node(navmap, toc)
|
||||||
|
return ncx
|
||||||
|
|
||||||
|
|
||||||
|
def commit_toc(container, toc, lang=None, uid=None):
|
||||||
|
tocname = find_existing_toc(container)
|
||||||
|
if tocname is None:
|
||||||
|
item = container.generate_item('toc.ncx', id_prefix='toc')
|
||||||
|
tocname = container.href_to_name(item.get('href'),
|
||||||
|
base=container.opf_name)
|
||||||
|
if not lang:
|
||||||
|
lang = get_lang()
|
||||||
|
for l in container.opf_xpath('//dc:language'):
|
||||||
|
l = canonicalize_lang(xml2text(l).strip())
|
||||||
|
if l:
|
||||||
|
lang = l
|
||||||
|
lang = lang_as_iso639_1(l) or l
|
||||||
|
break
|
||||||
|
lang = lang_as_iso639_1(lang) or lang
|
||||||
|
if not uid:
|
||||||
|
uid = uuid_id()
|
||||||
|
eid = container.opf.get('unique-identifier', None)
|
||||||
|
if eid:
|
||||||
|
m = container.opf_xpath('//*[@id="%s"]'%eid)
|
||||||
|
if m:
|
||||||
|
uid = xml2text(m[0])
|
||||||
|
|
||||||
|
title = _('Table of Contents')
|
||||||
|
m = container.opf_xpath('//dc:title')
|
||||||
|
if m:
|
||||||
|
x = xml2text(m[0]).strip()
|
||||||
|
title = x or title
|
||||||
|
|
||||||
|
to_href = partial(container.name_to_href, base=tocname)
|
||||||
|
root = create_ncx(toc, to_href, title, lang, uid)
|
||||||
|
container.replace(tocname, root)
|
||||||
|
|
||||||
|
@ -131,15 +131,14 @@ class ItemEdit(QWidget):
|
|||||||
la.setWordWrap(True)
|
la.setWordWrap(True)
|
||||||
l.addWidget(la)
|
l.addWidget(la)
|
||||||
|
|
||||||
f.la2 = la = QLabel(_('&Name of the ToC entry:'))
|
f.la2 = la = QLabel('<b>'+_('&Name of the ToC entry:'))
|
||||||
l.addWidget(la)
|
l.addWidget(la)
|
||||||
self.name = QLineEdit(self)
|
self.name = QLineEdit(self)
|
||||||
la.setBuddy(self.name)
|
la.setBuddy(self.name)
|
||||||
l.addWidget(self.name)
|
l.addWidget(self.name)
|
||||||
|
|
||||||
self.base_msg = _('Currently selected destination:')
|
self.base_msg = '<b>'+_('Currently selected destination:')+'</b>'
|
||||||
self.dest_label = la = QLabel(self.base_msg)
|
self.dest_label = la = QLabel(self.base_msg)
|
||||||
la.setTextFormat(Qt.PlainText)
|
|
||||||
la.setWordWrap(True)
|
la.setWordWrap(True)
|
||||||
la.setStyleSheet('QLabel { margin-top: 20px }')
|
la.setStyleSheet('QLabel { margin-top: 20px }')
|
||||||
l.addWidget(la)
|
l.addWidget(la)
|
||||||
@ -163,8 +162,8 @@ class ItemEdit(QWidget):
|
|||||||
load_html(path, self.view, codec=encoding,
|
load_html(path, self.view, codec=encoding,
|
||||||
mime_type=self.container.mime_map[name])
|
mime_type=self.container.mime_map[name])
|
||||||
self.view.load_js()
|
self.view.load_js()
|
||||||
self.dest_label.setText(self.base_msg + '\n' + _('File:') + ' ' +
|
self.dest_label.setText(self.base_msg + '<br>' + _('File:') + ' ' +
|
||||||
name + '\n' + _('Top of the file'))
|
name + '<br>' + _('Top of the file'))
|
||||||
|
|
||||||
def __call__(self, item, where):
|
def __call__(self, item, where):
|
||||||
self.current_item, self.current_where = item, where
|
self.current_item, self.current_where = item, where
|
||||||
@ -173,23 +172,22 @@ class ItemEdit(QWidget):
|
|||||||
if item is None:
|
if item is None:
|
||||||
self.dest_list.setCurrentRow(0)
|
self.dest_list.setCurrentRow(0)
|
||||||
self.name.setText(_('(Untitled)'))
|
self.name.setText(_('(Untitled)'))
|
||||||
self.dest_label.setText(self.base_msg + '\n' + _('None'))
|
|
||||||
|
|
||||||
def elem_clicked(self, tag, frac, elem_id, loc):
|
def elem_clicked(self, tag, frac, elem_id, loc):
|
||||||
self.current_frag = elem_id or loc
|
self.current_frag = elem_id or loc
|
||||||
frac = int(round(frac * 100))
|
frac = int(round(frac * 100))
|
||||||
base = _('Location: A <%s> tag inside the file')%tag
|
base = _('Location: A <%s> tag inside the file')%tag
|
||||||
if frac == 0:
|
if frac == 0:
|
||||||
loctext = _('Top of the file')
|
loctext = _('Top of the file')
|
||||||
else:
|
else:
|
||||||
loctext = _('Approximately %d%% from the top')%frac
|
loctext = _('Approximately %d%% from the top')%frac
|
||||||
loctext = base + ' [%s]'%loctext
|
loctext = base + ' [%s]'%loctext
|
||||||
self.dest_label.setText(self.base_msg + '\n' +
|
self.dest_label.setText(self.base_msg + '<br>' +
|
||||||
_('File:') + ' ' + self.current_name + '\n' + loctext)
|
_('File:') + ' ' + self.current_name + '<br>' + loctext)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def result(self):
|
def result(self):
|
||||||
return (self.current_item, self.current_where, self.current_name,
|
return (self.current_item, self.current_where, self.current_name,
|
||||||
self.current_frag)
|
self.current_frag, unicode(self.name.text()))
|
||||||
|
|
||||||
|
|
||||||
|
@ -16,7 +16,7 @@ from PyQt4.Qt import (QPushButton, QFrame,
|
|||||||
QToolButton, QItemSelectionModel)
|
QToolButton, QItemSelectionModel)
|
||||||
|
|
||||||
from calibre.ebooks.oeb.polish.container import get_container
|
from calibre.ebooks.oeb.polish.container import get_container
|
||||||
from calibre.ebooks.oeb.polish.toc import get_toc
|
from calibre.ebooks.oeb.polish.toc import get_toc, add_id, TOC, commit_toc
|
||||||
from calibre.gui2 import Application
|
from calibre.gui2 import Application
|
||||||
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
|
||||||
@ -191,43 +191,50 @@ class TOCView(QWidget): # {{{
|
|||||||
|
|
||||||
def update_status_tip(self, item):
|
def update_status_tip(self, item):
|
||||||
c = item.data(0, Qt.UserRole).toPyObject()
|
c = item.data(0, Qt.UserRole).toPyObject()
|
||||||
frag = c.frag or ''
|
if c is not None:
|
||||||
if frag:
|
frag = c.frag or ''
|
||||||
frag = '#'+frag
|
if frag:
|
||||||
item.setStatusTip(0, _('<b>Title</b>: {0} <b>Dest</b>: {1}{2}').format(
|
frag = '#'+frag
|
||||||
c.title, c.dest, frag))
|
item.setStatusTip(0, _('<b>Title</b>: {0} <b>Dest</b>: {1}{2}').format(
|
||||||
|
c.title, c.dest, frag))
|
||||||
|
|
||||||
def data_changed(self, top_left, bottom_right):
|
def data_changed(self, top_left, bottom_right):
|
||||||
for r in xrange(top_left.row(), bottom_right.row()+1):
|
for r in xrange(top_left.row(), bottom_right.row()+1):
|
||||||
idx = self.tocw.model().index(r, 0, top_left.parent())
|
idx = self.tocw.model().index(r, 0, top_left.parent())
|
||||||
new_title = unicode(idx.data(Qt.DisplayRole).toString()).strip()
|
new_title = unicode(idx.data(Qt.DisplayRole).toString()).strip()
|
||||||
toc = idx.data(Qt.UserRole).toPyObject()
|
toc = idx.data(Qt.UserRole).toPyObject()
|
||||||
toc.title = new_title or _('(Untitled)')
|
if toc is not None:
|
||||||
|
toc.title = new_title or _('(Untitled)')
|
||||||
item = self.tocw.itemFromIndex(idx)
|
item = self.tocw.itemFromIndex(idx)
|
||||||
self.update_status_tip(item)
|
self.update_status_tip(item)
|
||||||
|
|
||||||
|
def create_item(self, parent, child):
|
||||||
|
c = QTreeWidgetItem(parent)
|
||||||
|
c.setData(0, Qt.DisplayRole, child.title or _('(Untitled)'))
|
||||||
|
c.setData(0, Qt.UserRole, child)
|
||||||
|
c.setFlags(Qt.ItemIsDragEnabled|Qt.ItemIsEditable|Qt.ItemIsEnabled|
|
||||||
|
Qt.ItemIsSelectable|Qt.ItemIsDropEnabled)
|
||||||
|
c.setData(0, Qt.DecorationRole, self.icon_map[child.dest_exists])
|
||||||
|
if child.dest_exists is False:
|
||||||
|
c.setData(0, Qt.ToolTipRole, _(
|
||||||
|
'The location this entry point to does not exist:\n%s')
|
||||||
|
%child.dest_error)
|
||||||
|
|
||||||
|
self.update_status_tip(c)
|
||||||
|
return c
|
||||||
|
|
||||||
def __call__(self, ebook):
|
def __call__(self, ebook):
|
||||||
self.ebook = ebook
|
self.ebook = ebook
|
||||||
self.toc = get_toc(self.ebook)
|
self.toc = get_toc(self.ebook)
|
||||||
blank = self.blank = QIcon(I('blank.png'))
|
self.toc_lang, self.toc_uid = self.toc.lang, self.toc.uid
|
||||||
ok = self.ok = QIcon(I('ok.png'))
|
self.blank = QIcon(I('blank.png'))
|
||||||
err = self.err = QIcon(I('dot_red.png'))
|
self.ok = QIcon(I('ok.png'))
|
||||||
icon_map = {None:blank, True:ok, False:err}
|
self.err = QIcon(I('dot_red.png'))
|
||||||
|
self.icon_map = {None:self.blank, True:self.ok, False:self.err}
|
||||||
|
|
||||||
def process_item(node, parent):
|
def process_item(toc_node, parent):
|
||||||
for child in node:
|
for child in toc_node:
|
||||||
c = QTreeWidgetItem(parent)
|
c = self.create_item(parent, child)
|
||||||
c.setData(0, Qt.DisplayRole, child.title or _('(Untitled)'))
|
|
||||||
c.setData(0, Qt.UserRole, child)
|
|
||||||
c.setFlags(Qt.ItemIsDragEnabled|Qt.ItemIsEditable|Qt.ItemIsEnabled|
|
|
||||||
Qt.ItemIsSelectable|Qt.ItemIsDropEnabled)
|
|
||||||
c.setData(0, Qt.DecorationRole, icon_map[child.dest_exists])
|
|
||||||
if child.dest_exists is False:
|
|
||||||
c.setData(0, Qt.ToolTipRole, _(
|
|
||||||
'The location this entry point to does not exist:\n%s')
|
|
||||||
%child.dest_error)
|
|
||||||
|
|
||||||
self.update_status_tip(c)
|
|
||||||
process_item(child, c)
|
process_item(child, c)
|
||||||
|
|
||||||
root = self.root = self.tocw.invisibleRootItem()
|
root = self.root = self.tocw.invisibleRootItem()
|
||||||
@ -235,10 +242,38 @@ class TOCView(QWidget): # {{{
|
|||||||
process_item(self.toc, root)
|
process_item(self.toc, root)
|
||||||
self.tocw.model().dataChanged.connect(self.data_changed)
|
self.tocw.model().dataChanged.connect(self.data_changed)
|
||||||
self.tocw.currentItemChanged.connect(self.current_item_changed)
|
self.tocw.currentItemChanged.connect(self.current_item_changed)
|
||||||
|
self.tocw.setCurrentItem(None)
|
||||||
|
|
||||||
def current_item_changed(self, current, previous):
|
def current_item_changed(self, current, previous):
|
||||||
self.item_view(current)
|
self.item_view(current)
|
||||||
|
|
||||||
|
def update_item(self, item, where, name, frag, title):
|
||||||
|
if isinstance(frag, tuple):
|
||||||
|
frag = add_id(self.ebook, name, frag)
|
||||||
|
if item is None:
|
||||||
|
if where is None:
|
||||||
|
where = self.tocw.invisibleRootItem()
|
||||||
|
child = TOC(title, name, frag)
|
||||||
|
child.dest_exists = True
|
||||||
|
c = self.create_item(where, child)
|
||||||
|
self.tocw.setCurrentItem(c, 0, QItemSelectionModel.ClearAndSelect)
|
||||||
|
self.tocw.scrollToItem(c)
|
||||||
|
|
||||||
|
def create_toc(self):
|
||||||
|
root = TOC()
|
||||||
|
|
||||||
|
def process_node(parent, toc_parent):
|
||||||
|
for i in xrange(parent.childCount()):
|
||||||
|
item = parent.child(i)
|
||||||
|
title = unicode(item.data(0, Qt.DisplayRole).toString()).strip()
|
||||||
|
toc = item.data(0, Qt.UserRole).toPyObject()
|
||||||
|
dest, frag = toc.dest, toc.frag
|
||||||
|
toc = toc_parent.add(title, dest, frag)
|
||||||
|
process_node(item, toc)
|
||||||
|
|
||||||
|
process_node(self.tocw.invisibleRootItem(), root)
|
||||||
|
return root
|
||||||
|
|
||||||
# }}}
|
# }}}
|
||||||
|
|
||||||
class TOCEditor(QDialog): # {{{
|
class TOCEditor(QDialog): # {{{
|
||||||
@ -283,6 +318,7 @@ class TOCEditor(QDialog): # {{{
|
|||||||
self.explode_done.connect(self.read_toc, type=Qt.QueuedConnection)
|
self.explode_done.connect(self.read_toc, type=Qt.QueuedConnection)
|
||||||
|
|
||||||
self.resize(950, 630)
|
self.resize(950, 630)
|
||||||
|
self.working = True
|
||||||
|
|
||||||
def add_new_item(self, item, where):
|
def add_new_item(self, item, where):
|
||||||
self.item_edit(item, where)
|
self.item_edit(item, where)
|
||||||
@ -290,15 +326,18 @@ class TOCEditor(QDialog): # {{{
|
|||||||
|
|
||||||
def accept(self):
|
def accept(self):
|
||||||
if self.stacks.currentIndex() == 2:
|
if self.stacks.currentIndex() == 2:
|
||||||
self.toc_view.update_item(self.item_edit.result)
|
self.toc_view.update_item(*self.item_edit.result)
|
||||||
self.stacks.setCurrentIndex(1)
|
self.stacks.setCurrentIndex(1)
|
||||||
else:
|
else:
|
||||||
|
self.write_toc()
|
||||||
|
self.working = False
|
||||||
super(TOCEditor, self).accept()
|
super(TOCEditor, self).accept()
|
||||||
|
|
||||||
def reject(self):
|
def reject(self):
|
||||||
if self.stacks.currentIndex() == 2:
|
if self.stacks.currentIndex() == 2:
|
||||||
self.stacks.setCurrentIndex(1)
|
self.stacks.setCurrentIndex(1)
|
||||||
else:
|
else:
|
||||||
|
self.working = False
|
||||||
super(TOCEditor, self).accept()
|
super(TOCEditor, self).accept()
|
||||||
|
|
||||||
def start(self):
|
def start(self):
|
||||||
@ -309,9 +348,8 @@ class TOCEditor(QDialog): # {{{
|
|||||||
|
|
||||||
def explode(self):
|
def explode(self):
|
||||||
self.ebook = get_container(self.pathtobook, log=self.log)
|
self.ebook = get_container(self.pathtobook, log=self.log)
|
||||||
if not self.isVisible():
|
if self.working:
|
||||||
return
|
self.explode_done.emit()
|
||||||
self.explode_done.emit()
|
|
||||||
|
|
||||||
def read_toc(self):
|
def read_toc(self):
|
||||||
self.pi.stopAnimation()
|
self.pi.stopAnimation()
|
||||||
@ -319,6 +357,12 @@ class TOCEditor(QDialog): # {{{
|
|||||||
self.item_edit.load(self.ebook)
|
self.item_edit.load(self.ebook)
|
||||||
self.stacks.setCurrentIndex(1)
|
self.stacks.setCurrentIndex(1)
|
||||||
|
|
||||||
|
def write_toc(self):
|
||||||
|
toc = self.toc_view.create_toc()
|
||||||
|
commit_toc(self.ebook, toc, lang=self.toc_view.toc_lang,
|
||||||
|
uid=self.toc_view.toc_uid)
|
||||||
|
self.ebook.commit()
|
||||||
|
|
||||||
# }}}
|
# }}}
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
|
Loading…
x
Reference in New Issue
Block a user