class LogViewer(QDialog): # {{{ def __init__(self, log, parent=None): QDialog.__init__(self, parent) self.log = log self.l = l = QVBoxLayout() self.setLayout(l) self.tb = QTextBrowser(self) l.addWidget(self.tb) self.bb = QDialogButtonBox(QDialogButtonBox.StandardButton.Close) l.addWidget(self.bb) self.copy_button = self.bb.addButton( _('Copy to clipboard'), QDialogButtonBox.ButtonRole.ActionRole) self.copy_button.clicked.connect(self.copy_to_clipboard) self.copy_button.setIcon(QIcon(I('edit-copy.png'))) self.bb.rejected.connect(self.reject) self.bb.accepted.connect(self.accept) self.setWindowTitle(_('Download log')) self.setWindowIcon(QIcon(I('debug.png'))) self.resize(QSize(800, 400)) self.keep_updating = True self.last_html = None self.finished.connect(self.stop) QTimer.singleShot(100, self.update_log) self.show() def copy_to_clipboard(self): QApplication.clipboard().setText(''.join(self.log.plain_text)) def stop(self, *args): self.keep_updating = False def update_log(self): if not self.keep_updating: return html = self.log.html if html != self.last_html: self.last_html = html self.tb.setHtml('<pre style="font-family:monospace">%s</pre>' % html) QTimer.singleShot(1000, self.update_log)
class ViewLog(QDialog): # {{{ def __init__(self, title, html, parent=None, unique_name=None): QDialog.__init__(self, parent) self.l = l = QVBoxLayout() self.setLayout(l) self.tb = QTextBrowser(self) self.tb.setHtml('<pre style="font-family: monospace">%s</pre>' % html) l.addWidget(self.tb) self.bb = QDialogButtonBox(QDialogButtonBox.StandardButton.Ok) self.bb.accepted.connect(self.accept) self.bb.rejected.connect(self.reject) self.copy_button = self.bb.addButton(_('Copy to clipboard'), QDialogButtonBox.ButtonRole.ActionRole) self.copy_button.setIcon(QIcon(I('edit-copy.png'))) self.copy_button.clicked.connect(self.copy_to_clipboard) l.addWidget(self.bb) self.unique_name = unique_name or 'view-log-dialog' self.finished.connect(self.dialog_closing) self.resize(QSize(700, 500)) geom = gprefs.get(self.unique_name, None) if geom is not None: QApplication.instance().safe_restore_geometry(self, geom) self.setModal(False) self.setWindowTitle(title) self.setWindowIcon(QIcon(I('debug.png'))) self.show() def copy_to_clipboard(self): txt = self.tb.toPlainText() QApplication.clipboard().setText(txt) def dialog_closing(self, result): gprefs[self.unique_name] = bytearray(self.saveGeometry())
def setHtml(self, html): self.last_set_html = html QTextBrowser.setHtml(self, html)
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.ConnectionType.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.Policy.Expanding, QSizePolicy.Policy.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.AlignmentFlag.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(QDialogButtonBox.StandardButton.Close) self.rb = b = self.bb.addButton(_('&Refresh'), QDialogButtonBox.ButtonRole.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 iteritems(nmap): 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