src/eric7/WebBrowser/WebBrowserPage.py

branch
eric7
changeset 9221
bf71ee032bb4
parent 9209
b99e7fd55fd3
child 9384
b1b8e2dc2280
diff -r e9e7eca7efee -r bf71ee032bb4 src/eric7/WebBrowser/WebBrowserPage.py
--- a/src/eric7/WebBrowser/WebBrowserPage.py	Wed Jul 13 11:16:20 2022 +0200
+++ b/src/eric7/WebBrowser/WebBrowserPage.py	Wed Jul 13 14:55:47 2022 +0200
@@ -9,16 +9,21 @@
 """
 
 from PyQt6.QtCore import (
-    pyqtSlot, pyqtSignal, QUrl, QUrlQuery, QTimer, QEventLoop, QPoint
+    pyqtSlot,
+    pyqtSignal,
+    QUrl,
+    QUrlQuery,
+    QTimer,
+    QEventLoop,
+    QPoint,
 )
 from PyQt6.QtGui import QDesktopServices
-from PyQt6.QtWebEngineCore import (
-    QWebEnginePage, QWebEngineSettings, QWebEngineScript
-)
+from PyQt6.QtWebEngineCore import QWebEnginePage, QWebEngineSettings, QWebEngineScript
 from PyQt6.QtWebChannel import QWebChannel
 
 try:
     from PyQt6.QtNetwork import QSslConfiguration, QSslCertificate
+
     SSL_AVAILABLE = True
 except ImportError:
     SSL_AVAILABLE = False
@@ -39,7 +44,7 @@
 class WebBrowserPage(QWebEnginePage):
     """
     Class implementing an enhanced web page.
-    
+
     @signal safeBrowsingAbort() emitted to indicate an abort due to a safe
         browsing event
     @signal safeBrowsingBad(threatType, threatMessages) emitted to indicate a
@@ -51,51 +56,53 @@
     @signal sslConfigurationChanged() emitted to indicate a change of the
         stored SSL configuration data
     """
+
     SafeJsWorld = QWebEngineScript.ScriptWorldId.ApplicationWorld
     UnsafeJsWorld = QWebEngineScript.ScriptWorldId.MainWorld
-    
+
     safeBrowsingAbort = pyqtSignal()
     safeBrowsingBad = pyqtSignal(str, str)
-    
+
     printPageRequested = pyqtSignal()
-    navigationRequestAccepted = pyqtSignal(QUrl, QWebEnginePage.NavigationType,
-                                           bool)
-    
+    navigationRequestAccepted = pyqtSignal(QUrl, QWebEnginePage.NavigationType, bool)
+
     sslConfigurationChanged = pyqtSignal()
-    
+
     def __init__(self, view, parent=None):
         """
         Constructor
-        
+
         @param view reference to the WebBrowserView associated with the page
         @type WebBrowserView
         @param parent reference to the parent widget (defaults to None)
         @type QWidget (optional)
         """
-        super().__init__(
-            WebBrowserWindow.webProfile(), parent)
-        
+        super().__init__(WebBrowserWindow.webProfile(), parent)
+
         self.__printer = None
         self.__badSite = False
         self.__registerProtocolHandlerRequest = None
-        
+
         self.__view = view
-        
-        self.featurePermissionRequested.connect(
-            self.__featurePermissionRequested)
+
+        self.featurePermissionRequested.connect(self.__featurePermissionRequested)
         self.authenticationRequired.connect(
             lambda url, auth: WebBrowserWindow.networkManager().authentication(
-                url, auth, self))
+                url, auth, self
+            )
+        )
         self.proxyAuthenticationRequired.connect(
-            WebBrowserWindow.networkManager().proxyAuthentication)
+            WebBrowserWindow.networkManager().proxyAuthentication
+        )
         self.fullScreenRequested.connect(self.__fullScreenRequested)
         self.urlChanged.connect(self.__urlChanged)
         self.contentsSizeChanged.connect(self.__contentsSizeChanged)
         self.registerProtocolHandlerRequested.connect(
-            self.__registerProtocolHandlerRequested)
-        
+            self.__registerProtocolHandlerRequested
+        )
+
         self.__sslConfiguration = None
-        
+
         # Workaround for changing webchannel world inside
         # acceptNavigationRequest not working
         self.__channelUrl = QUrl()
@@ -104,28 +111,28 @@
         self.__setupChannelTimer.setSingleShot(True)
         self.__setupChannelTimer.setInterval(100)
         self.__setupChannelTimer.timeout.connect(self.__setupChannelTimeout)
-    
+
     def view(self):
         """
         Public method to get a reference to the WebBrowserView associated with
         the page.
-        
+
         @return reference to the WebBrowserView associated with the page
         r@type WebBrowserView
         """
         return self.__view
-    
+
     @pyqtSlot()
     def __setupChannelTimeout(self):
         """
         Private slot to initiate the setup of the web channel.
         """
         self.__setupWebChannelForUrl(self.__channelUrl)
-    
+
     def acceptNavigationRequest(self, url, type_, isMainFrame):
         """
         Public method to determine, if a request may be accepted.
-        
+
         @param url URL to navigate to
         @type QUrl
         @param type_ type of the navigation request
@@ -140,113 +147,114 @@
         if scheme == "mailto":
             QDesktopServices.openUrl(url)
             return False
-        
+
         # AdBlock
         if (
-            url.scheme() == "abp" and
-            WebBrowserWindow.adBlockManager().addSubscriptionFromUrl(url)
+            url.scheme() == "abp"
+            and WebBrowserWindow.adBlockManager().addSubscriptionFromUrl(url)
         ):
             return False
-        
+
         # GreaseMonkey
         navigationType = type_ in (
             QWebEnginePage.NavigationType.NavigationTypeLinkClicked,
-            QWebEnginePage.NavigationType.NavigationTypeRedirect
+            QWebEnginePage.NavigationType.NavigationTypeRedirect,
         )
         if navigationType and url.toString().endswith(".user.js"):
             WebBrowserWindow.greaseMonkeyManager().downloadScript(url)
             return False
-        
+
         if url.scheme() == "eric":
             if url.path() == "AddSearchProvider":
                 query = QUrlQuery(url)
                 self.__view.mainWindow().openSearchManager().addEngine(
-                    QUrl(query.queryItemValue("url")))
+                    QUrl(query.queryItemValue("url"))
+                )
                 return False
             elif url.path() == "PrintPage":
                 self.printPageRequested.emit()
                 return False
-        
+
         # Safe Browsing
         self.__badSite = False
-        from WebBrowser.SafeBrowsing.SafeBrowsingManager import (
-            SafeBrowsingManager
-        )
+        from WebBrowser.SafeBrowsing.SafeBrowsingManager import SafeBrowsingManager
+
         if (
-            SafeBrowsingManager.isEnabled() and
-            url.scheme() not in SafeBrowsingManager.getIgnoreSchemes()
+            SafeBrowsingManager.isEnabled()
+            and url.scheme() not in SafeBrowsingManager.getIgnoreSchemes()
         ):
-            threatLists = (
-                WebBrowserWindow.safeBrowsingManager().lookupUrl(url)[0]
-            )
+            threatLists = WebBrowserWindow.safeBrowsingManager().lookupUrl(url)[0]
             if threatLists:
                 threatMessages = (
-                    WebBrowserWindow.safeBrowsingManager()
-                    .getThreatMessages(threatLists)
+                    WebBrowserWindow.safeBrowsingManager().getThreatMessages(
+                        threatLists
+                    )
                 )
                 res = EricMessageBox.warning(
                     WebBrowserWindow.getWindow(),
                     self.tr("Suspicuous URL detected"),
-                    self.tr("<p>The URL <b>{0}</b> was found in the Safe"
-                            " Browsing database.</p>{1}").format(
-                        url.toString(), "".join(threatMessages)),
+                    self.tr(
+                        "<p>The URL <b>{0}</b> was found in the Safe"
+                        " Browsing database.</p>{1}"
+                    ).format(url.toString(), "".join(threatMessages)),
                     EricMessageBox.Abort | EricMessageBox.Ignore,
-                    EricMessageBox.Abort)
+                    EricMessageBox.Abort,
+                )
                 if res == EricMessageBox.Abort:
                     self.safeBrowsingAbort.emit()
                     return False
-                
+
                 self.__badSite = True
-                threatType = (
-                    WebBrowserWindow.safeBrowsingManager()
-                    .getThreatType(threatLists[0])
+                threatType = WebBrowserWindow.safeBrowsingManager().getThreatType(
+                    threatLists[0]
                 )
                 self.safeBrowsingBad.emit(threatType, "".join(threatMessages))
-        
-        result = QWebEnginePage.acceptNavigationRequest(
-            self, url, type_, isMainFrame)
-        
+
+        result = QWebEnginePage.acceptNavigationRequest(self, url, type_, isMainFrame)
+
         if result:
             if isMainFrame:
-                isWeb = url.scheme() in ("http", "https", "ftp", "ftps",
-                                         "file")
+                isWeb = url.scheme() in ("http", "https", "ftp", "ftps", "file")
                 globalJsEnabled = WebBrowserWindow.webSettings().testAttribute(
-                    QWebEngineSettings.WebAttribute.JavascriptEnabled)
+                    QWebEngineSettings.WebAttribute.JavascriptEnabled
+                )
                 if isWeb:
                     enable = globalJsEnabled
                 else:
                     enable = True
                 self.settings().setAttribute(
-                    QWebEngineSettings.WebAttribute.JavascriptEnabled, enable)
-                
+                    QWebEngineSettings.WebAttribute.JavascriptEnabled, enable
+                )
+
                 self.__channelUrl = url
                 self.__setupChannelTimer.start()
             self.navigationRequestAccepted.emit(url, type_, isMainFrame)
-        
+
         return result
-    
+
     @pyqtSlot(QUrl)
     def __urlChanged(self, url):
         """
         Private slot to handle changes of the URL.
-        
+
         @param url new URL
         @type QUrl
         """
         if (
-            not url.isEmpty() and
-            url.scheme() == "eric" and
-            not self.isJavaScriptEnabled()
+            not url.isEmpty()
+            and url.scheme() == "eric"
+            and not self.isJavaScriptEnabled()
         ):
             self.settings().setAttribute(
-                QWebEngineSettings.WebAttribute.JavascriptEnabled, True)
+                QWebEngineSettings.WebAttribute.JavascriptEnabled, True
+            )
             self.triggerAction(QWebEnginePage.WebAction.Reload)
-    
+
     @classmethod
     def userAgent(cls, resolveEmpty=False):
         """
         Class method to get the global user agent setting.
-        
+
         @param resolveEmpty flag indicating to resolve an empty
             user agent (boolean)
         @return user agent string (string)
@@ -255,21 +263,21 @@
         if agent == "" and resolveEmpty:
             agent = cls.userAgentForUrl(QUrl())
         return agent
-    
+
     @classmethod
     def setUserAgent(cls, agent):
         """
         Class method to set the global user agent string.
-        
+
         @param agent new current user agent string (string)
         """
         Preferences.setWebBrowser("UserAgent", agent)
-    
+
     @classmethod
     def userAgentForUrl(cls, url):
         """
         Class method to determine the user agent for the given URL.
-        
+
         @param url URL to determine user agent for (QUrl)
         @return user agent string (string)
         """
@@ -281,11 +289,11 @@
                 # no global agent string specified -> use default one
                 agent = WebBrowserWindow.webProfile().httpUserAgent()
         return agent
-    
+
     def __featurePermissionRequested(self, url, feature):
         """
         Private slot handling a feature permission request.
-        
+
         @param url url requesting the feature
         @type QUrl
         @param feature requested feature
@@ -293,13 +301,13 @@
         """
         manager = WebBrowserWindow.featurePermissionManager()
         manager.requestFeaturePermission(self, url, feature)
-    
-    def execJavaScript(self, script,
-                       worldId=QWebEngineScript.ScriptWorldId.MainWorld,
-                       timeout=500):
+
+    def execJavaScript(
+        self, script, worldId=QWebEngineScript.ScriptWorldId.MainWorld, timeout=500
+    ):
         """
         Public method to execute a JavaScript function synchroneously.
-        
+
         @param script JavaScript script source to be executed
         @type str
         @param worldId ID to run the script under
@@ -312,21 +320,21 @@
         loop = QEventLoop()
         resultDict = {"res": None}
         QTimer.singleShot(timeout, loop.quit)
-        
+
         def resultCallback(res, resDict=resultDict):
             if loop and loop.isRunning():
                 resDict["res"] = res
                 loop.quit()
-        
+
         self.runJavaScript(script, worldId, resultCallback)
-        
+
         loop.exec()
         return resultDict["res"]
-    
+
     def runJavaScript(self, script, worldId=-1, callback=None):
         """
         Public method to run a script in the context of the page.
-        
+
         @param script JavaScript script source to be executed
         @type str
         @param worldId ID to run the script under
@@ -345,71 +353,72 @@
                 QWebEnginePage.runJavaScript(self, script)
             else:
                 QWebEnginePage.runJavaScript(self, script, callback)
-    
+
     def isJavaScriptEnabled(self):
         """
         Public method to test, if JavaScript is enabled.
-        
+
         @return flag indicating the state of the JavaScript support
         @rtype bool
         """
         return self.settings().testAttribute(
-            QWebEngineSettings.WebAttribute.JavascriptEnabled)
-    
+            QWebEngineSettings.WebAttribute.JavascriptEnabled
+        )
+
     def scroll(self, x, y):
         """
         Public method to scroll by the given amount of pixels.
-        
+
         @param x horizontal scroll value
         @type int
         @param y vertical scroll value
         @type int
         """
         self.runJavaScript(
-            "window.scrollTo(window.scrollX + {0}, window.scrollY + {1})"
-            .format(x, y),
-            WebBrowserPage.SafeJsWorld
+            "window.scrollTo(window.scrollX + {0}, window.scrollY + {1})".format(x, y),
+            WebBrowserPage.SafeJsWorld,
         )
-    
+
     def scrollTo(self, pos):
         """
         Public method to scroll to the given position.
-        
+
         @param pos position to scroll to
         @type QPointF
         """
         self.runJavaScript(
             "window.scrollTo({0}, {1});".format(pos.x(), pos.y()),
-            WebBrowserPage.SafeJsWorld
+            WebBrowserPage.SafeJsWorld,
         )
-    
+
     def mapToViewport(self, pos):
         """
         Public method to map a position to the viewport.
-        
+
         @param pos position to be mapped
         @type QPoint
         @return viewport position
         @rtype QPoint
         """
-        return QPoint(int(pos.x() // self.zoomFactor()),
-                      int(pos.y() // self.zoomFactor()))
-    
+        return QPoint(
+            int(pos.x() // self.zoomFactor()), int(pos.y() // self.zoomFactor())
+        )
+
     def hitTestContent(self, pos):
         """
         Public method to test the content at a specified position.
-        
+
         @param pos position to execute the test at
         @type QPoint
         @return test result object
         @rtype WebHitTestResult
         """
         return WebHitTestResult(self, pos)
-    
+
     def __setupWebChannelForUrl(self, url):
         """
         Private method to setup a web channel to our external object.
-        
+
         @param url URL for which to setup the web channel
         @type QUrl
         """
@@ -417,49 +426,48 @@
         if channel is None:
             channel = QWebChannel(self)
             ExternalJsObject.setupWebChannel(channel, self)
-        
+
         worldId = -1
         worldId = (
             self.UnsafeJsWorld
-            if url.scheme() in ("eric", "qthelp") else
-            self.SafeJsWorld
+            if url.scheme() in ("eric", "qthelp")
+            else self.SafeJsWorld
         )
         if worldId != self.__channelWorldId:
             self.__channelWorldId = worldId
             self.setWebChannel(channel, self.__channelWorldId)
-    
+
     def certificateError(self, error):
         """
         Public method to handle SSL certificate errors.
-        
+
         @param error object containing the certificate error information
         @type QWebEngineCertificateError
         @return flag indicating to ignore this error
         @rtype bool
         """
-        return WebBrowserWindow.networkManager().certificateError(
-            error, self.__view)
-    
+        return WebBrowserWindow.networkManager().certificateError(error, self.__view)
+
     def __fullScreenRequested(self, request):
         """
         Private slot handling a full screen request.
-        
+
         @param request reference to the full screen request
         @type QWebEngineFullScreenRequest
         """
         self.__view.requestFullScreen(request.toggleOn())
-        
+
         accepted = request.toggleOn() == self.__view.isFullScreen()
-        
+
         if accepted:
             request.accept()
         else:
             request.reject()
-    
+
     def execPrintPage(self, printer, timeout=1000):
         """
         Public method to execute a synchronous print.
-        
+
         @param printer reference to the printer object
         @type QPrinter
         @param timeout timeout value in milliseconds
@@ -470,36 +478,36 @@
         loop = QEventLoop()
         resultDict = {"res": None}
         QTimer.singleShot(timeout, loop.quit)
-        
+
         def printCallback(res, resDict=resultDict):
             if loop and loop.isRunning():
                 resDict["res"] = res
                 loop.quit()
-        
+
         self.print(printer, printCallback)
-        
+
         loop.exec()
         return resultDict["res"]
-    
+
     def __contentsSizeChanged(self, size):
         """
         Private slot to work around QWebEnginePage not scrolling to anchors
         when opened in a background tab.
-        
+
         @param size changed contents size (unused)
         @type QSize
         """
         fragment = self.url().fragment()
         self.runJavaScript(Scripts.scrollToAnchor(fragment))
-    
+
     ##############################################
     ## Methods below deal with JavaScript messages
     ##############################################
-    
+
     def javaScriptConsoleMessage(self, level, message, lineNumber, sourceId):
         """
         Public method to show a console message.
-        
+
         @param level severity
         @type QWebEnginePage.JavaScriptConsoleMessageLevel
         @param message message to be shown
@@ -510,172 +518,169 @@
         @type str
         """
         self.__view.mainWindow().javascriptConsole().javaScriptConsoleMessage(
-            level, message, lineNumber, sourceId)
-    
+            level, message, lineNumber, sourceId
+        )
+
     ###########################################################################
     ## Methods below implement safe browsing related functions
     ###########################################################################
-    
+
     def getSafeBrowsingStatus(self):
         """
         Public method to get the safe browsing status of the current page.
-        
+
         @return flag indicating a safe site
         @rtype bool
         """
         return not self.__badSite
-    
+
     #############################################################
     ## Methods below implement protocol handler related functions
     #############################################################
-    
+
     @pyqtSlot("QWebEngineRegisterProtocolHandlerRequest")
     def __registerProtocolHandlerRequested(self, request):
         """
         Private slot to handle the registration of a custom protocol
         handler.
-        
+
         @param request reference to the registration request
         @type QWebEngineRegisterProtocolHandlerRequest
         """
-        from PyQt6.QtWebEngineCore import (
-            QWebEngineRegisterProtocolHandlerRequest
-        )
-        
+        from PyQt6.QtWebEngineCore import QWebEngineRegisterProtocolHandlerRequest
+
         if self.__registerProtocolHandlerRequest:
             del self.__registerProtocolHandlerRequest
             self.__registerProtocolHandlerRequest = None
         self.__registerProtocolHandlerRequest = (
             QWebEngineRegisterProtocolHandlerRequest(request)
         )
-    
+
     def registerProtocolHandlerRequestUrl(self):
         """
         Public method to get the registered protocol handler request URL.
-        
+
         @return registered protocol handler request URL
         @rtype QUrl
         """
-        if (
-            self.__registerProtocolHandlerRequest and
-            (self.url().host() ==
-             self.__registerProtocolHandlerRequest.origin().host())
+        if self.__registerProtocolHandlerRequest and (
+            self.url().host() == self.__registerProtocolHandlerRequest.origin().host()
         ):
             return self.__registerProtocolHandlerRequest.origin()
         else:
             return QUrl()
-    
+
     def registerProtocolHandlerRequestScheme(self):
         """
         Public method to get the registered protocol handler request scheme.
-        
+
         @return registered protocol handler request scheme
         @rtype str
         """
-        if (
-            self.__registerProtocolHandlerRequest and
-            (self.url().host() ==
-             self.__registerProtocolHandlerRequest.origin().host())
+        if self.__registerProtocolHandlerRequest and (
+            self.url().host() == self.__registerProtocolHandlerRequest.origin().host()
         ):
             return self.__registerProtocolHandlerRequest.scheme()
         else:
             return ""
-    
+
     #############################################################
     ## SSL configuration handling below
     #############################################################
-    
+
     def setSslConfiguration(self, sslConfiguration):
         """
         Public slot to set the SSL configuration data of the page.
-        
+
         @param sslConfiguration SSL configuration to be set
         @type QSslConfiguration
         """
         self.__sslConfiguration = QSslConfiguration(sslConfiguration)
         self.__sslConfiguration.url = self.url()
         self.sslConfigurationChanged.emit()
-    
+
     def getSslConfiguration(self):
         """
         Public method to return a reference to the current SSL configuration.
-        
+
         @return reference to the SSL configuration in use
         @rtype QSslConfiguration
         """
         return self.__sslConfiguration
-    
+
     def clearSslConfiguration(self):
         """
         Public slot to clear the stored SSL configuration data.
         """
         self.__sslConfiguration = None
         self.sslConfigurationChanged.emit()
-    
+
     def getSslCertificate(self):
         """
         Public method to get a reference to the SSL certificate.
-        
+
         @return amended SSL certificate
         @rtype QSslCertificate
         """
         if self.__sslConfiguration is None:
             return None
-        
+
         sslCertificate = self.__sslConfiguration.peerCertificate()
         sslCertificate.url = QUrl(self.__sslConfiguration.url)
         return sslCertificate
-    
+
     def getSslCertificateChain(self):
         """
         Public method to get a reference to the SSL certificate chain.
-        
+
         @return SSL certificate chain
         @rtype list of QSslCertificate
         """
         if self.__sslConfiguration is None:
             return []
-        
+
         chain = self.__sslConfiguration.peerCertificateChain()
         return chain
-    
+
     def showSslInfo(self, pos):
         """
         Public slot to show some SSL information for the loaded page.
-        
+
         @param pos position to show the info at
         @type QPoint
         """
         if SSL_AVAILABLE and self.__sslConfiguration is not None:
             from EricNetwork.EricSslInfoWidget import EricSslInfoWidget
-            widget = EricSslInfoWidget(self.url(), self.__sslConfiguration,
-                                       self.__view)
+
+            widget = EricSslInfoWidget(self.url(), self.__sslConfiguration, self.__view)
             widget.showAt(pos)
         else:
             EricMessageBox.warning(
                 self.__view,
                 self.tr("SSL Info"),
-                self.tr("""This site does not contain SSL information."""))
-    
+                self.tr("""This site does not contain SSL information."""),
+            )
+
     def hasValidSslInfo(self):
         """
         Public method to check, if the page has a valid SSL certificate.
-        
+
         @return flag indicating a valid SSL certificate
         @rtype bool
         """
         if self.__sslConfiguration is None:
             return False
-        
+
         certList = self.__sslConfiguration.peerCertificateChain()
         if not certList:
             return False
-        
+
         certificateDict = Globals.toDict(
-            Preferences.getSettings().value("Ssl/CaCertificatesDict"))
+            Preferences.getSettings().value("Ssl/CaCertificatesDict")
+        )
         for server in certificateDict:
             localCAList = QSslCertificate.fromData(certificateDict[server])
             if any(cert in localCAList for cert in certList):
                 return True
-        
+
         return all(not cert.isBlacklisted() for cert in certList)

eric ide

mercurial