diff --git a/manual/edit.rst b/manual/edit.rst index 3475b54a3d..bc92fb7ff4 100644 --- a/manual/edit.rst +++ b/manual/edit.rst @@ -433,9 +433,12 @@ the location you want, simply click and the split will be performed. Splitting the file will automatically update all links and references that pointed into the bottom half of the file and will open the newly split file in -an editor. If you want to repeatedly split a file, you can do that, and then -use the bulk renaming facility of the Files Browser, described above, to give -the split off files sensible names. +an editor. + +You can also split a single HTML file at multiple locations automatically, by +right clicking inside the file in the editor and choosing :guilabel:`Split at +multiple locations`. This will allow you to easily split a large file at all +heading tags or all tags having a certain class and so on. Miscellaneous Tools diff --git a/src/calibre/ebooks/oeb/polish/split.py b/src/calibre/ebooks/oeb/polish/split.py index 114133deca..a6d4124498 100644 --- a/src/calibre/ebooks/oeb/polish/split.py +++ b/src/calibre/ebooks/oeb/polish/split.py @@ -222,6 +222,34 @@ def split(container, name, loc_or_xpath, before=True): container.dirty(container.opf_name) return bottom_name +def multisplit(container, name, xpath, before=True): + root = container.parsed(name) + nodes = root.xpath(xpath, namespaces=XPNSMAP) + if not nodes: + raise AbortError(_('The expression %s did not match any nodes') % xpath) + for split_point in nodes: + if in_table(split_point): + raise AbortError('Cannot split inside tables') + if split_point.tag.endswith('}body'): + raise AbortError('Cannot split on the
tag') + + for i, tag in enumerate(nodes): + tag.set('calibre-split-point', str(i)) + + current = name + all_names = [name] + for i in xrange(len(nodes)): + current = split(container, current, '//*[@calibre-split-point="%d"]' % i, before=before) + all_names.append(current) + + for x in all_names: + for tag in container.parsed(x).xpath('//*[@calibre-split-point]'): + tag.attrib.pop('calibre-split-point') + container.dirty(x) + + return all_names[1:] + + class MergeLinkReplacer(object): def __init__(self, base, anchor_map, master, container): diff --git a/src/calibre/gui2/tweak_book/boss.py b/src/calibre/gui2/tweak_book/boss.py index 29f7cf821b..e114806730 100644 --- a/src/calibre/gui2/tweak_book/boss.py +++ b/src/calibre/gui2/tweak_book/boss.py @@ -22,7 +22,7 @@ from calibre.ebooks.oeb.polish.container import get_container as _gc, clone_cont from calibre.ebooks.oeb.polish.cover import mark_as_cover, mark_as_titlepage from calibre.ebooks.oeb.polish.pretty import fix_all_html, pretty_all from calibre.ebooks.oeb.polish.replace import rename_files, replace_file, get_recommended_folders, rationalize_folders -from calibre.ebooks.oeb.polish.split import split, merge, AbortError +from calibre.ebooks.oeb.polish.split import split, merge, AbortError, multisplit from calibre.ebooks.oeb.polish.toc import remove_names_from_toc, find_existing_toc from calibre.ebooks.oeb.polish.utils import link_stylesheets from calibre.gui2 import error_dialog, choose_files, question_dialog, info_dialog, choose_save_file @@ -36,7 +36,7 @@ from calibre.gui2.tweak_book.toc import TOCEditor from calibre.gui2.tweak_book.editor import editor_from_syntax, syntax_from_mime from calibre.gui2.tweak_book.editor.insert_resource import get_resource_data, NewBook from calibre.gui2.tweak_book.preferences import Preferences -from calibre.gui2.tweak_book.widgets import RationalizeFolders +from calibre.gui2.tweak_book.widgets import RationalizeFolders, MultiSplit def get_container(*args, **kwargs): kwargs['tweak_mode'] = True @@ -821,6 +821,29 @@ class Boss(QObject): self.apply_container_update_to_gui() self.edit_file(bottom_name, 'html') + def multisplit(self): + ed = self.gui.central.current_editor + if ed.syntax != 'html': + return + name = None + for n, x in editors.iteritems(): + if ed is x: + name = n + break + if name is None: + return + d = MultiSplit(self.gui) + if d.exec_() == d.Accepted: + with BusyCursor(): + self.commit_all_editors_to_container() + self.add_savepoint(_('Split %s') % self.gui.elided_text(name)) + try: + multisplit(current_container(), name, d.xpath) + except AbortError: + self.rewind_savepoint() + raise + self.apply_container_update_to_gui() + @in_thread_job def link_clicked(self, name, anchor): if not name: diff --git a/src/calibre/gui2/tweak_book/editor/widget.py b/src/calibre/gui2/tweak_book/editor/widget.py index b5f1b95997..f2be7e4119 100644 --- a/src/calibre/gui2/tweak_book/editor/widget.py +++ b/src/calibre/gui2/tweak_book/editor/widget.py @@ -268,6 +268,8 @@ class Editor(QMainWindow): m.addSeparator() m.addAction(_('&Select all'), self.editor.select_all) m.addAction(actions['mark-selected-text']) + if self.syntax == 'html': + m.addAction(actions['multisplit']) m.exec_(self.editor.mapToGlobal(pos)) diff --git a/src/calibre/gui2/tweak_book/ui.py b/src/calibre/gui2/tweak_book/ui.py index 3fa558a137..2bec7db44d 100644 --- a/src/calibre/gui2/tweak_book/ui.py +++ b/src/calibre/gui2/tweak_book/ui.py @@ -403,6 +403,9 @@ class Main(MainWindow): self.action_browse_images = reg( 'view-image.png', _('&Browse images in book'), self.boss.browse_images, 'browse-images', (), _( 'Browse images in the books visually')) + self.action_multiple_split = reg( + 'auto_author_sort.png', _('&Split at multiple locations'), self.boss.multisplit, 'multisplit', (), _( + 'Split HTML file at multiple locations')) def create_menubar(self): p, q = self.create_application_menubar() diff --git a/src/calibre/gui2/tweak_book/widgets.py b/src/calibre/gui2/tweak_book/widgets.py index c7a9ba0033..e2dc4824aa 100644 --- a/src/calibre/gui2/tweak_book/widgets.py +++ b/src/calibre/gui2/tweak_book/widgets.py @@ -6,8 +6,10 @@ from __future__ import (unicode_literals, division, absolute_import, __license__ = 'GPL v3' __copyright__ = '2014, Kovid Goyal