Sat, 22 May 2021 18:51:46 +0200
Renamed the modules and classes of the E5Gui package to have the prefix 'Eric' instead of 'E5'.
# -*- coding: utf-8 -*- # Copyright (c) 2011 - 2021 Detlev Offenbach <detlev@die-offenbachs.de> # """ Module implementing a dialog to show some information about a site. """ from PyQt6.QtCore import pyqtSlot, QUrl, Qt from PyQt6.QtGui import QPixmap, QImage, QPainter, QColor, QBrush from PyQt6.QtNetwork import QNetworkRequest, QNetworkReply from PyQt6.QtWidgets import ( QDialog, QTreeWidgetItem, QGraphicsScene, QMenu, QApplication, QGraphicsPixmapItem ) try: from PyQt6.QtNetwork import QSslCertificate # __IGNORE_WARNING__ SSL = True except ImportError: SSL = False from E5Gui import EricMessageBox, EricFileDialog from .Ui_SiteInfoDialog import Ui_SiteInfoDialog from ..Tools import Scripts, WebBrowserTools from ..WebBrowserPage import WebBrowserPage import UI.PixmapCache import Preferences from WebBrowser.WebBrowserWindow import WebBrowserWindow class SiteInfoDialog(QDialog, Ui_SiteInfoDialog): """ Class implementing a dialog to show some information about a site. """ securityStyleFormat = "QLabel {{ background-color : {0}; }}" def __init__(self, browser, parent=None): """ Constructor @param browser reference to the browser window (HelpBrowser) @param parent reference to the parent widget (QWidget) """ super().__init__(parent) self.setupUi(self) self.setWindowFlags(Qt.WindowType.Window) # put icons self.tabWidget.setTabIcon( 0, UI.PixmapCache.getIcon("siteinfo-general")) self.tabWidget.setTabIcon( 1, UI.PixmapCache.getIcon("siteinfo-media")) if SSL: self.tabWidget.setTabIcon( 2, UI.PixmapCache.getIcon("siteinfo-security")) self.__imageReply = None self.__baseUrl = browser.url() title = browser.title() sslInfo = browser.page().getSslCertificateChain() #prepare background of image preview self.__imagePreviewStandardBackground = ( self.imagePreview.backgroundBrush() ) color1 = QColor(220, 220, 220) color2 = QColor(160, 160, 160) self.__tilePixmap = QPixmap(8, 8) self.__tilePixmap.fill(color1) tilePainter = QPainter(self.__tilePixmap) tilePainter.fillRect(0, 0, 4, 4, color2) tilePainter.fillRect(4, 4, 4, 4, color2) tilePainter.end() # populate General tab self.heading.setText("<b>{0}</b>".format(title)) self.siteAddressLabel.setText(self.__baseUrl.toString()) if self.__baseUrl.scheme() in ["https"]: if WebBrowserWindow.networkManager().isInsecureHost( self.__baseUrl.host() ): self.securityIconLabel.setPixmap( UI.PixmapCache.getPixmap("securityMedium")) self.securityLabel.setStyleSheet( SiteInfoDialog.securityStyleFormat.format( Preferences.getWebBrowser("InsecureUrlColor").name() ) ) self.securityLabel.setText(self.tr( '<b>Connection is encrypted but may be insecure.</b>')) else: self.securityIconLabel.setPixmap( UI.PixmapCache.getPixmap("securityHigh")) self.securityLabel.setStyleSheet( SiteInfoDialog.securityStyleFormat.format( Preferences.getWebBrowser("SecureUrlColor").name() ) ) self.securityLabel.setText( self.tr('<b>Connection is encrypted.</b>')) else: self.securityIconLabel.setPixmap( UI.PixmapCache.getPixmap("securityLow")) self.securityLabel.setText( self.tr('<b>Connection is not encrypted.</b>')) browser.page().runJavaScript( "document.charset", WebBrowserPage.SafeJsWorld, lambda res: self.encodingLabel.setText(res)) # populate the Security tab if sslInfo and SSL: self.sslWidget.showCertificateChain(sslInfo) self.tabWidget.setTabEnabled(2, SSL and bool(sslInfo)) self.securityDetailsButton.setEnabled(SSL and bool(sslInfo)) # populate Meta tags browser.page().runJavaScript(Scripts.getAllMetaAttributes(), WebBrowserPage.SafeJsWorld, self.__processMetaAttributes) # populate Media tab browser.page().runJavaScript(Scripts.getAllImages(), WebBrowserPage.SafeJsWorld, self.__processImageTags) self.tabWidget.setCurrentIndex(0) @pyqtSlot() def on_securityDetailsButton_clicked(self): """ Private slot to show security details. """ self.tabWidget.setCurrentIndex( self.tabWidget.indexOf(self.securityTab)) def __processImageTags(self, res): """ Private method to process the image tags. @param res result of the JavaScript script @type list of dict """ for img in res: src = img["src"] alt = img["alt"] if not alt: if src.find("/") == -1: alt = src else: pos = src.rfind("/") alt = src[pos + 1:] if not src or not alt: continue QTreeWidgetItem(self.imagesTree, [alt, src]) for col in range(self.imagesTree.columnCount()): self.imagesTree.resizeColumnToContents(col) if self.imagesTree.columnWidth(0) > 300: self.imagesTree.setColumnWidth(0, 300) self.imagesTree.setCurrentItem(self.imagesTree.topLevelItem(0)) self.imagesTree.setContextMenuPolicy( Qt.ContextMenuPolicy.CustomContextMenu) self.imagesTree.customContextMenuRequested.connect( self.__imagesTreeContextMenuRequested) def __processMetaAttributes(self, res): """ Private method to process the meta attributes. @param res result of the JavaScript script @type list of dict """ for meta in res: content = meta["content"] name = meta["name"] if not name: name = meta["httpequiv"] if not name or not content: continue if meta["charset"]: self.encodingLabel.setText(meta["charset"]) if "charset=" in content: self.encodingLabel.setText( content[content.index("charset=") + 8:]) QTreeWidgetItem(self.tagsTree, [name, content]) for col in range(self.tagsTree.columnCount()): self.tagsTree.resizeColumnToContents(col) @pyqtSlot(QTreeWidgetItem, QTreeWidgetItem) def on_imagesTree_currentItemChanged(self, current, previous): """ Private slot to show a preview of the selected image. @param current current image entry (QTreeWidgetItem) @param previous old current entry (QTreeWidgetItem) """ if current is None: return imageUrl = QUrl(current.text(1)) if imageUrl.isRelative(): imageUrl = self.__baseUrl.resolved(imageUrl) pixmap = QPixmap() loading = False if imageUrl.scheme() == "data": encodedUrl = current.text(1).encode("utf-8") imageData = encodedUrl[encodedUrl.find(b",") + 1:] pixmap = WebBrowserTools.pixmapFromByteArray(imageData) elif imageUrl.scheme() == "file": pixmap = QPixmap(imageUrl.toLocalFile()) elif imageUrl.scheme() == "qrc": pixmap = QPixmap(imageUrl.toString()[3:]) else: if self.__imageReply is not None: self.__imageReply.deleteLater() self.__imageReply = None from WebBrowser.WebBrowserWindow import WebBrowserWindow self.__imageReply = WebBrowserWindow.networkManager().get( QNetworkRequest(imageUrl)) self.__imageReply.finished.connect(self.__imageReplyFinished) loading = True self.__showLoadingText() if not loading: self.__showPixmap(pixmap) @pyqtSlot() def __imageReplyFinished(self): """ Private slot handling the loading of an image. """ if self.__imageReply.error() != QNetworkReply.NetworkError.NoError: return data = self.__imageReply.readAll() self.__showPixmap(QPixmap.fromImage(QImage.fromData(data))) def __showPixmap(self, pixmap): """ Private method to show a pixmap in the preview pane. @param pixmap pixmap to be shown @type QPixmap """ scene = QGraphicsScene(self.imagePreview) if pixmap.isNull(): self.imagePreview.setBackgroundBrush( self.__imagePreviewStandardBackground) scene.addText(self.tr("Preview not available.")) else: self.imagePreview.setBackgroundBrush(QBrush(self.__tilePixmap)) scene.addPixmap(pixmap) self.imagePreview.setScene(scene) def __showLoadingText(self): """ Private method to show some text while loading an image. """ self.imagePreview.setBackgroundBrush( self.__imagePreviewStandardBackground) scene = QGraphicsScene(self.imagePreview) scene.addText(self.tr("Loading...")) self.imagePreview.setScene(scene) def __imagesTreeContextMenuRequested(self, pos): """ Private slot to show a context menu for the images list. @param pos position for the menu (QPoint) """ itm = self.imagesTree.itemAt(pos) if itm is None: return menu = QMenu() act1 = menu.addAction(self.tr("Copy Image Location to Clipboard")) act1.setData(itm.text(1)) act1.triggered.connect(lambda: self.__copyAction(act1)) act2 = menu.addAction(self.tr("Copy Image Name to Clipboard")) act2.setData(itm.text(0)) act2.triggered.connect(lambda: self.__copyAction(act2)) menu.addSeparator() act3 = menu.addAction(self.tr("Save Image")) act3.setData(self.imagesTree.indexOfTopLevelItem(itm)) act3.triggered.connect(lambda: self.__saveImage(act3)) menu.exec(self.imagesTree.viewport().mapToGlobal(pos)) def __copyAction(self, act): """ Private slot to copy the image URL or the image name to the clipboard. @param act reference to the action that triggered @type QAction """ QApplication.clipboard().setText(act.data()) def __saveImage(self, act): """ Private slot to save the selected image to disk. @param act reference to the action that triggered @type QAction """ index = act.data() itm = self.imagesTree.topLevelItem(index) if itm is None: return if ( not self.imagePreview.scene() or len(self.imagePreview.scene().items()) == 0 ): return pixmapItem = self.imagePreview.scene().items()[0] if not isinstance(pixmapItem, QGraphicsPixmapItem): return if pixmapItem.pixmap().isNull(): EricMessageBox.warning( self, self.tr("Save Image"), self.tr( """<p>This preview is not available.</p>""")) return imageFileName = WebBrowserTools.getFileNameFromUrl(QUrl(itm.text(1))) index = imageFileName.rfind(".") if index != -1: imageFileName = imageFileName[:index] + ".png" filename = EricFileDialog.getSaveFileName( self, self.tr("Save Image"), imageFileName, self.tr("All Files (*)"), EricFileDialog.DontConfirmOverwrite) if not filename: return if not pixmapItem.pixmap().save(filename, "PNG"): EricMessageBox.critical( self, self.tr("Save Image"), self.tr( """<p>Cannot write to file <b>{0}</b>.</p>""") .format(filename)) return