Ejemplo n.º 1
0
    def __init__(self, derrors, parent=None):
        QDialog.__init__(self, parent=parent)

        self.setWindowFlags(Qt.Window)
        self.derrors = derrors

        buttonBox = QDialogButtonBox(QDialogButtonBox.Close)

        browser = QTextBrowser()
        browser.setText('')
        browser.setFontFamily("Courier")
        browser.setFontWeight(QFont.Bold)
        browser.setLineWrapMode(QTextBrowser.NoWrap)
        browser.setReadOnly(True)

        self.ctc_button = QPushButton('Copy to clipboard')
        self.ctc_button.setMaximumWidth(100)

        gpbox2 = QGroupBox()
        lay2 = QHBoxLayout()
        gpbox2.setLayout(lay2)
        lay2.addWidget(browser)
        gpbox2.setMinimumHeight(500)
        gpbox2.setMinimumWidth(1000)

        lay = QVBoxLayout()
        self.setLayout(lay)
        lay.addWidget(gpbox2)
        lay.addWidget(self.ctc_button)
        lay.addWidget(buttonBox)

        buttonBox.rejected.connect(self.reject)
        self.ctc_button.clicked.connect(self.copy_to_clipboard)

        self.setWindowTitle('%s: Calibre error checks' % CAPTION)

        if 'scramb' in self.derrors:
            msg = 'Original vs. After scrambling'
        else:
            msg = 'Original - ebook not yet scrambled'

        gpbox2.setTitle(msg)

        self.report = self.summarise_errors()
        browser.setText(self.report)
Ejemplo n.º 2
0
    def __init__(self, metadata, parent=None):
        QDialog.__init__(self, parent=parent)

        self.setWindowFlags(Qt.Window)

        buttonBox = QDialogButtonBox(QDialogButtonBox.Close)

        origbrowser = QTextBrowser()
        origbrowser.setText('')
        origbrowser.setReadOnly(True)

        browser = QTextBrowser()
        browser.setText('')
        browser.setReadOnly(True)

        gpbox2 = QGroupBox('Metadata: Original')
        lay2 = QHBoxLayout()
        gpbox2.setLayout(lay2)
        lay2.addWidget(origbrowser)

        gpbox4 = QGroupBox('Metadata: After scrambling')
        lay4 = QHBoxLayout()
        gpbox4.setLayout(lay4)
        lay4.addWidget(browser)

        splitter = QSplitter(Qt.Horizontal)
        splitter.addWidget(gpbox2)
        splitter.addWidget(gpbox4)
        splitter.setMinimumHeight(500)
        splitter.setMinimumWidth(1000)

        lay = QVBoxLayout()
        self.setLayout(lay)
        lay.addWidget(splitter)
        lay.addWidget(buttonBox)

        # create connect signals/slots
        buttonBox.rejected.connect(self.reject)

        metaorig = metadata.get('orig', '')
        metaorig = re.sub(r'\n\s*', r'\n     ', metaorig)
        origbrowser.setText(metaorig)
        browser.setText(metadata.get('scramb', ''))

        self.setWindowTitle('%s: Metadata' % CAPTION)
        if not 'scramb' in metadata:
            gpbox4.setVisible(False)
Ejemplo n.º 3
0
class CheckExternalLinks(Dialog):

    progress_made = pyqtSignal(object, object)

    def __init__(self, parent=None):
        Dialog.__init__(self, _('Check external links'),
                        'check-external-links-dialog', parent)
        self.progress_made.connect(self.on_progress_made,
                                   type=Qt.QueuedConnection)

    def show(self):
        if self.rb.isEnabled():
            self.refresh()
        return Dialog.show(self)

    def refresh(self):
        self.stack.setCurrentIndex(0)
        self.rb.setEnabled(False)
        t = Thread(name='CheckLinksMaster', target=self.run)
        t.daemon = True
        t.start()

    def setup_ui(self):
        self.pb = pb = QProgressBar(self)
        pb.setTextVisible(True)
        pb.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed)
        pb.setRange(0, 0)
        self.w = w = QWidget(self)
        self.w.l = l = QVBoxLayout(w)
        l.addStretch(), l.addWidget(pb)
        self.w.la = la = QLabel(_('Checking external links, please wait...'))
        la.setStyleSheet('QLabel { font-size: 20px; font-weight: bold }')
        l.addWidget(la, 0, Qt.AlignCenter), l.addStretch()

        self.l = l = QVBoxLayout(self)
        self.results = QTextBrowser(self)
        self.results.setOpenLinks(False)
        self.results.anchorClicked.connect(self.anchor_clicked)
        self.stack = s = QStackedWidget(self)
        s.addWidget(w), s.addWidget(self.results)
        l.addWidget(s)
        self.bh = h = QHBoxLayout()
        self.check_anchors = ca = QCheckBox(_('Check &anchors'))
        ca.setToolTip(
            _('Check HTML anchors in links (the part after the #).\n'
              ' This can be a little slow, since it requires downloading and parsing all the HTML pages.'
              ))
        ca.setChecked(tprefs.get('check_external_link_anchors', True))
        ca.stateChanged.connect(self.anchors_changed)
        h.addWidget(ca), h.addStretch(100), h.addWidget(self.bb)
        l.addLayout(h)
        self.bb.setStandardButtons(self.bb.Close)
        self.rb = b = self.bb.addButton(_('&Refresh'), self.bb.ActionRole)
        b.setIcon(QIcon(I('view-refresh.png')))
        b.clicked.connect(self.refresh)

    def anchors_changed(self):
        tprefs.set('check_external_link_anchors',
                   self.check_anchors.isChecked())

    def sizeHint(self):
        ans = Dialog.sizeHint(self)
        ans.setHeight(600)
        ans.setWidth(max(ans.width(), 800))
        return ans

    def run(self):
        from calibre.ebooks.oeb.polish.check.links import check_external_links
        self.tb = None
        self.errors = []
        try:
            self.errors = check_external_links(
                current_container(),
                self.progress_made.emit,
                check_anchors=self.check_anchors.isChecked())
        except Exception:
            import traceback
            self.tb = traceback.format_exc()
        self.progress_made.emit(None, None)

    def on_progress_made(self, curr, total):
        if curr is None:
            self.results.setText('')
            self.stack.setCurrentIndex(1)
            self.fixed_errors = set()
            self.rb.setEnabled(True)
            if self.tb is not None:
                return error_dialog(
                    self,
                    _('Checking failed'),
                    _('There was an error while checking links, click "Show details" for more information'
                      ),
                    det_msg=self.tb,
                    show=True)
            if not self.errors:
                self.results.setText(_('No broken links found'))
            else:
                self.populate_results()
        else:
            self.pb.setMaximum(total), self.pb.setValue(curr)

    def populate_results(self, preserve_pos=False):
        num = len(self.errors) - len(self.fixed_errors)
        text = '<h3>%s</h3><ol>' % (ngettext(
            'Found a broken link', 'Found {} broken links', num).format(num))
        for i, (locations, err, url) in enumerate(self.errors):
            if i in self.fixed_errors:
                continue
            text += '<li><b>%s</b> \xa0<a href="err:%d">[%s]</a><br>%s<br><ul>' % (
                url, i, _('Fix this link'), err)
            for name, href, lnum, col in locations:
                text += '<li>{name} \xa0<a href="loc:{lnum},{name}">[{line}: {lnum}]</a></li>'.format(
                    name=name, lnum=lnum, line=_('line number'))
            text += '</ul></li><hr>'
        self.results.setHtml(text)

    def anchor_clicked(self, qurl):
        url = qurl.toString()
        if url.startswith('err:'):
            errnum = int(url[4:])
            err = self.errors[errnum]
            newurl, ok = QInputDialog.getText(self,
                                              _('Fix URL'),
                                              _('Enter the corrected URL:') +
                                              '\xa0' * 40,
                                              text=err[2])
            if not ok:
                return
            nmap = defaultdict(set)
            for name, href in {(l[0], l[1]) for l in err[0]}:
                nmap[name].add(href)

            for name, hrefs in nmap.iteritems():
                raw = oraw = get_data(name)
                for href in hrefs:
                    raw = raw.replace(href, newurl)
                if raw != oraw:
                    set_data(name, raw)
            self.fixed_errors.add(errnum)
            self.populate_results()
        elif url.startswith('loc:'):
            lnum, name = url[4:].partition(',')[::2]
            lnum = int(lnum or 1)
            editor = get_boss().edit_file(name)
            if lnum and editor is not None and editor.has_line_numbers:
                editor.current_line = lnum
Ejemplo n.º 4
0
class CheckExternalLinks(Dialog):

    progress_made = pyqtSignal(object, object)

    def __init__(self, parent=None):
        Dialog.__init__(self, _('Check external links'), 'check-external-links-dialog', parent)
        self.progress_made.connect(self.on_progress_made, type=Qt.QueuedConnection)

    def show(self):
        if self.rb.isEnabled():
            self.refresh()
        return Dialog.show(self)

    def refresh(self):
        self.stack.setCurrentIndex(0)
        self.rb.setEnabled(False)
        t = Thread(name='CheckLinksMaster', target=self.run)
        t.daemon = True
        t.start()

    def setup_ui(self):
        self.pb = pb = QProgressBar(self)
        pb.setTextVisible(True)
        pb.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed)
        pb.setRange(0, 0)
        self.w = w = QWidget(self)
        self.w.l = l = QVBoxLayout(w)
        l.addStretch(), l.addWidget(pb)
        self.w.la = la = QLabel(_('Checking external links, please wait...'))
        la.setStyleSheet('QLabel { font-size: 20px; font-weight: bold }')
        l.addWidget(la, 0, Qt.AlignCenter), l.addStretch()

        self.l = l = QVBoxLayout(self)
        self.results = QTextBrowser(self)
        self.results.setOpenLinks(False)
        self.results.anchorClicked.connect(self.anchor_clicked)
        self.stack = s = QStackedWidget(self)
        s.addWidget(w), s.addWidget(self.results)
        l.addWidget(s)
        self.bh = h = QHBoxLayout()
        self.check_anchors = ca = QCheckBox(_('Check &anchors'))
        ca.setToolTip(_('Check HTML anchors in links (the part after the #).\n'
            ' This can be a little slow, since it requires downloading and parsing all the HTML pages.'))
        ca.setChecked(tprefs.get('check_external_link_anchors', True))
        ca.stateChanged.connect(self.anchors_changed)
        h.addWidget(ca), h.addStretch(100), h.addWidget(self.bb)
        l.addLayout(h)
        self.bb.setStandardButtons(self.bb.Close)
        self.rb = b = self.bb.addButton(_('&Refresh'), self.bb.ActionRole)
        b.setIcon(QIcon(I('view-refresh.png')))
        b.clicked.connect(self.refresh)

    def anchors_changed(self):
        tprefs.set('check_external_link_anchors', self.check_anchors.isChecked())

    def sizeHint(self):
        ans = Dialog.sizeHint(self)
        ans.setHeight(600)
        ans.setWidth(max(ans.width(), 800))
        return ans

    def run(self):
        from calibre.ebooks.oeb.polish.check.links import check_external_links
        self.tb = None
        self.errors = []
        try:
            self.errors = check_external_links(current_container(), self.progress_made.emit, check_anchors=self.check_anchors.isChecked())
        except Exception:
            import traceback
            self.tb = traceback.format_exc()
        self.progress_made.emit(None, None)

    def on_progress_made(self, curr, total):
        if curr is None:
            self.results.setText('')
            self.stack.setCurrentIndex(1)
            self.fixed_errors = set()
            self.rb.setEnabled(True)
            if self.tb is not None:
                return error_dialog(self, _('Checking failed'), _(
                    'There was an error while checking links, click "Show details" for more information'),
                             det_msg=self.tb, show=True)
            if not self.errors:
                self.results.setText(_('No broken links found'))
            else:
                self.populate_results()
        else:
            self.pb.setMaximum(total), self.pb.setValue(curr)

    def populate_results(self, preserve_pos=False):
        num = len(self.errors) - len(self.fixed_errors)
        text = '<h3>%s</h3><ol>' % (ngettext(
            'Found a broken link', 'Found {} broken links', num).format(num))
        for i, (locations, err, url) in enumerate(self.errors):
            if i in self.fixed_errors:
                continue
            text += '<li><b>%s</b> \xa0<a href="err:%d">[%s]</a><br>%s<br><ul>' % (url, i, _('Fix this link'), err)
            for name, href, lnum, col in locations:
                text += '<li>{name} \xa0<a href="loc:{lnum},{name}">[{line}: {lnum}]</a></li>'.format(
                    name=name, lnum=lnum, line=_('line number'))
            text += '</ul></li><hr>'
        self.results.setHtml(text)

    def anchor_clicked(self, qurl):
        url = qurl.toString()
        if url.startswith('err:'):
            errnum = int(url[4:])
            err = self.errors[errnum]
            newurl, ok = QInputDialog.getText(self, _('Fix URL'), _('Enter the corrected URL:') + '\xa0'*40, text=err[2])
            if not ok:
                return
            nmap = defaultdict(set)
            for name, href in {(l[0], l[1]) for l in err[0]}:
                nmap[name].add(href)

            for name, hrefs in nmap.iteritems():
                raw = oraw = get_data(name)
                for href in hrefs:
                    raw = raw.replace(href, newurl)
                if raw != oraw:
                    set_data(name, raw)
            self.fixed_errors.add(errnum)
            self.populate_results()
        elif url.startswith('loc:'):
            lnum, name = url[4:].partition(',')[::2]
            lnum = int(lnum or 1)
            editor = get_boss().edit_file(name)
            if lnum and editor is not None and editor.has_line_numbers:
                editor.current_line = lnum
Ejemplo n.º 5
0
class EbookScramble(QDialog):
    ''' Read an EPUB/KEPUB/AZW3 de-DRM'd ebook file and
        scramble various contents '''
    def __init__(self,
                 pathtoebook,
                 book_id=None,
                 from_calibre=False,
                 dsettings={},
                 calibre_libpaths=[],
                 parent=None):
        QDialog.__init__(self, parent=parent)
        self.gui = parent
        self.pathtoebook = pathtoebook
        self.book_id = book_id
        self.from_calibre = from_calibre
        self.calibre_libpaths = calibre_libpaths
        self.dsettings = MR_SETTINGS.copy()
        self.dsettings.update(dsettings)

        self.ebook = None
        self.eborig = None
        self.cleanup_dirs = []
        self.cleanup_files = []
        self.log = []

        self.rename_file_map = {}
        self.meta, self.errors = {}, {}
        self.is_scrambled = False
        self.dummyimg = None
        self.dummysvg = ''

        self.setWindowTitle(CAPTION)
        self.setWindowIcon(get_icons('images/plugin_icon.png'))

        # create widgets
        self.buttonBox = QDialogButtonBox(QDialogButtonBox.Save
                                          | QDialogButtonBox.Cancel)
        self.buttonBox.button(
            QDialogButtonBox.Save).setText('Save scrambled ebook && Exit')

        self.browser = QTextBrowser()
        self.browser.setText('')
        self.browser.setLineWrapMode(QTextBrowser.NoWrap)
        self.browser.setMinimumWidth(600)
        self.browser.setMinimumHeight(150)
        self.browser.setReadOnly(True)

        self.savefile = QLineEdit()
        self.savefile.setReadOnly(True)

        self.sourcefile = QLineEdit()
        self.sourcefile.setMinimumWidth(100)
        self.sourcefile.setReadOnly(True)

        self.browsesource = QPushButton('...')
        self.browsesource.setMaximumWidth(30)

        about_button = QPushButton('About', self)
        self.runButton = QPushButton('Scramble now')
        previewButton = QPushButton('Preview content')
        if Webview is None:
            previewButton.setEnabled(False)
            previewButton.setToolTip(
                'Preview not currently available for this book')

        configButton = QPushButton('Change rules *')
        configButton.setToolTip(
            'Only available in standalone version, not calibre plugin')
        metadataButton = QPushButton('View metadata *')
        metadataButton.setToolTip(
            'Only available in standalone version, not calibre plugin')
        errorsButton = QPushButton('View errors *')
        errorsButton.setToolTip(
            'Only available in standalone version, not calibre plugin')

        # layout widgets
        gpsource = QGroupBox('Source ebook:')
        laysource = QGridLayout()
        gpsource.setLayout(laysource)
        laysource.addWidget(self.sourcefile, 0, 0)
        laysource.addWidget(self.browsesource, 0, 1)

        gptarget = QGroupBox('Scrambled ebook:')
        laytarget = QGridLayout()
        gptarget.setLayout(laytarget)
        laytarget.addWidget(self.savefile, 0, 0)

        gpaction = QGroupBox('Actions:')
        layaction = QVBoxLayout()
        gpaction.setLayout(layaction)
        layaction.addWidget(self.runButton)
        layaction.addStretch()
        layaction.addWidget(previewButton)
        layaction.addStretch()

        gpextras = QGroupBox('Extras:')
        layaction2 = QVBoxLayout()
        gpextras.setLayout(layaction2)
        layaction2.addWidget(configButton)
        layaction2.addWidget(metadataButton)
        layaction2.addWidget(errorsButton)

        layaction3 = QVBoxLayout()
        layaction3.addWidget(about_button)
        layaction3.addStretch()
        layaction3.addWidget(gpextras)

        grid = QGridLayout()
        grid.addWidget(self.browser, 0, 0)
        grid.addLayout(layaction3, 0, 1)
        grid.addWidget(gpsource, 2, 0)
        grid.addWidget(gptarget, 3, 0)
        grid.addWidget(gpaction, 2, 1, 2, 1)
        grid.addWidget(self.buttonBox, 5, 0, 1, 2)
        self.setLayout(grid)

        # create connect signals/slots
        about_button.clicked.connect(self.about_button_clicked)
        self.runButton.clicked.connect(self.create_scramble_book)
        previewButton.clicked.connect(self.preview_ebook)
        configButton.clicked.connect(self.change_rules)
        metadataButton.clicked.connect(self.view_metadata)
        errorsButton.clicked.connect(self.view_errors)
        self.browsesource.clicked.connect(self.choose_source_ebook)

        self.buttonBox.accepted.connect(self.accept)
        self.buttonBox.rejected.connect(self.reject)

        if self.from_calibre:
            gpextras.setVisible(
                False)  # Extras not available in calibre plugin
            self.browsesource.setVisible(
                False)  # ebook file selection done by calibre

        self.initialise_new_file(self.pathtoebook)

    def initialise_new_file(self, pathtoebook):
        self.meta, self.errors = {}, {}
        self.rename_file_map = {}
        self.is_scrambled = False
        self.dummyimg = None
        self.dummysvg = ''
        self.runButton.setEnabled(True)
        self.buttonBox.button(QDialogButtonBox.Save).setEnabled(False)

        fileok = True
        if not os.path.isfile(pathtoebook):
            fileok = False
        else:
            try:
                self.ebook = get_container(pathtoebook)
            except:
                fileok = False
                msg = "Source ebook must be de-DRM'd and in one of these formats:" \
                    "\n- azw3\n- epub\n- kepub\n- kepub.epub.\n\nPlease select another."
                error_dialog(self,
                             CAPTION,
                             msg,
                             show=True,
                             show_copy_button=True)

        if not fileok:
            self.log.append('No ebook selected yet')
        else:
            self.cleanup_dirs.append(self.ebook.root)
            tdir = PersistentTemporaryDirectory('_scramble_clone_orig')
            self.cleanup_dirs.append(tdir)
            self.eborig = clone_container(self.ebook, tdir)

            dirn, fname, ext, is_kepub_epub = get_fileparts(
                self.ebook.path_to_ebook)
            ext = ext.lower()
            format = 'kepub' if is_kepub_epub else ext

            if self.book_id is not None:
                # calibre library book
                self.cleanup_files.append(self.ebook.path_to_ebook)
            sourcepath = self.ebook.path_to_ebook

            self.dummyimg = get_resources('images/' + format + '.png')
            self.dummysvg = get_resources('images/' + format + '.svg')

            if self.from_calibre:
                # calibre plugin
                self.dirout = ''
            else:
                # standalone version
                self.dirout = dirn
                self.log.append('\n--- New ebook: %s' % sourcepath)

            fn = fname + '_scrambled.'
            fn += 'kepub.' + ext if is_kepub_epub else ext
            self.fname_scrambled_ebook = ascii_text(fn)
            self.sourcefile.setText(sourcepath)
            self.savefile.setText(self.fname_scrambled_ebook)
            self.meta['orig'] = get_metadata(self.ebook)
            self.errors['orig'] = get_run_check_error(self.ebook)

        self.viewlog()

    def accept(self):
        # Any accept actions which need to be done before returning to caller
        savedir = self.choose_save_dir(self.dirout)
        if savedir is not None:
            self.buttonBox.button(QDialogButtonBox.Save).setText('Saving ...')
            self.buttonBox.button(QDialogButtonBox.Save).setEnabled(False)
            msg = ''
            if self.ebook.book_type.lower() == 'azw3':
                msg = '\n   ... please note, rebuilding an AZW3 may take a little longer ...'
            self.log.append('\nSaving now ... %s' % msg)
            self.viewlog()
            path_to_scrambled_ebook = os.path.join(savedir,
                                                   self.fname_scrambled_ebook)
            self.ebook.commit(path_to_scrambled_ebook)
            self.cleanup()
            QDialog.accept(self)

    def reject(self):
        self.cleanup()
        QDialog.reject(self)

    def cleanup(self):
        # delete calibre plugin temp files
        if self.book_id:
            for f in self.cleanup_files:
                try:
                    os.remove(f)
                except:
                    pass

        if self.from_calibre:
            for d in self.cleanup_dirs:
                try:
                    shutil.rmtree(d)
                except:
                    pass

    def choose_save_dir(self, default_dir):
        savedir = None
        askagain = True
        no_save_dir = False
        if default_dir:
            no_save_dir = True
        title = _('Choose destination directory for scrambled ebook')
        while askagain:
            savedir = choose_dir(window=self,
                                 name='',
                                 title=title,
                                 default_dir=default_dir,
                                 no_save_dir=no_save_dir)
            askagain = False
            if savedir is not None:
                savedir = os.path.normpath(savedir)
                if savedir.startswith(tuple(self.calibre_libpaths)):
                    askagain = True
                    msg = []
                    msg.append(
                        'You have selected a destination inside your Calibre library.'
                    )
                    msg.append(savedir)
                    msg.append('\nThis is NOT recommended. Try again.')
                    msg.append('\nPlease avoid the following:')
                    [
                        msg.append(path)
                        for path in sorted(self.calibre_libpaths)
                    ]
                    warning_dialog(self,
                                   'Calibre library chosen',
                                   '\n'.join(msg),
                                   show=True,
                                   show_copy_button=True)
        return savedir

    def choose_source_ebook(self):
        sf = self.sourcefile.text()
        seldir = get_fileparts(sf)[0] if sf else ''
        title = _('Select source ebook')
        selfiles = choose_files(self,
                                name='',
                                title=title,
                                filters=[('Ebooks', ['epub', 'kepub',
                                                     'azw3'])],
                                select_only_single_file=True,
                                default_dir=seldir)
        if selfiles:
            self.pathtoebook = os.path.normpath(selfiles[0])
            self.initialise_new_file(self.pathtoebook)

    def create_scramble_book(self):
        if self.ebook is None:
            return

        sf = self.sourcefile.text()

        self.log.append('\nScrambling %s ...' % sf)
        self.viewlog()

        scrambler = EbookScrambleAction(self.ebook, self.dsettings,
                                        self.dummyimg, self.dummysvg)
        self.rename_file_map = {
            k: v
            for (k, v) in iteritems(scrambler.file_map)
        }

        self.meta['scramb'] = get_metadata(self.ebook)
        self.errors['scramb'] = get_run_check_error(self.ebook)
        self.buttonBox.button(QDialogButtonBox.Save).setEnabled(True)
        self.runButton.setEnabled(False)
        self.is_scrambled = True

        self.log.append(scrambler.results)
        self.log.append('\n... finished')
        self.viewlog()

    def change_rules(self):
        dlg = EbookScrambleRulesDlg(self.dsettings, parent=self.gui)
        if dlg.exec_():
            self.dsettings.update(dlg.dsettings)
            self.log.append('\n--- Scrambling rules updated ---')
        self.viewlog()

    def preview_ebook(self):
        if self.ebook is None:
            return

        dlg = EbookScramblePreviewDlg(self.ebook,
                                      self.eborig,
                                      self.is_scrambled,
                                      self.rename_file_map,
                                      parent=self.gui)
        dlg.exec_()
        dlg.raise_()

    def view_metadata(self):
        if self.ebook is None:
            return

        dlg = EbookScrambleMetadataDlg(self.meta, parent=self.gui)
        dlg.exec_()
        dlg.raise_()

    def view_errors(self):
        if self.ebook is None:
            return

        dlg = EbookScrambleErrorsDlg(self.errors, parent=self.gui)
        dlg.exec_()
        dlg.raise_()

    def display_settings(self):
        self.log.append('\nCurrent Scramble rules:')
        [
            self.log.append('%s: %s' % (k, v))
            for (k, v) in sorted(iteritems(self.dsettings))
        ]

    def viewlog(self):
        self.browser.setText('\n'.join(self.log))
        self.browser.moveCursor(QTextCursor.End)
        QApplication.instance().processEvents()

    def about_button_clicked(self):
        # Get the about text from a file inside the plugin zip file
        # The get_resources function is a builtin function defined for all your
        # plugin code. It loads files from the plugin zip file. It returns
        # the bytes from the specified file.
        #
        # Note that if you are loading more than one file, for performance, you
        # should pass a list of names to get_resources. In this case,
        # get_resources will return a dictionary mapping names to bytes. Names that
        # are not found in the zip file will not be in the returned dictionary.

        source = 'calibre plugin' if self.from_calibre else 'standalone'
        text = get_resources('about.txt')
        QMessageBox.about(self, 'About %s %s' % (CAPTION, source), text)