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)
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)