src/eric7/WebBrowser/WebBrowserPage.py

branch
eric7
changeset 9221
bf71ee032bb4
parent 9209
b99e7fd55fd3
child 9384
b1b8e2dc2280
equal deleted inserted replaced
9220:e9e7eca7efee 9221:bf71ee032bb4
7 """ 7 """
8 Module implementing the helpbrowser using QWebView. 8 Module implementing the helpbrowser using QWebView.
9 """ 9 """
10 10
11 from PyQt6.QtCore import ( 11 from PyQt6.QtCore import (
12 pyqtSlot, pyqtSignal, QUrl, QUrlQuery, QTimer, QEventLoop, QPoint 12 pyqtSlot,
13 pyqtSignal,
14 QUrl,
15 QUrlQuery,
16 QTimer,
17 QEventLoop,
18 QPoint,
13 ) 19 )
14 from PyQt6.QtGui import QDesktopServices 20 from PyQt6.QtGui import QDesktopServices
15 from PyQt6.QtWebEngineCore import ( 21 from PyQt6.QtWebEngineCore import QWebEnginePage, QWebEngineSettings, QWebEngineScript
16 QWebEnginePage, QWebEngineSettings, QWebEngineScript
17 )
18 from PyQt6.QtWebChannel import QWebChannel 22 from PyQt6.QtWebChannel import QWebChannel
19 23
20 try: 24 try:
21 from PyQt6.QtNetwork import QSslConfiguration, QSslCertificate 25 from PyQt6.QtNetwork import QSslConfiguration, QSslCertificate
26
22 SSL_AVAILABLE = True 27 SSL_AVAILABLE = True
23 except ImportError: 28 except ImportError:
24 SSL_AVAILABLE = False 29 SSL_AVAILABLE = False
25 30
26 from EricWidgets import EricMessageBox 31 from EricWidgets import EricMessageBox
37 42
38 43
39 class WebBrowserPage(QWebEnginePage): 44 class WebBrowserPage(QWebEnginePage):
40 """ 45 """
41 Class implementing an enhanced web page. 46 Class implementing an enhanced web page.
42 47
43 @signal safeBrowsingAbort() emitted to indicate an abort due to a safe 48 @signal safeBrowsingAbort() emitted to indicate an abort due to a safe
44 browsing event 49 browsing event
45 @signal safeBrowsingBad(threatType, threatMessages) emitted to indicate a 50 @signal safeBrowsingBad(threatType, threatMessages) emitted to indicate a
46 malicious web site as determined by safe browsing 51 malicious web site as determined by safe browsing
47 @signal printPageRequested() emitted to indicate a print request of the 52 @signal printPageRequested() emitted to indicate a print request of the
49 @signal navigationRequestAccepted(url, navigation type, main frame) emitted 54 @signal navigationRequestAccepted(url, navigation type, main frame) emitted
50 to signal an accepted navigation request 55 to signal an accepted navigation request
51 @signal sslConfigurationChanged() emitted to indicate a change of the 56 @signal sslConfigurationChanged() emitted to indicate a change of the
52 stored SSL configuration data 57 stored SSL configuration data
53 """ 58 """
59
54 SafeJsWorld = QWebEngineScript.ScriptWorldId.ApplicationWorld 60 SafeJsWorld = QWebEngineScript.ScriptWorldId.ApplicationWorld
55 UnsafeJsWorld = QWebEngineScript.ScriptWorldId.MainWorld 61 UnsafeJsWorld = QWebEngineScript.ScriptWorldId.MainWorld
56 62
57 safeBrowsingAbort = pyqtSignal() 63 safeBrowsingAbort = pyqtSignal()
58 safeBrowsingBad = pyqtSignal(str, str) 64 safeBrowsingBad = pyqtSignal(str, str)
59 65
60 printPageRequested = pyqtSignal() 66 printPageRequested = pyqtSignal()
61 navigationRequestAccepted = pyqtSignal(QUrl, QWebEnginePage.NavigationType, 67 navigationRequestAccepted = pyqtSignal(QUrl, QWebEnginePage.NavigationType, bool)
62 bool) 68
63
64 sslConfigurationChanged = pyqtSignal() 69 sslConfigurationChanged = pyqtSignal()
65 70
66 def __init__(self, view, parent=None): 71 def __init__(self, view, parent=None):
67 """ 72 """
68 Constructor 73 Constructor
69 74
70 @param view reference to the WebBrowserView associated with the page 75 @param view reference to the WebBrowserView associated with the page
71 @type WebBrowserView 76 @type WebBrowserView
72 @param parent reference to the parent widget (defaults to None) 77 @param parent reference to the parent widget (defaults to None)
73 @type QWidget (optional) 78 @type QWidget (optional)
74 """ 79 """
75 super().__init__( 80 super().__init__(WebBrowserWindow.webProfile(), parent)
76 WebBrowserWindow.webProfile(), parent) 81
77
78 self.__printer = None 82 self.__printer = None
79 self.__badSite = False 83 self.__badSite = False
80 self.__registerProtocolHandlerRequest = None 84 self.__registerProtocolHandlerRequest = None
81 85
82 self.__view = view 86 self.__view = view
83 87
84 self.featurePermissionRequested.connect( 88 self.featurePermissionRequested.connect(self.__featurePermissionRequested)
85 self.__featurePermissionRequested)
86 self.authenticationRequired.connect( 89 self.authenticationRequired.connect(
87 lambda url, auth: WebBrowserWindow.networkManager().authentication( 90 lambda url, auth: WebBrowserWindow.networkManager().authentication(
88 url, auth, self)) 91 url, auth, self
92 )
93 )
89 self.proxyAuthenticationRequired.connect( 94 self.proxyAuthenticationRequired.connect(
90 WebBrowserWindow.networkManager().proxyAuthentication) 95 WebBrowserWindow.networkManager().proxyAuthentication
96 )
91 self.fullScreenRequested.connect(self.__fullScreenRequested) 97 self.fullScreenRequested.connect(self.__fullScreenRequested)
92 self.urlChanged.connect(self.__urlChanged) 98 self.urlChanged.connect(self.__urlChanged)
93 self.contentsSizeChanged.connect(self.__contentsSizeChanged) 99 self.contentsSizeChanged.connect(self.__contentsSizeChanged)
94 self.registerProtocolHandlerRequested.connect( 100 self.registerProtocolHandlerRequested.connect(
95 self.__registerProtocolHandlerRequested) 101 self.__registerProtocolHandlerRequested
96 102 )
103
97 self.__sslConfiguration = None 104 self.__sslConfiguration = None
98 105
99 # Workaround for changing webchannel world inside 106 # Workaround for changing webchannel world inside
100 # acceptNavigationRequest not working 107 # acceptNavigationRequest not working
101 self.__channelUrl = QUrl() 108 self.__channelUrl = QUrl()
102 self.__channelWorldId = -1 109 self.__channelWorldId = -1
103 self.__setupChannelTimer = QTimer(self) 110 self.__setupChannelTimer = QTimer(self)
104 self.__setupChannelTimer.setSingleShot(True) 111 self.__setupChannelTimer.setSingleShot(True)
105 self.__setupChannelTimer.setInterval(100) 112 self.__setupChannelTimer.setInterval(100)
106 self.__setupChannelTimer.timeout.connect(self.__setupChannelTimeout) 113 self.__setupChannelTimer.timeout.connect(self.__setupChannelTimeout)
107 114
108 def view(self): 115 def view(self):
109 """ 116 """
110 Public method to get a reference to the WebBrowserView associated with 117 Public method to get a reference to the WebBrowserView associated with
111 the page. 118 the page.
112 119
113 @return reference to the WebBrowserView associated with the page 120 @return reference to the WebBrowserView associated with the page
114 r@type WebBrowserView 121 r@type WebBrowserView
115 """ 122 """
116 return self.__view 123 return self.__view
117 124
118 @pyqtSlot() 125 @pyqtSlot()
119 def __setupChannelTimeout(self): 126 def __setupChannelTimeout(self):
120 """ 127 """
121 Private slot to initiate the setup of the web channel. 128 Private slot to initiate the setup of the web channel.
122 """ 129 """
123 self.__setupWebChannelForUrl(self.__channelUrl) 130 self.__setupWebChannelForUrl(self.__channelUrl)
124 131
125 def acceptNavigationRequest(self, url, type_, isMainFrame): 132 def acceptNavigationRequest(self, url, type_, isMainFrame):
126 """ 133 """
127 Public method to determine, if a request may be accepted. 134 Public method to determine, if a request may be accepted.
128 135
129 @param url URL to navigate to 136 @param url URL to navigate to
130 @type QUrl 137 @type QUrl
131 @param type_ type of the navigation request 138 @param type_ type of the navigation request
132 @type QWebEnginePage.NavigationType 139 @type QWebEnginePage.NavigationType
133 @param isMainFrame flag indicating, that the request originated from 140 @param isMainFrame flag indicating, that the request originated from
138 """ 145 """
139 scheme = url.scheme() 146 scheme = url.scheme()
140 if scheme == "mailto": 147 if scheme == "mailto":
141 QDesktopServices.openUrl(url) 148 QDesktopServices.openUrl(url)
142 return False 149 return False
143 150
144 # AdBlock 151 # AdBlock
145 if ( 152 if (
146 url.scheme() == "abp" and 153 url.scheme() == "abp"
147 WebBrowserWindow.adBlockManager().addSubscriptionFromUrl(url) 154 and WebBrowserWindow.adBlockManager().addSubscriptionFromUrl(url)
148 ): 155 ):
149 return False 156 return False
150 157
151 # GreaseMonkey 158 # GreaseMonkey
152 navigationType = type_ in ( 159 navigationType = type_ in (
153 QWebEnginePage.NavigationType.NavigationTypeLinkClicked, 160 QWebEnginePage.NavigationType.NavigationTypeLinkClicked,
154 QWebEnginePage.NavigationType.NavigationTypeRedirect 161 QWebEnginePage.NavigationType.NavigationTypeRedirect,
155 ) 162 )
156 if navigationType and url.toString().endswith(".user.js"): 163 if navigationType and url.toString().endswith(".user.js"):
157 WebBrowserWindow.greaseMonkeyManager().downloadScript(url) 164 WebBrowserWindow.greaseMonkeyManager().downloadScript(url)
158 return False 165 return False
159 166
160 if url.scheme() == "eric": 167 if url.scheme() == "eric":
161 if url.path() == "AddSearchProvider": 168 if url.path() == "AddSearchProvider":
162 query = QUrlQuery(url) 169 query = QUrlQuery(url)
163 self.__view.mainWindow().openSearchManager().addEngine( 170 self.__view.mainWindow().openSearchManager().addEngine(
164 QUrl(query.queryItemValue("url"))) 171 QUrl(query.queryItemValue("url"))
172 )
165 return False 173 return False
166 elif url.path() == "PrintPage": 174 elif url.path() == "PrintPage":
167 self.printPageRequested.emit() 175 self.printPageRequested.emit()
168 return False 176 return False
169 177
170 # Safe Browsing 178 # Safe Browsing
171 self.__badSite = False 179 self.__badSite = False
172 from WebBrowser.SafeBrowsing.SafeBrowsingManager import ( 180 from WebBrowser.SafeBrowsing.SafeBrowsingManager import SafeBrowsingManager
173 SafeBrowsingManager 181
174 )
175 if ( 182 if (
176 SafeBrowsingManager.isEnabled() and 183 SafeBrowsingManager.isEnabled()
177 url.scheme() not in SafeBrowsingManager.getIgnoreSchemes() 184 and url.scheme() not in SafeBrowsingManager.getIgnoreSchemes()
178 ): 185 ):
179 threatLists = ( 186 threatLists = WebBrowserWindow.safeBrowsingManager().lookupUrl(url)[0]
180 WebBrowserWindow.safeBrowsingManager().lookupUrl(url)[0]
181 )
182 if threatLists: 187 if threatLists:
183 threatMessages = ( 188 threatMessages = (
184 WebBrowserWindow.safeBrowsingManager() 189 WebBrowserWindow.safeBrowsingManager().getThreatMessages(
185 .getThreatMessages(threatLists) 190 threatLists
191 )
186 ) 192 )
187 res = EricMessageBox.warning( 193 res = EricMessageBox.warning(
188 WebBrowserWindow.getWindow(), 194 WebBrowserWindow.getWindow(),
189 self.tr("Suspicuous URL detected"), 195 self.tr("Suspicuous URL detected"),
190 self.tr("<p>The URL <b>{0}</b> was found in the Safe" 196 self.tr(
191 " Browsing database.</p>{1}").format( 197 "<p>The URL <b>{0}</b> was found in the Safe"
192 url.toString(), "".join(threatMessages)), 198 " Browsing database.</p>{1}"
199 ).format(url.toString(), "".join(threatMessages)),
193 EricMessageBox.Abort | EricMessageBox.Ignore, 200 EricMessageBox.Abort | EricMessageBox.Ignore,
194 EricMessageBox.Abort) 201 EricMessageBox.Abort,
202 )
195 if res == EricMessageBox.Abort: 203 if res == EricMessageBox.Abort:
196 self.safeBrowsingAbort.emit() 204 self.safeBrowsingAbort.emit()
197 return False 205 return False
198 206
199 self.__badSite = True 207 self.__badSite = True
200 threatType = ( 208 threatType = WebBrowserWindow.safeBrowsingManager().getThreatType(
201 WebBrowserWindow.safeBrowsingManager() 209 threatLists[0]
202 .getThreatType(threatLists[0])
203 ) 210 )
204 self.safeBrowsingBad.emit(threatType, "".join(threatMessages)) 211 self.safeBrowsingBad.emit(threatType, "".join(threatMessages))
205 212
206 result = QWebEnginePage.acceptNavigationRequest( 213 result = QWebEnginePage.acceptNavigationRequest(self, url, type_, isMainFrame)
207 self, url, type_, isMainFrame) 214
208
209 if result: 215 if result:
210 if isMainFrame: 216 if isMainFrame:
211 isWeb = url.scheme() in ("http", "https", "ftp", "ftps", 217 isWeb = url.scheme() in ("http", "https", "ftp", "ftps", "file")
212 "file")
213 globalJsEnabled = WebBrowserWindow.webSettings().testAttribute( 218 globalJsEnabled = WebBrowserWindow.webSettings().testAttribute(
214 QWebEngineSettings.WebAttribute.JavascriptEnabled) 219 QWebEngineSettings.WebAttribute.JavascriptEnabled
220 )
215 if isWeb: 221 if isWeb:
216 enable = globalJsEnabled 222 enable = globalJsEnabled
217 else: 223 else:
218 enable = True 224 enable = True
219 self.settings().setAttribute( 225 self.settings().setAttribute(
220 QWebEngineSettings.WebAttribute.JavascriptEnabled, enable) 226 QWebEngineSettings.WebAttribute.JavascriptEnabled, enable
221 227 )
228
222 self.__channelUrl = url 229 self.__channelUrl = url
223 self.__setupChannelTimer.start() 230 self.__setupChannelTimer.start()
224 self.navigationRequestAccepted.emit(url, type_, isMainFrame) 231 self.navigationRequestAccepted.emit(url, type_, isMainFrame)
225 232
226 return result 233 return result
227 234
228 @pyqtSlot(QUrl) 235 @pyqtSlot(QUrl)
229 def __urlChanged(self, url): 236 def __urlChanged(self, url):
230 """ 237 """
231 Private slot to handle changes of the URL. 238 Private slot to handle changes of the URL.
232 239
233 @param url new URL 240 @param url new URL
234 @type QUrl 241 @type QUrl
235 """ 242 """
236 if ( 243 if (
237 not url.isEmpty() and 244 not url.isEmpty()
238 url.scheme() == "eric" and 245 and url.scheme() == "eric"
239 not self.isJavaScriptEnabled() 246 and not self.isJavaScriptEnabled()
240 ): 247 ):
241 self.settings().setAttribute( 248 self.settings().setAttribute(
242 QWebEngineSettings.WebAttribute.JavascriptEnabled, True) 249 QWebEngineSettings.WebAttribute.JavascriptEnabled, True
250 )
243 self.triggerAction(QWebEnginePage.WebAction.Reload) 251 self.triggerAction(QWebEnginePage.WebAction.Reload)
244 252
245 @classmethod 253 @classmethod
246 def userAgent(cls, resolveEmpty=False): 254 def userAgent(cls, resolveEmpty=False):
247 """ 255 """
248 Class method to get the global user agent setting. 256 Class method to get the global user agent setting.
249 257
250 @param resolveEmpty flag indicating to resolve an empty 258 @param resolveEmpty flag indicating to resolve an empty
251 user agent (boolean) 259 user agent (boolean)
252 @return user agent string (string) 260 @return user agent string (string)
253 """ 261 """
254 agent = Preferences.getWebBrowser("UserAgent") 262 agent = Preferences.getWebBrowser("UserAgent")
255 if agent == "" and resolveEmpty: 263 if agent == "" and resolveEmpty:
256 agent = cls.userAgentForUrl(QUrl()) 264 agent = cls.userAgentForUrl(QUrl())
257 return agent 265 return agent
258 266
259 @classmethod 267 @classmethod
260 def setUserAgent(cls, agent): 268 def setUserAgent(cls, agent):
261 """ 269 """
262 Class method to set the global user agent string. 270 Class method to set the global user agent string.
263 271
264 @param agent new current user agent string (string) 272 @param agent new current user agent string (string)
265 """ 273 """
266 Preferences.setWebBrowser("UserAgent", agent) 274 Preferences.setWebBrowser("UserAgent", agent)
267 275
268 @classmethod 276 @classmethod
269 def userAgentForUrl(cls, url): 277 def userAgentForUrl(cls, url):
270 """ 278 """
271 Class method to determine the user agent for the given URL. 279 Class method to determine the user agent for the given URL.
272 280
273 @param url URL to determine user agent for (QUrl) 281 @param url URL to determine user agent for (QUrl)
274 @return user agent string (string) 282 @return user agent string (string)
275 """ 283 """
276 agent = WebBrowserWindow.userAgentsManager().userAgentForUrl(url) 284 agent = WebBrowserWindow.userAgentsManager().userAgentForUrl(url)
277 if agent == "": 285 if agent == "":
279 agent = Preferences.getWebBrowser("UserAgent") 287 agent = Preferences.getWebBrowser("UserAgent")
280 if agent == "": 288 if agent == "":
281 # no global agent string specified -> use default one 289 # no global agent string specified -> use default one
282 agent = WebBrowserWindow.webProfile().httpUserAgent() 290 agent = WebBrowserWindow.webProfile().httpUserAgent()
283 return agent 291 return agent
284 292
285 def __featurePermissionRequested(self, url, feature): 293 def __featurePermissionRequested(self, url, feature):
286 """ 294 """
287 Private slot handling a feature permission request. 295 Private slot handling a feature permission request.
288 296
289 @param url url requesting the feature 297 @param url url requesting the feature
290 @type QUrl 298 @type QUrl
291 @param feature requested feature 299 @param feature requested feature
292 @type QWebEnginePage.Feature 300 @type QWebEnginePage.Feature
293 """ 301 """
294 manager = WebBrowserWindow.featurePermissionManager() 302 manager = WebBrowserWindow.featurePermissionManager()
295 manager.requestFeaturePermission(self, url, feature) 303 manager.requestFeaturePermission(self, url, feature)
296 304
297 def execJavaScript(self, script, 305 def execJavaScript(
298 worldId=QWebEngineScript.ScriptWorldId.MainWorld, 306 self, script, worldId=QWebEngineScript.ScriptWorldId.MainWorld, timeout=500
299 timeout=500): 307 ):
300 """ 308 """
301 Public method to execute a JavaScript function synchroneously. 309 Public method to execute a JavaScript function synchroneously.
302 310
303 @param script JavaScript script source to be executed 311 @param script JavaScript script source to be executed
304 @type str 312 @type str
305 @param worldId ID to run the script under 313 @param worldId ID to run the script under
306 @type QWebEngineScript.ScriptWorldId 314 @type QWebEngineScript.ScriptWorldId
307 @param timeout max. time the script is given to execute 315 @param timeout max. time the script is given to execute
310 @rtype depending upon script result 318 @rtype depending upon script result
311 """ 319 """
312 loop = QEventLoop() 320 loop = QEventLoop()
313 resultDict = {"res": None} 321 resultDict = {"res": None}
314 QTimer.singleShot(timeout, loop.quit) 322 QTimer.singleShot(timeout, loop.quit)
315 323
316 def resultCallback(res, resDict=resultDict): 324 def resultCallback(res, resDict=resultDict):
317 if loop and loop.isRunning(): 325 if loop and loop.isRunning():
318 resDict["res"] = res 326 resDict["res"] = res
319 loop.quit() 327 loop.quit()
320 328
321 self.runJavaScript(script, worldId, resultCallback) 329 self.runJavaScript(script, worldId, resultCallback)
322 330
323 loop.exec() 331 loop.exec()
324 return resultDict["res"] 332 return resultDict["res"]
325 333
326 def runJavaScript(self, script, worldId=-1, callback=None): 334 def runJavaScript(self, script, worldId=-1, callback=None):
327 """ 335 """
328 Public method to run a script in the context of the page. 336 Public method to run a script in the context of the page.
329 337
330 @param script JavaScript script source to be executed 338 @param script JavaScript script source to be executed
331 @type str 339 @type str
332 @param worldId ID to run the script under 340 @param worldId ID to run the script under
333 @type int 341 @type int
334 @param callback callback function to be executed when the script has 342 @param callback callback function to be executed when the script has
343 else: 351 else:
344 if callback is None: 352 if callback is None:
345 QWebEnginePage.runJavaScript(self, script) 353 QWebEnginePage.runJavaScript(self, script)
346 else: 354 else:
347 QWebEnginePage.runJavaScript(self, script, callback) 355 QWebEnginePage.runJavaScript(self, script, callback)
348 356
349 def isJavaScriptEnabled(self): 357 def isJavaScriptEnabled(self):
350 """ 358 """
351 Public method to test, if JavaScript is enabled. 359 Public method to test, if JavaScript is enabled.
352 360
353 @return flag indicating the state of the JavaScript support 361 @return flag indicating the state of the JavaScript support
354 @rtype bool 362 @rtype bool
355 """ 363 """
356 return self.settings().testAttribute( 364 return self.settings().testAttribute(
357 QWebEngineSettings.WebAttribute.JavascriptEnabled) 365 QWebEngineSettings.WebAttribute.JavascriptEnabled
358 366 )
367
359 def scroll(self, x, y): 368 def scroll(self, x, y):
360 """ 369 """
361 Public method to scroll by the given amount of pixels. 370 Public method to scroll by the given amount of pixels.
362 371
363 @param x horizontal scroll value 372 @param x horizontal scroll value
364 @type int 373 @type int
365 @param y vertical scroll value 374 @param y vertical scroll value
366 @type int 375 @type int
367 """ 376 """
368 self.runJavaScript( 377 self.runJavaScript(
369 "window.scrollTo(window.scrollX + {0}, window.scrollY + {1})" 378 "window.scrollTo(window.scrollX + {0}, window.scrollY + {1})".format(x, y),
370 .format(x, y), 379 WebBrowserPage.SafeJsWorld,
371 WebBrowserPage.SafeJsWorld 380 )
372 ) 381
373
374 def scrollTo(self, pos): 382 def scrollTo(self, pos):
375 """ 383 """
376 Public method to scroll to the given position. 384 Public method to scroll to the given position.
377 385
378 @param pos position to scroll to 386 @param pos position to scroll to
379 @type QPointF 387 @type QPointF
380 """ 388 """
381 self.runJavaScript( 389 self.runJavaScript(
382 "window.scrollTo({0}, {1});".format(pos.x(), pos.y()), 390 "window.scrollTo({0}, {1});".format(pos.x(), pos.y()),
383 WebBrowserPage.SafeJsWorld 391 WebBrowserPage.SafeJsWorld,
384 ) 392 )
385 393
386 def mapToViewport(self, pos): 394 def mapToViewport(self, pos):
387 """ 395 """
388 Public method to map a position to the viewport. 396 Public method to map a position to the viewport.
389 397
390 @param pos position to be mapped 398 @param pos position to be mapped
391 @type QPoint 399 @type QPoint
392 @return viewport position 400 @return viewport position
393 @rtype QPoint 401 @rtype QPoint
394 """ 402 """
395 return QPoint(int(pos.x() // self.zoomFactor()), 403 return QPoint(
396 int(pos.y() // self.zoomFactor())) 404 int(pos.x() // self.zoomFactor()), int(pos.y() // self.zoomFactor())
397 405 )
406
398 def hitTestContent(self, pos): 407 def hitTestContent(self, pos):
399 """ 408 """
400 Public method to test the content at a specified position. 409 Public method to test the content at a specified position.
401 410
402 @param pos position to execute the test at 411 @param pos position to execute the test at
403 @type QPoint 412 @type QPoint
404 @return test result object 413 @return test result object
405 @rtype WebHitTestResult 414 @rtype WebHitTestResult
406 """ 415 """
407 return WebHitTestResult(self, pos) 416 return WebHitTestResult(self, pos)
408 417
409 def __setupWebChannelForUrl(self, url): 418 def __setupWebChannelForUrl(self, url):
410 """ 419 """
411 Private method to setup a web channel to our external object. 420 Private method to setup a web channel to our external object.
412 421
413 @param url URL for which to setup the web channel 422 @param url URL for which to setup the web channel
414 @type QUrl 423 @type QUrl
415 """ 424 """
416 channel = self.webChannel() 425 channel = self.webChannel()
417 if channel is None: 426 if channel is None:
418 channel = QWebChannel(self) 427 channel = QWebChannel(self)
419 ExternalJsObject.setupWebChannel(channel, self) 428 ExternalJsObject.setupWebChannel(channel, self)
420 429
421 worldId = -1 430 worldId = -1
422 worldId = ( 431 worldId = (
423 self.UnsafeJsWorld 432 self.UnsafeJsWorld
424 if url.scheme() in ("eric", "qthelp") else 433 if url.scheme() in ("eric", "qthelp")
425 self.SafeJsWorld 434 else self.SafeJsWorld
426 ) 435 )
427 if worldId != self.__channelWorldId: 436 if worldId != self.__channelWorldId:
428 self.__channelWorldId = worldId 437 self.__channelWorldId = worldId
429 self.setWebChannel(channel, self.__channelWorldId) 438 self.setWebChannel(channel, self.__channelWorldId)
430 439
431 def certificateError(self, error): 440 def certificateError(self, error):
432 """ 441 """
433 Public method to handle SSL certificate errors. 442 Public method to handle SSL certificate errors.
434 443
435 @param error object containing the certificate error information 444 @param error object containing the certificate error information
436 @type QWebEngineCertificateError 445 @type QWebEngineCertificateError
437 @return flag indicating to ignore this error 446 @return flag indicating to ignore this error
438 @rtype bool 447 @rtype bool
439 """ 448 """
440 return WebBrowserWindow.networkManager().certificateError( 449 return WebBrowserWindow.networkManager().certificateError(error, self.__view)
441 error, self.__view) 450
442
443 def __fullScreenRequested(self, request): 451 def __fullScreenRequested(self, request):
444 """ 452 """
445 Private slot handling a full screen request. 453 Private slot handling a full screen request.
446 454
447 @param request reference to the full screen request 455 @param request reference to the full screen request
448 @type QWebEngineFullScreenRequest 456 @type QWebEngineFullScreenRequest
449 """ 457 """
450 self.__view.requestFullScreen(request.toggleOn()) 458 self.__view.requestFullScreen(request.toggleOn())
451 459
452 accepted = request.toggleOn() == self.__view.isFullScreen() 460 accepted = request.toggleOn() == self.__view.isFullScreen()
453 461
454 if accepted: 462 if accepted:
455 request.accept() 463 request.accept()
456 else: 464 else:
457 request.reject() 465 request.reject()
458 466
459 def execPrintPage(self, printer, timeout=1000): 467 def execPrintPage(self, printer, timeout=1000):
460 """ 468 """
461 Public method to execute a synchronous print. 469 Public method to execute a synchronous print.
462 470
463 @param printer reference to the printer object 471 @param printer reference to the printer object
464 @type QPrinter 472 @type QPrinter
465 @param timeout timeout value in milliseconds 473 @param timeout timeout value in milliseconds
466 @type int 474 @type int
467 @return flag indicating a successful print job 475 @return flag indicating a successful print job
468 @rtype bool 476 @rtype bool
469 """ 477 """
470 loop = QEventLoop() 478 loop = QEventLoop()
471 resultDict = {"res": None} 479 resultDict = {"res": None}
472 QTimer.singleShot(timeout, loop.quit) 480 QTimer.singleShot(timeout, loop.quit)
473 481
474 def printCallback(res, resDict=resultDict): 482 def printCallback(res, resDict=resultDict):
475 if loop and loop.isRunning(): 483 if loop and loop.isRunning():
476 resDict["res"] = res 484 resDict["res"] = res
477 loop.quit() 485 loop.quit()
478 486
479 self.print(printer, printCallback) 487 self.print(printer, printCallback)
480 488
481 loop.exec() 489 loop.exec()
482 return resultDict["res"] 490 return resultDict["res"]
483 491
484 def __contentsSizeChanged(self, size): 492 def __contentsSizeChanged(self, size):
485 """ 493 """
486 Private slot to work around QWebEnginePage not scrolling to anchors 494 Private slot to work around QWebEnginePage not scrolling to anchors
487 when opened in a background tab. 495 when opened in a background tab.
488 496
489 @param size changed contents size (unused) 497 @param size changed contents size (unused)
490 @type QSize 498 @type QSize
491 """ 499 """
492 fragment = self.url().fragment() 500 fragment = self.url().fragment()
493 self.runJavaScript(Scripts.scrollToAnchor(fragment)) 501 self.runJavaScript(Scripts.scrollToAnchor(fragment))
494 502
495 ############################################## 503 ##############################################
496 ## Methods below deal with JavaScript messages 504 ## Methods below deal with JavaScript messages
497 ############################################## 505 ##############################################
498 506
499 def javaScriptConsoleMessage(self, level, message, lineNumber, sourceId): 507 def javaScriptConsoleMessage(self, level, message, lineNumber, sourceId):
500 """ 508 """
501 Public method to show a console message. 509 Public method to show a console message.
502 510
503 @param level severity 511 @param level severity
504 @type QWebEnginePage.JavaScriptConsoleMessageLevel 512 @type QWebEnginePage.JavaScriptConsoleMessageLevel
505 @param message message to be shown 513 @param message message to be shown
506 @type str 514 @type str
507 @param lineNumber line number of an error 515 @param lineNumber line number of an error
508 @type int 516 @type int
509 @param sourceId source URL causing the error 517 @param sourceId source URL causing the error
510 @type str 518 @type str
511 """ 519 """
512 self.__view.mainWindow().javascriptConsole().javaScriptConsoleMessage( 520 self.__view.mainWindow().javascriptConsole().javaScriptConsoleMessage(
513 level, message, lineNumber, sourceId) 521 level, message, lineNumber, sourceId
514 522 )
523
515 ########################################################################### 524 ###########################################################################
516 ## Methods below implement safe browsing related functions 525 ## Methods below implement safe browsing related functions
517 ########################################################################### 526 ###########################################################################
518 527
519 def getSafeBrowsingStatus(self): 528 def getSafeBrowsingStatus(self):
520 """ 529 """
521 Public method to get the safe browsing status of the current page. 530 Public method to get the safe browsing status of the current page.
522 531
523 @return flag indicating a safe site 532 @return flag indicating a safe site
524 @rtype bool 533 @rtype bool
525 """ 534 """
526 return not self.__badSite 535 return not self.__badSite
527 536
528 ############################################################# 537 #############################################################
529 ## Methods below implement protocol handler related functions 538 ## Methods below implement protocol handler related functions
530 ############################################################# 539 #############################################################
531 540
532 @pyqtSlot("QWebEngineRegisterProtocolHandlerRequest") 541 @pyqtSlot("QWebEngineRegisterProtocolHandlerRequest")
533 def __registerProtocolHandlerRequested(self, request): 542 def __registerProtocolHandlerRequested(self, request):
534 """ 543 """
535 Private slot to handle the registration of a custom protocol 544 Private slot to handle the registration of a custom protocol
536 handler. 545 handler.
537 546
538 @param request reference to the registration request 547 @param request reference to the registration request
539 @type QWebEngineRegisterProtocolHandlerRequest 548 @type QWebEngineRegisterProtocolHandlerRequest
540 """ 549 """
541 from PyQt6.QtWebEngineCore import ( 550 from PyQt6.QtWebEngineCore import QWebEngineRegisterProtocolHandlerRequest
542 QWebEngineRegisterProtocolHandlerRequest 551
543 )
544
545 if self.__registerProtocolHandlerRequest: 552 if self.__registerProtocolHandlerRequest:
546 del self.__registerProtocolHandlerRequest 553 del self.__registerProtocolHandlerRequest
547 self.__registerProtocolHandlerRequest = None 554 self.__registerProtocolHandlerRequest = None
548 self.__registerProtocolHandlerRequest = ( 555 self.__registerProtocolHandlerRequest = (
549 QWebEngineRegisterProtocolHandlerRequest(request) 556 QWebEngineRegisterProtocolHandlerRequest(request)
550 ) 557 )
551 558
552 def registerProtocolHandlerRequestUrl(self): 559 def registerProtocolHandlerRequestUrl(self):
553 """ 560 """
554 Public method to get the registered protocol handler request URL. 561 Public method to get the registered protocol handler request URL.
555 562
556 @return registered protocol handler request URL 563 @return registered protocol handler request URL
557 @rtype QUrl 564 @rtype QUrl
558 """ 565 """
559 if ( 566 if self.__registerProtocolHandlerRequest and (
560 self.__registerProtocolHandlerRequest and 567 self.url().host() == self.__registerProtocolHandlerRequest.origin().host()
561 (self.url().host() ==
562 self.__registerProtocolHandlerRequest.origin().host())
563 ): 568 ):
564 return self.__registerProtocolHandlerRequest.origin() 569 return self.__registerProtocolHandlerRequest.origin()
565 else: 570 else:
566 return QUrl() 571 return QUrl()
567 572
568 def registerProtocolHandlerRequestScheme(self): 573 def registerProtocolHandlerRequestScheme(self):
569 """ 574 """
570 Public method to get the registered protocol handler request scheme. 575 Public method to get the registered protocol handler request scheme.
571 576
572 @return registered protocol handler request scheme 577 @return registered protocol handler request scheme
573 @rtype str 578 @rtype str
574 """ 579 """
575 if ( 580 if self.__registerProtocolHandlerRequest and (
576 self.__registerProtocolHandlerRequest and 581 self.url().host() == self.__registerProtocolHandlerRequest.origin().host()
577 (self.url().host() ==
578 self.__registerProtocolHandlerRequest.origin().host())
579 ): 582 ):
580 return self.__registerProtocolHandlerRequest.scheme() 583 return self.__registerProtocolHandlerRequest.scheme()
581 else: 584 else:
582 return "" 585 return ""
583 586
584 ############################################################# 587 #############################################################
585 ## SSL configuration handling below 588 ## SSL configuration handling below
586 ############################################################# 589 #############################################################
587 590
588 def setSslConfiguration(self, sslConfiguration): 591 def setSslConfiguration(self, sslConfiguration):
589 """ 592 """
590 Public slot to set the SSL configuration data of the page. 593 Public slot to set the SSL configuration data of the page.
591 594
592 @param sslConfiguration SSL configuration to be set 595 @param sslConfiguration SSL configuration to be set
593 @type QSslConfiguration 596 @type QSslConfiguration
594 """ 597 """
595 self.__sslConfiguration = QSslConfiguration(sslConfiguration) 598 self.__sslConfiguration = QSslConfiguration(sslConfiguration)
596 self.__sslConfiguration.url = self.url() 599 self.__sslConfiguration.url = self.url()
597 self.sslConfigurationChanged.emit() 600 self.sslConfigurationChanged.emit()
598 601
599 def getSslConfiguration(self): 602 def getSslConfiguration(self):
600 """ 603 """
601 Public method to return a reference to the current SSL configuration. 604 Public method to return a reference to the current SSL configuration.
602 605
603 @return reference to the SSL configuration in use 606 @return reference to the SSL configuration in use
604 @rtype QSslConfiguration 607 @rtype QSslConfiguration
605 """ 608 """
606 return self.__sslConfiguration 609 return self.__sslConfiguration
607 610
608 def clearSslConfiguration(self): 611 def clearSslConfiguration(self):
609 """ 612 """
610 Public slot to clear the stored SSL configuration data. 613 Public slot to clear the stored SSL configuration data.
611 """ 614 """
612 self.__sslConfiguration = None 615 self.__sslConfiguration = None
613 self.sslConfigurationChanged.emit() 616 self.sslConfigurationChanged.emit()
614 617
615 def getSslCertificate(self): 618 def getSslCertificate(self):
616 """ 619 """
617 Public method to get a reference to the SSL certificate. 620 Public method to get a reference to the SSL certificate.
618 621
619 @return amended SSL certificate 622 @return amended SSL certificate
620 @rtype QSslCertificate 623 @rtype QSslCertificate
621 """ 624 """
622 if self.__sslConfiguration is None: 625 if self.__sslConfiguration is None:
623 return None 626 return None
624 627
625 sslCertificate = self.__sslConfiguration.peerCertificate() 628 sslCertificate = self.__sslConfiguration.peerCertificate()
626 sslCertificate.url = QUrl(self.__sslConfiguration.url) 629 sslCertificate.url = QUrl(self.__sslConfiguration.url)
627 return sslCertificate 630 return sslCertificate
628 631
629 def getSslCertificateChain(self): 632 def getSslCertificateChain(self):
630 """ 633 """
631 Public method to get a reference to the SSL certificate chain. 634 Public method to get a reference to the SSL certificate chain.
632 635
633 @return SSL certificate chain 636 @return SSL certificate chain
634 @rtype list of QSslCertificate 637 @rtype list of QSslCertificate
635 """ 638 """
636 if self.__sslConfiguration is None: 639 if self.__sslConfiguration is None:
637 return [] 640 return []
638 641
639 chain = self.__sslConfiguration.peerCertificateChain() 642 chain = self.__sslConfiguration.peerCertificateChain()
640 return chain 643 return chain
641 644
642 def showSslInfo(self, pos): 645 def showSslInfo(self, pos):
643 """ 646 """
644 Public slot to show some SSL information for the loaded page. 647 Public slot to show some SSL information for the loaded page.
645 648
646 @param pos position to show the info at 649 @param pos position to show the info at
647 @type QPoint 650 @type QPoint
648 """ 651 """
649 if SSL_AVAILABLE and self.__sslConfiguration is not None: 652 if SSL_AVAILABLE and self.__sslConfiguration is not None:
650 from EricNetwork.EricSslInfoWidget import EricSslInfoWidget 653 from EricNetwork.EricSslInfoWidget import EricSslInfoWidget
651 widget = EricSslInfoWidget(self.url(), self.__sslConfiguration, 654
652 self.__view) 655 widget = EricSslInfoWidget(self.url(), self.__sslConfiguration, self.__view)
653 widget.showAt(pos) 656 widget.showAt(pos)
654 else: 657 else:
655 EricMessageBox.warning( 658 EricMessageBox.warning(
656 self.__view, 659 self.__view,
657 self.tr("SSL Info"), 660 self.tr("SSL Info"),
658 self.tr("""This site does not contain SSL information.""")) 661 self.tr("""This site does not contain SSL information."""),
659 662 )
663
660 def hasValidSslInfo(self): 664 def hasValidSslInfo(self):
661 """ 665 """
662 Public method to check, if the page has a valid SSL certificate. 666 Public method to check, if the page has a valid SSL certificate.
663 667
664 @return flag indicating a valid SSL certificate 668 @return flag indicating a valid SSL certificate
665 @rtype bool 669 @rtype bool
666 """ 670 """
667 if self.__sslConfiguration is None: 671 if self.__sslConfiguration is None:
668 return False 672 return False
669 673
670 certList = self.__sslConfiguration.peerCertificateChain() 674 certList = self.__sslConfiguration.peerCertificateChain()
671 if not certList: 675 if not certList:
672 return False 676 return False
673 677
674 certificateDict = Globals.toDict( 678 certificateDict = Globals.toDict(
675 Preferences.getSettings().value("Ssl/CaCertificatesDict")) 679 Preferences.getSettings().value("Ssl/CaCertificatesDict")
680 )
676 for server in certificateDict: 681 for server in certificateDict:
677 localCAList = QSslCertificate.fromData(certificateDict[server]) 682 localCAList = QSslCertificate.fromData(certificateDict[server])
678 if any(cert in localCAList for cert in certList): 683 if any(cert in localCAList for cert in certList):
679 return True 684 return True
680 685
681 return all(not cert.isBlacklisted() for cert in certList) 686 return all(not cert.isBlacklisted() for cert in certList)

eric ide

mercurial