diff --git a/src/calibre/ebooks/oeb/polish/check/main.py b/src/calibre/ebooks/oeb/polish/check/main.py index 6aaeeed427..869f6ac39d 100644 --- a/src/calibre/ebooks/oeb/polish/check/main.py +++ b/src/calibre/ebooks/oeb/polish/check/main.py @@ -13,12 +13,13 @@ from calibre.ebooks.oeb.polish.container import guess_type from calibre.ebooks.oeb.polish.check.base import run_checkers from calibre.ebooks.oeb.polish.check.parsing import check_xml_parsing +XML_TYPES = frozenset(map(guess_type, ('a.xml', 'a.svg', 'a.opf', 'a.ncx'))) + def run_checks(container): errors = [] # Check parsing - XML_TYPES = frozenset(map(guess_type, ('a.xml', 'a.svg', 'a.opf', 'a.ncx'))) xml_items, html_items = [], [] for name, mt in container.mime_map.iteritems(): items = None @@ -33,3 +34,9 @@ def run_checks(container): return errors +def fix_errors(container, errors): + # Fix parsing + for name in {e.name for e in errors if getattr(e, 'is_parsing_error', False)}: + container.parsed(name) + container.dirty(name) + diff --git a/src/calibre/ebooks/oeb/polish/check/parsing.py b/src/calibre/ebooks/oeb/polish/check/parsing.py index 515632ed87..c34609f1ab 100644 --- a/src/calibre/ebooks/oeb/polish/check/parsing.py +++ b/src/calibre/ebooks/oeb/polish/check/parsing.py @@ -13,6 +13,8 @@ from calibre.ebooks.oeb.base import OEB_DOCS class XMLParseError(BaseError): + is_parsing_error = True + HELP = _('A parsing error in an XML file means that the XML syntax in the file is incorrect.' ' Such a file will most probably not open in an ebook reader. These errors can ' ' usually be fixed automatically, however, automatic fixing can sometimes ' diff --git a/src/calibre/gui2/tweak_book/boss.py b/src/calibre/gui2/tweak_book/boss.py index e21dfa0257..a418bc3d06 100644 --- a/src/calibre/gui2/tweak_book/boss.py +++ b/src/calibre/gui2/tweak_book/boss.py @@ -94,6 +94,7 @@ class Boss(QObject): self.gui.preview.link_clicked.connect(self.link_clicked) self.gui.check_book.item_activated.connect(self.check_item_activated) self.gui.check_book.check_requested.connect(self.check_requested) + self.gui.check_book.fix_requested.connect(self.fix_requested) def preferences(self): p = Preferences(self.gui) @@ -703,6 +704,17 @@ class Boss(QObject): c.parent().raise_() c.run_checks(current_container()) + @in_thread_job + def fix_requested(self): + self.commit_all_editors_to_container() + self.add_savepoint(_('Auto-fix errors')) + c = self.gui.check_book + c.parent().show() + c.parent().raise_() + c.fix_errors(current_container()) + self.apply_container_update_to_gui() + self.set_modified() + @in_thread_job def merge_requested(self, category, names, master): self.commit_all_editors_to_container() diff --git a/src/calibre/gui2/tweak_book/check.py b/src/calibre/gui2/tweak_book/check.py index 3d05b42113..d82b004909 100644 --- a/src/calibre/gui2/tweak_book/check.py +++ b/src/calibre/gui2/tweak_book/check.py @@ -13,7 +13,7 @@ from PyQt4.Qt import ( QListWidgetItem, pyqtSignal, QApplication, QStyledItemDelegate) from calibre.ebooks.oeb.polish.check.base import WARN, INFO, DEBUG, ERROR, CRITICAL -from calibre.ebooks.oeb.polish.check.main import run_checks +from calibre.ebooks.oeb.polish.check.main import run_checks, fix_errors from calibre.gui2.tweak_book import tprefs def icon_for_level(level): @@ -39,6 +39,7 @@ class Check(QSplitter): item_activated = pyqtSignal(object) check_requested = pyqtSignal() + fix_requested = pyqtSignal() def __init__(self, parent=None): QSplitter.__init__(self, parent) @@ -77,6 +78,8 @@ class Check(QSplitter): self.current_item_activated() elif url == 'run:check': self.check_requested.emit() + elif url == 'fix:errors': + self.fix_requested.emit() def next_error(self, delta=1): row = self.items.currentRow() @@ -106,10 +109,14 @@ class Check(QSplitter): if loc: loc = ' (%s)' % loc self.help.setText( - '''

%s

-
%s %s
+ '''

%s [%d]

+
%s %s

%s

- ''' % (header, _('Click to open in editor'), err.name, loc, err.HELP)) +
%s

+ %s
+ ''' % (header, self.items.currentRow()+1, _('Click to open in editor'), err.name, loc, err.HELP, + _('Try to fix all errors automatically. Only works for some types of error.'), _('Try fixing errors automatically'), + _('Re-run the check'), _('Re-run check'))) def run_checks(self, container): from calibre.gui2.tweak_book.boss import BusyCursor @@ -130,6 +137,15 @@ class Check(QSplitter): else: self.clear_help(_('No problems found')) + def fix_errors(self, container): + from calibre.gui2.tweak_book.boss import BusyCursor + with BusyCursor(): + errors = [self.items.item(i).data(Qt.UserRole).toPyObject() for i in xrange(self.items.count())] + self.show_busy(_('Running fixers, please wait...')) + QApplication.processEvents() + fix_errors(container, errors) + self.run_checks(container) + def show_busy(self, msg=_('Running checks, please wait...')): self.help.setText(msg) self.items.clear()