src/eric7/WebBrowser/WebBrowserView.py

branch
eric7
changeset 9221
bf71ee032bb4
parent 9209
b99e7fd55fd3
child 9350
8d2b507f8588
equal deleted inserted replaced
9220:e9e7eca7efee 9221:bf71ee032bb4
12 import functools 12 import functools
13 import contextlib 13 import contextlib
14 import pathlib 14 import pathlib
15 15
16 from PyQt6.QtCore import ( 16 from PyQt6.QtCore import (
17 pyqtSignal, pyqtSlot, Qt, QUrl, QTimer, QEvent, QPoint, QPointF, QDateTime, 17 pyqtSignal,
18 QStandardPaths, QByteArray, QIODevice, QDataStream 18 pyqtSlot,
19 Qt,
20 QUrl,
21 QTimer,
22 QEvent,
23 QPoint,
24 QPointF,
25 QDateTime,
26 QStandardPaths,
27 QByteArray,
28 QIODevice,
29 QDataStream,
19 ) 30 )
20 from PyQt6.QtGui import ( 31 from PyQt6.QtGui import (
21 QDesktopServices, QClipboard, QIcon, QContextMenuEvent, QPixmap, QCursor 32 QDesktopServices,
33 QClipboard,
34 QIcon,
35 QContextMenuEvent,
36 QPixmap,
37 QCursor,
22 ) 38 )
23 from PyQt6.QtWidgets import QStyle, QMenu, QApplication, QDialog 39 from PyQt6.QtWidgets import QStyle, QMenu, QApplication, QDialog
24 from PyQt6.QtWebEngineCore import QWebEnginePage, QWebEngineDownloadRequest 40 from PyQt6.QtWebEngineCore import QWebEnginePage, QWebEngineDownloadRequest
25 from PyQt6.QtWebEngineWidgets import QWebEngineView 41 from PyQt6.QtWebEngineWidgets import QWebEngineView
26 42
42 58
43 59
44 class WebBrowserView(QWebEngineView): 60 class WebBrowserView(QWebEngineView):
45 """ 61 """
46 Class implementing the web browser view widget. 62 Class implementing the web browser view widget.
47 63
48 @signal sourceChanged(QUrl) emitted after the current URL has changed 64 @signal sourceChanged(QUrl) emitted after the current URL has changed
49 @signal forwardAvailable(bool) emitted after the current URL has changed 65 @signal forwardAvailable(bool) emitted after the current URL has changed
50 @signal backwardAvailable(bool) emitted after the current URL has changed 66 @signal backwardAvailable(bool) emitted after the current URL has changed
51 @signal highlighted(str) emitted, when the mouse hovers over a link 67 @signal highlighted(str) emitted, when the mouse hovers over a link
52 @signal search(QUrl) emitted, when a search is requested 68 @signal search(QUrl) emitted, when a search is requested
57 @signal safeBrowsingBad(threatType, threatMessages) emitted to indicate a 73 @signal safeBrowsingBad(threatType, threatMessages) emitted to indicate a
58 malicious web site as determined by safe browsing 74 malicious web site as determined by safe browsing
59 @signal showMessage(str) emitted to show a message in the main window 75 @signal showMessage(str) emitted to show a message in the main window
60 status bar 76 status bar
61 """ 77 """
78
62 sourceChanged = pyqtSignal(QUrl) 79 sourceChanged = pyqtSignal(QUrl)
63 forwardAvailable = pyqtSignal(bool) 80 forwardAvailable = pyqtSignal(bool)
64 backwardAvailable = pyqtSignal(bool) 81 backwardAvailable = pyqtSignal(bool)
65 highlighted = pyqtSignal(str) 82 highlighted = pyqtSignal(str)
66 search = pyqtSignal(QUrl) 83 search = pyqtSignal(QUrl)
67 zoomValueChanged = pyqtSignal(int) 84 zoomValueChanged = pyqtSignal(int)
68 faviconChanged = pyqtSignal() 85 faviconChanged = pyqtSignal()
69 safeBrowsingAbort = pyqtSignal() 86 safeBrowsingAbort = pyqtSignal()
70 safeBrowsingBad = pyqtSignal(str, str) 87 safeBrowsingBad = pyqtSignal(str, str)
71 showMessage = pyqtSignal(str) 88 showMessage = pyqtSignal(str)
72 89
73 ZoomLevels = [ 90 ZoomLevels = [
74 30, 40, 50, 67, 80, 90, 91 30,
92 40,
93 50,
94 67,
95 80,
96 90,
75 100, 97 100,
76 110, 120, 133, 150, 170, 200, 220, 233, 250, 270, 285, 300, 98 110,
99 120,
100 133,
101 150,
102 170,
103 200,
104 220,
105 233,
106 250,
107 270,
108 285,
109 300,
77 ] 110 ]
78 ZoomLevelDefault = 100 111 ZoomLevelDefault = 100
79 112
80 def __init__(self, mainWindow, parent=None, name=""): 113 def __init__(self, mainWindow, parent=None, name=""):
81 """ 114 """
82 Constructor 115 Constructor
83 116
84 @param mainWindow reference to the main window (WebBrowserWindow) 117 @param mainWindow reference to the main window (WebBrowserWindow)
85 @param parent parent widget of this window (QWidget) 118 @param parent parent widget of this window (QWidget)
86 @param name name of this window (string) 119 @param name name of this window (string)
87 """ 120 """
88 super().__init__(parent) 121 super().__init__(parent)
89 self.setObjectName(name) 122 self.setObjectName(name)
90 123
91 self.__rwhvqt = None 124 self.__rwhvqt = None
92 self.installEventFilter(self) 125 self.installEventFilter(self)
93 126
94 self.__speedDial = WebBrowserWindow.speedDial() 127 self.__speedDial = WebBrowserWindow.speedDial()
95 128
96 self.__page = None 129 self.__page = None
97 self.__createNewPage() 130 self.__createNewPage()
98 131
99 self.__mw = mainWindow 132 self.__mw = mainWindow
100 self.__tabWidget = parent 133 self.__tabWidget = parent
101 self.__isLoading = False 134 self.__isLoading = False
102 self.__progress = 0 135 self.__progress = 0
103 self.__siteIconLoader = None 136 self.__siteIconLoader = None
104 self.__siteIcon = QIcon() 137 self.__siteIcon = QIcon()
105 self.__menu = QMenu(self) 138 self.__menu = QMenu(self)
106 self.__clickedPos = QPoint() 139 self.__clickedPos = QPoint()
107 self.__firstLoad = False 140 self.__firstLoad = False
108 self.__preview = QPixmap() 141 self.__preview = QPixmap()
109 142
110 self.__currentZoom = 100 143 self.__currentZoom = 100
111 self.__zoomLevels = WebBrowserView.ZoomLevels[:] 144 self.__zoomLevels = WebBrowserView.ZoomLevels[:]
112 145
113 self.iconUrlChanged.connect(self.__iconUrlChanged) 146 self.iconUrlChanged.connect(self.__iconUrlChanged)
114 self.urlChanged.connect(self.__urlChanged) 147 self.urlChanged.connect(self.__urlChanged)
115 self.page().linkHovered.connect(self.__linkHovered) 148 self.page().linkHovered.connect(self.__linkHovered)
116 149
117 self.loadStarted.connect(self.__loadStarted) 150 self.loadStarted.connect(self.__loadStarted)
118 self.loadProgress.connect(self.__loadProgress) 151 self.loadProgress.connect(self.__loadProgress)
119 self.loadFinished.connect(self.__loadFinished) 152 self.loadFinished.connect(self.__loadFinished)
120 self.renderProcessTerminated.connect(self.__renderProcessTerminated) 153 self.renderProcessTerminated.connect(self.__renderProcessTerminated)
121 154
122 self.__mw.openSearchManager().currentEngineChanged.connect( 155 self.__mw.openSearchManager().currentEngineChanged.connect(
123 self.__currentEngineChanged) 156 self.__currentEngineChanged
124 157 )
158
125 self.setAcceptDrops(True) 159 self.setAcceptDrops(True)
126 160
127 self.__rss = [] 161 self.__rss = []
128 162
129 self.__clickedFrame = None 163 self.__clickedFrame = None
130 164
131 self.__mw.personalInformationManager().connectPage(self.page()) 165 self.__mw.personalInformationManager().connectPage(self.page())
132 166
133 self.__inspector = None 167 self.__inspector = None
134 WebInspector.registerView(self) 168 WebInspector.registerView(self)
135 169
136 self.__restoreData = None 170 self.__restoreData = None
137 171
138 if self.parentWidget() is not None: 172 if self.parentWidget() is not None:
139 self.parentWidget().installEventFilter(self) 173 self.parentWidget().installEventFilter(self)
140 174
141 self.grabGesture(Qt.GestureType.PinchGesture) 175 self.grabGesture(Qt.GestureType.PinchGesture)
142 176
143 def __createNewPage(self): 177 def __createNewPage(self):
144 """ 178 """
145 Private method to create a new page object. 179 Private method to create a new page object.
146 """ 180 """
147 self.__page = WebBrowserPage(self, self) 181 self.__page = WebBrowserPage(self, self)
148 self.setPage(self.__page) 182 self.setPage(self.__page)
149 183
150 self.__page.safeBrowsingAbort.connect(self.safeBrowsingAbort) 184 self.__page.safeBrowsingAbort.connect(self.safeBrowsingAbort)
151 self.__page.safeBrowsingBad.connect(self.safeBrowsingBad) 185 self.__page.safeBrowsingBad.connect(self.safeBrowsingBad)
152 self.__page.printPageRequested.connect(self.__printPage) 186 self.__page.printPageRequested.connect(self.__printPage)
153 self.__page.quotaRequested.connect(self.__quotaRequested) 187 self.__page.quotaRequested.connect(self.__quotaRequested)
154 # The registerProtocolHandlerRequested signal is handled in 188 # The registerProtocolHandlerRequested signal is handled in
155 # WebBrowserPage. 189 # WebBrowserPage.
156 self.__page.selectClientCertificate.connect( 190 self.__page.selectClientCertificate.connect(self.__selectClientCertificate)
157 self.__selectClientCertificate)
158 self.__page.findTextFinished.connect(self.__findTextFinished) 191 self.__page.findTextFinished.connect(self.__findTextFinished)
159 192
160 def __setRwhvqt(self): 193 def __setRwhvqt(self):
161 """ 194 """
162 Private slot to set widget that receives input events. 195 Private slot to set widget that receives input events.
163 """ 196 """
164 self.grabGesture(Qt.GestureType.PinchGesture) 197 self.grabGesture(Qt.GestureType.PinchGesture)
165 self.__rwhvqt = self.focusProxy() 198 self.__rwhvqt = self.focusProxy()
166 if self.__rwhvqt: 199 if self.__rwhvqt:
167 self.__rwhvqt.grabGesture(Qt.GestureType.PinchGesture) 200 self.__rwhvqt.grabGesture(Qt.GestureType.PinchGesture)
168 self.__rwhvqt.installEventFilter(self) 201 self.__rwhvqt.installEventFilter(self)
169 else: 202 else:
170 print("Focus proxy is null!") # __IGNORE_WARNING_M801__ 203 print("Focus proxy is null!") # __IGNORE_WARNING_M801__
171 204
172 def __currentEngineChanged(self): 205 def __currentEngineChanged(self):
173 """ 206 """
174 Private slot to track a change of the current search engine. 207 Private slot to track a change of the current search engine.
175 """ 208 """
176 if self.url().toString() == "eric:home": 209 if self.url().toString() == "eric:home":
177 self.reload() 210 self.reload()
178 211
179 def mainWindow(self): 212 def mainWindow(self):
180 """ 213 """
181 Public method to get a reference to the main window. 214 Public method to get a reference to the main window.
182 215
183 @return reference to the main window 216 @return reference to the main window
184 @rtype WebBrowserWindow 217 @rtype WebBrowserWindow
185 """ 218 """
186 return self.__mw 219 return self.__mw
187 220
188 def tabWidget(self): 221 def tabWidget(self):
189 """ 222 """
190 Public method to get a reference to the tab widget containing this 223 Public method to get a reference to the tab widget containing this
191 view. 224 view.
192 225
193 @return reference to the tab widget 226 @return reference to the tab widget
194 @rtype WebBrowserTabWidget 227 @rtype WebBrowserTabWidget
195 """ 228 """
196 return self.__tabWidget 229 return self.__tabWidget
197 230
198 def load(self, url): 231 def load(self, url):
199 """ 232 """
200 Public method to load a web site. 233 Public method to load a web site.
201 234
202 @param url URL to be loaded 235 @param url URL to be loaded
203 @type QUrl 236 @type QUrl
204 """ 237 """
205 if ( 238 if self.__page is not None and not self.__page.acceptNavigationRequest(
206 self.__page is not None and 239 url, QWebEnginePage.NavigationType.NavigationTypeTyped, True
207 not self.__page.acceptNavigationRequest(
208 url, QWebEnginePage.NavigationType.NavigationTypeTyped, True)
209 ): 240 ):
210 return 241 return
211 242
212 super().load(url) 243 super().load(url)
213 244
214 if not self.__firstLoad: 245 if not self.__firstLoad:
215 self.__firstLoad = True 246 self.__firstLoad = True
216 WebInspector.pushView(self) 247 WebInspector.pushView(self)
217 248
218 def setSource(self, name, newTab=False): 249 def setSource(self, name, newTab=False):
219 """ 250 """
220 Public method used to set the source to be displayed. 251 Public method used to set the source to be displayed.
221 252
222 @param name filename to be shown (QUrl) 253 @param name filename to be shown (QUrl)
223 @param newTab flag indicating to open the URL in a new tab (bool) 254 @param newTab flag indicating to open the URL in a new tab (bool)
224 """ 255 """
225 if name is None or not name.isValid(): 256 if name is None or not name.isValid():
226 return 257 return
227 258
228 if newTab: 259 if newTab:
229 # open in a new tab 260 # open in a new tab
230 self.__mw.newTab(name) 261 self.__mw.newTab(name)
231 return 262 return
232 263
233 if not name.scheme(): 264 if not name.scheme():
234 if not os.path.exists(name.toString()): 265 if not os.path.exists(name.toString()):
235 name.setScheme(Preferences.getWebBrowser("DefaultScheme")) 266 name.setScheme(Preferences.getWebBrowser("DefaultScheme"))
236 else: 267 else:
237 if Utilities.isWindowsPlatform(): 268 if Utilities.isWindowsPlatform():
238 name.setUrl("file:///" + Utilities.fromNativeSeparators( 269 name.setUrl(
239 name.toString())) 270 "file:///" + Utilities.fromNativeSeparators(name.toString())
271 )
240 else: 272 else:
241 name.setUrl("file://" + name.toString()) 273 name.setUrl("file://" + name.toString())
242 274
243 if ( 275 if len(name.scheme()) == 1 or name.scheme() == "file":
244 len(name.scheme()) == 1 or
245 name.scheme() == "file"
246 ):
247 # name is a local file 276 # name is a local file
248 if name.scheme() and len(name.scheme()) == 1: 277 if name.scheme() and len(name.scheme()) == 1:
249 # it is a local path on win os 278 # it is a local path on win os
250 name = QUrl.fromLocalFile(name.toString()) 279 name = QUrl.fromLocalFile(name.toString())
251 280
252 if not pathlib.Path(name.toLocalFile()).exists(): 281 if not pathlib.Path(name.toLocalFile()).exists():
253 EricMessageBox.critical( 282 EricMessageBox.critical(
254 self, 283 self,
255 self.tr("eric Web Browser"), 284 self.tr("eric Web Browser"),
256 self.tr( 285 self.tr("""<p>The file <b>{0}</b> does not exist.</p>""").format(
257 """<p>The file <b>{0}</b> does not exist.</p>""") 286 name.toLocalFile()
258 .format(name.toLocalFile())) 287 ),
288 )
259 return 289 return
260 290
261 if name.toLocalFile().lower().endswith((".pdf", ".chm")): 291 if name.toLocalFile().lower().endswith((".pdf", ".chm")):
262 started = QDesktopServices.openUrl(name) 292 started = QDesktopServices.openUrl(name)
263 if not started: 293 if not started:
264 EricMessageBox.critical( 294 EricMessageBox.critical(
265 self, 295 self,
266 self.tr("eric Web Browser"), 296 self.tr("eric Web Browser"),
267 self.tr( 297 self.tr(
268 """<p>Could not start a viewer""" 298 """<p>Could not start a viewer"""
269 """ for file <b>{0}</b>.</p>""") 299 """ for file <b>{0}</b>.</p>"""
270 .format(name.path())) 300 ).format(name.path()),
301 )
271 return 302 return
272 elif name.scheme() in ["mailto"]: 303 elif name.scheme() in ["mailto"]:
273 started = QDesktopServices.openUrl(name) 304 started = QDesktopServices.openUrl(name)
274 if not started: 305 if not started:
275 EricMessageBox.critical( 306 EricMessageBox.critical(
276 self, 307 self,
277 self.tr("eric Web Browser"), 308 self.tr("eric Web Browser"),
278 self.tr( 309 self.tr(
279 """<p>Could not start an application""" 310 """<p>Could not start an application"""
280 """ for URL <b>{0}</b>.</p>""") 311 """ for URL <b>{0}</b>.</p>"""
281 .format(name.toString())) 312 ).format(name.toString()),
313 )
282 return 314 return
283 else: 315 else:
284 if name.toString().lower().endswith((".pdf", ".chm")): 316 if name.toString().lower().endswith((".pdf", ".chm")):
285 started = QDesktopServices.openUrl(name) 317 started = QDesktopServices.openUrl(name)
286 if not started: 318 if not started:
287 EricMessageBox.critical( 319 EricMessageBox.critical(
288 self, 320 self,
289 self.tr("eric Web Browser"), 321 self.tr("eric Web Browser"),
290 self.tr( 322 self.tr(
291 """<p>Could not start a viewer""" 323 """<p>Could not start a viewer"""
292 """ for file <b>{0}</b>.</p>""") 324 """ for file <b>{0}</b>.</p>"""
293 .format(name.path())) 325 ).format(name.path()),
326 )
294 return 327 return
295 328
296 self.load(name) 329 self.load(name)
297 330
298 def source(self): 331 def source(self):
299 """ 332 """
300 Public method to return the URL of the loaded page. 333 Public method to return the URL of the loaded page.
301 334
302 @return URL loaded in the help browser (QUrl) 335 @return URL loaded in the help browser (QUrl)
303 """ 336 """
304 return self.url() 337 return self.url()
305 338
306 def documentTitle(self): 339 def documentTitle(self):
307 """ 340 """
308 Public method to return the title of the loaded page. 341 Public method to return the title of the loaded page.
309 342
310 @return title (string) 343 @return title (string)
311 """ 344 """
312 return self.title() 345 return self.title()
313 346
314 def backward(self): 347 def backward(self):
315 """ 348 """
316 Public slot to move backwards in history. 349 Public slot to move backwards in history.
317 """ 350 """
318 self.triggerPageAction(QWebEnginePage.WebAction.Back) 351 self.triggerPageAction(QWebEnginePage.WebAction.Back)
319 self.__urlChanged(self.history().currentItem().url()) 352 self.__urlChanged(self.history().currentItem().url())
320 353
321 def forward(self): 354 def forward(self):
322 """ 355 """
323 Public slot to move forward in history. 356 Public slot to move forward in history.
324 """ 357 """
325 self.triggerPageAction(QWebEnginePage.WebAction.Forward) 358 self.triggerPageAction(QWebEnginePage.WebAction.Forward)
326 self.__urlChanged(self.history().currentItem().url()) 359 self.__urlChanged(self.history().currentItem().url())
327 360
328 def home(self): 361 def home(self):
329 """ 362 """
330 Public slot to move to the first page loaded. 363 Public slot to move to the first page loaded.
331 """ 364 """
332 homeUrl = QUrl(Preferences.getWebBrowser("HomePage")) 365 homeUrl = QUrl(Preferences.getWebBrowser("HomePage"))
333 self.setSource(homeUrl) 366 self.setSource(homeUrl)
334 self.__urlChanged(self.history().currentItem().url()) 367 self.__urlChanged(self.history().currentItem().url())
335 368
336 def reload(self): 369 def reload(self):
337 """ 370 """
338 Public slot to reload the current page. 371 Public slot to reload the current page.
339 """ 372 """
340 self.triggerPageAction(QWebEnginePage.WebAction.Reload) 373 self.triggerPageAction(QWebEnginePage.WebAction.Reload)
341 374
342 def reloadBypassingCache(self): 375 def reloadBypassingCache(self):
343 """ 376 """
344 Public slot to reload the current page bypassing the cache. 377 Public slot to reload the current page bypassing the cache.
345 """ 378 """
346 self.triggerPageAction(QWebEnginePage.WebAction.ReloadAndBypassCache) 379 self.triggerPageAction(QWebEnginePage.WebAction.ReloadAndBypassCache)
347 380
348 def copy(self): 381 def copy(self):
349 """ 382 """
350 Public slot to copy the selected text. 383 Public slot to copy the selected text.
351 """ 384 """
352 self.triggerPageAction(QWebEnginePage.WebAction.Copy) 385 self.triggerPageAction(QWebEnginePage.WebAction.Copy)
353 386
354 def cut(self): 387 def cut(self):
355 """ 388 """
356 Public slot to cut the selected text. 389 Public slot to cut the selected text.
357 """ 390 """
358 self.triggerPageAction(QWebEnginePage.WebAction.Cut) 391 self.triggerPageAction(QWebEnginePage.WebAction.Cut)
359 392
360 def paste(self): 393 def paste(self):
361 """ 394 """
362 Public slot to paste text from the clipboard. 395 Public slot to paste text from the clipboard.
363 """ 396 """
364 self.triggerPageAction(QWebEnginePage.WebAction.Paste) 397 self.triggerPageAction(QWebEnginePage.WebAction.Paste)
365 398
366 def undo(self): 399 def undo(self):
367 """ 400 """
368 Public slot to undo the last edit action. 401 Public slot to undo the last edit action.
369 """ 402 """
370 self.triggerPageAction(QWebEnginePage.WebAction.Undo) 403 self.triggerPageAction(QWebEnginePage.WebAction.Undo)
371 404
372 def redo(self): 405 def redo(self):
373 """ 406 """
374 Public slot to redo the last edit action. 407 Public slot to redo the last edit action.
375 """ 408 """
376 self.triggerPageAction(QWebEnginePage.WebAction.Redo) 409 self.triggerPageAction(QWebEnginePage.WebAction.Redo)
377 410
378 def selectAll(self): 411 def selectAll(self):
379 """ 412 """
380 Public slot to select all text. 413 Public slot to select all text.
381 """ 414 """
382 self.triggerPageAction(QWebEnginePage.WebAction.SelectAll) 415 self.triggerPageAction(QWebEnginePage.WebAction.SelectAll)
383 416
384 def unselect(self): 417 def unselect(self):
385 """ 418 """
386 Public slot to clear the current selection. 419 Public slot to clear the current selection.
387 """ 420 """
388 self.triggerPageAction(QWebEnginePage.WebAction.Unselect) 421 self.triggerPageAction(QWebEnginePage.WebAction.Unselect)
389 422
390 def isForwardAvailable(self): 423 def isForwardAvailable(self):
391 """ 424 """
392 Public method to determine, if a forward move in history is possible. 425 Public method to determine, if a forward move in history is possible.
393 426
394 @return flag indicating move forward is possible (boolean) 427 @return flag indicating move forward is possible (boolean)
395 """ 428 """
396 return self.history().canGoForward() 429 return self.history().canGoForward()
397 430
398 def isBackwardAvailable(self): 431 def isBackwardAvailable(self):
399 """ 432 """
400 Public method to determine, if a backwards move in history is possible. 433 Public method to determine, if a backwards move in history is possible.
401 434
402 @return flag indicating move backwards is possible (boolean) 435 @return flag indicating move backwards is possible (boolean)
403 """ 436 """
404 return self.history().canGoBack() 437 return self.history().canGoBack()
405 438
406 def __levelForZoom(self, zoom): 439 def __levelForZoom(self, zoom):
407 """ 440 """
408 Private method determining the zoom level index given a zoom factor. 441 Private method determining the zoom level index given a zoom factor.
409 442
410 @param zoom zoom factor (integer) 443 @param zoom zoom factor (integer)
411 @return index of zoom factor (integer) 444 @return index of zoom factor (integer)
412 """ 445 """
413 try: 446 try:
414 index = self.__zoomLevels.index(zoom) 447 index = self.__zoomLevels.index(zoom)
415 except ValueError: 448 except ValueError:
416 for index in range(len(self.__zoomLevels)): 449 for index in range(len(self.__zoomLevels)):
417 if zoom <= self.__zoomLevels[index]: 450 if zoom <= self.__zoomLevels[index]:
418 break 451 break
419 return index 452 return index
420 453
421 def setZoomValue(self, value, saveValue=True): 454 def setZoomValue(self, value, saveValue=True):
422 """ 455 """
423 Public method to set the zoom value. 456 Public method to set the zoom value.
424 457
425 @param value zoom value (integer) 458 @param value zoom value (integer)
426 @param saveValue flag indicating to save the zoom value with the 459 @param saveValue flag indicating to save the zoom value with the
427 zoom manager 460 zoom manager
428 @type bool 461 @type bool
429 """ 462 """
430 if value != self.__currentZoom: 463 if value != self.__currentZoom:
431 self.setZoomFactor(value / 100.0) 464 self.setZoomFactor(value / 100.0)
432 self.__currentZoom = value 465 self.__currentZoom = value
433 if saveValue and not self.__mw.isPrivate(): 466 if saveValue and not self.__mw.isPrivate():
434 from .ZoomManager import ZoomManager 467 from .ZoomManager import ZoomManager
468
435 ZoomManager.instance().setZoomValue(self.url(), value) 469 ZoomManager.instance().setZoomValue(self.url(), value)
436 self.zoomValueChanged.emit(value) 470 self.zoomValueChanged.emit(value)
437 471
438 def zoomValue(self): 472 def zoomValue(self):
439 """ 473 """
440 Public method to get the current zoom value. 474 Public method to get the current zoom value.
441 475
442 @return zoom value (integer) 476 @return zoom value (integer)
443 """ 477 """
444 val = self.zoomFactor() * 100 478 val = self.zoomFactor() * 100
445 return int(val) 479 return int(val)
446 480
447 def zoomIn(self): 481 def zoomIn(self):
448 """ 482 """
449 Public slot to zoom into the page. 483 Public slot to zoom into the page.
450 """ 484 """
451 index = self.__levelForZoom(self.__currentZoom) 485 index = self.__levelForZoom(self.__currentZoom)
452 if index < len(self.__zoomLevels) - 1: 486 if index < len(self.__zoomLevels) - 1:
453 self.setZoomValue(self.__zoomLevels[index + 1]) 487 self.setZoomValue(self.__zoomLevels[index + 1])
454 488
455 def zoomOut(self): 489 def zoomOut(self):
456 """ 490 """
457 Public slot to zoom out of the page. 491 Public slot to zoom out of the page.
458 """ 492 """
459 index = self.__levelForZoom(self.__currentZoom) 493 index = self.__levelForZoom(self.__currentZoom)
460 if index > 0: 494 if index > 0:
461 self.setZoomValue(self.__zoomLevels[index - 1]) 495 self.setZoomValue(self.__zoomLevels[index - 1])
462 496
463 def zoomReset(self): 497 def zoomReset(self):
464 """ 498 """
465 Public method to reset the zoom factor. 499 Public method to reset the zoom factor.
466 """ 500 """
467 index = self.__levelForZoom(WebBrowserView.ZoomLevelDefault) 501 index = self.__levelForZoom(WebBrowserView.ZoomLevelDefault)
468 self.setZoomValue(self.__zoomLevels[index]) 502 self.setZoomValue(self.__zoomLevels[index])
469 503
470 def mapToViewport(self, pos): 504 def mapToViewport(self, pos):
471 """ 505 """
472 Public method to map a position to the viewport. 506 Public method to map a position to the viewport.
473 507
474 @param pos position to be mapped 508 @param pos position to be mapped
475 @type QPoint 509 @type QPoint
476 @return viewport position 510 @return viewport position
477 @rtype QPoint 511 @rtype QPoint
478 """ 512 """
479 return self.page().mapToViewport(pos) 513 return self.page().mapToViewport(pos)
480 514
481 def hasSelection(self): 515 def hasSelection(self):
482 """ 516 """
483 Public method to determine, if there is some text selected. 517 Public method to determine, if there is some text selected.
484 518
485 @return flag indicating text has been selected (boolean) 519 @return flag indicating text has been selected (boolean)
486 """ 520 """
487 return self.selectedText() != "" 521 return self.selectedText() != ""
488 522
489 def findNextPrev(self, txt, case, backwards, callback): 523 def findNextPrev(self, txt, case, backwards, callback):
490 """ 524 """
491 Public slot to find the next occurrence of a text. 525 Public slot to find the next occurrence of a text.
492 526
493 @param txt text to search for (string) 527 @param txt text to search for (string)
494 @param case flag indicating a case sensitive search (boolean) 528 @param case flag indicating a case sensitive search (boolean)
495 @param backwards flag indicating a backwards search (boolean) 529 @param backwards flag indicating a backwards search (boolean)
496 @param callback reference to a function with a bool parameter 530 @param callback reference to a function with a bool parameter
497 @type function(bool) or None 531 @type function(bool) or None
499 findFlags = QWebEnginePage.FindFlag(0) 533 findFlags = QWebEnginePage.FindFlag(0)
500 if case: 534 if case:
501 findFlags |= QWebEnginePage.FindFlag.FindCaseSensitively 535 findFlags |= QWebEnginePage.FindFlag.FindCaseSensitively
502 if backwards: 536 if backwards:
503 findFlags |= QWebEnginePage.FindFlag.FindBackward 537 findFlags |= QWebEnginePage.FindFlag.FindBackward
504 538
505 if callback is None: 539 if callback is None:
506 self.findText(txt, findFlags) 540 self.findText(txt, findFlags)
507 else: 541 else:
508 self.findText(txt, findFlags, callback) 542 self.findText(txt, findFlags, callback)
509 543
510 def __findTextFinished(self, result): 544 def __findTextFinished(self, result):
511 """ 545 """
512 Private slot handling the findTextFinished signal of the web page. 546 Private slot handling the findTextFinished signal of the web page.
513 547
514 @param result reference to the QWebEngineFindTextResult object of the 548 @param result reference to the QWebEngineFindTextResult object of the
515 last search 549 last search
516 @type QWebEngineFindTextResult 550 @type QWebEngineFindTextResult
517 """ 551 """
518 self.showMessage.emit(self.tr("Match {0} of {1}").format( 552 self.showMessage.emit(
519 result.activeMatch(), result.numberOfMatches()) 553 self.tr("Match {0} of {1}").format(
520 ) 554 result.activeMatch(), result.numberOfMatches()
521 555 )
556 )
557
522 def contextMenuEvent(self, evt): 558 def contextMenuEvent(self, evt):
523 """ 559 """
524 Protected method called to create a context menu. 560 Protected method called to create a context menu.
525 561
526 This method is overridden from QWebEngineView. 562 This method is overridden from QWebEngineView.
527 563
528 @param evt reference to the context menu event object 564 @param evt reference to the context menu event object
529 (QContextMenuEvent) 565 (QContextMenuEvent)
530 """ 566 """
531 pos = evt.pos() 567 pos = evt.pos()
532 reason = evt.reason() 568 reason = evt.reason()
533 QTimer.singleShot( 569 QTimer.singleShot(
534 0, functools.partial( 570 0, functools.partial(self._contextMenuEvent, QContextMenuEvent(reason, pos))
535 self._contextMenuEvent, QContextMenuEvent(reason, pos))) 571 )
536 # needs to be done this way because contextMenuEvent is blocking 572 # needs to be done this way because contextMenuEvent is blocking
537 # the main loop 573 # the main loop
538 574
539 def _contextMenuEvent(self, evt): 575 def _contextMenuEvent(self, evt):
540 """ 576 """
541 Protected method called to create a context menu. 577 Protected method called to create a context menu.
542 578
543 @param evt reference to the context menu event object 579 @param evt reference to the context menu event object
544 (QContextMenuEvent) 580 (QContextMenuEvent)
545 """ 581 """
546 self.__menu.clear() 582 self.__menu.clear()
547 583
548 hitTest = self.page().hitTestContent(evt.pos()) 584 hitTest = self.page().hitTestContent(evt.pos())
549 585
550 self.__createContextMenu(self.__menu, hitTest) 586 self.__createContextMenu(self.__menu, hitTest)
551 587
552 if not hitTest.isContentEditable() and not hitTest.isContentSelected(): 588 if not hitTest.isContentEditable() and not hitTest.isContentSelected():
553 self.__menu.addSeparator() 589 self.__menu.addSeparator()
554 self.__menu.addMenu(self.__mw.adBlockIcon().menu()) 590 self.__menu.addMenu(self.__mw.adBlockIcon().menu())
555 591
556 self.__menu.addSeparator() 592 self.__menu.addSeparator()
557 self.__menu.addAction( 593 self.__menu.addAction(
558 UI.PixmapCache.getIcon("webInspector"), 594 UI.PixmapCache.getIcon("webInspector"),
559 self.tr("Inspect Element..."), self.__webInspector) 595 self.tr("Inspect Element..."),
560 596 self.__webInspector,
597 )
598
561 if not self.__menu.isEmpty(): 599 if not self.__menu.isEmpty():
562 pos = evt.globalPos() 600 pos = evt.globalPos()
563 self.__menu.popup(QPoint(pos.x(), pos.y() + 1)) 601 self.__menu.popup(QPoint(pos.x(), pos.y() + 1))
564 602
565 def __createContextMenu(self, menu, hitTest): 603 def __createContextMenu(self, menu, hitTest):
566 """ 604 """
567 Private method to populate the context menu. 605 Private method to populate the context menu.
568 606
569 @param menu reference to the menu to be populated 607 @param menu reference to the menu to be populated
570 @type QMenu 608 @type QMenu
571 @param hitTest reference to the hit test object 609 @param hitTest reference to the hit test object
572 @type WebHitTestResult 610 @type WebHitTestResult
573 """ 611 """
574 spellCheckActionCount = 0 612 spellCheckActionCount = 0
575 contextMenuData = self.lastContextMenuRequest() 613 contextMenuData = self.lastContextMenuRequest()
576 hitTest.updateWithContextMenuData(contextMenuData) 614 hitTest.updateWithContextMenuData(contextMenuData)
577 615
578 if bool(contextMenuData.misspelledWord()): 616 if bool(contextMenuData.misspelledWord()):
579 boldFont = menu.font() 617 boldFont = menu.font()
580 boldFont.setBold(True) 618 boldFont.setBold(True)
581 619
582 for suggestion in contextMenuData.spellCheckerSuggestions(): 620 for suggestion in contextMenuData.spellCheckerSuggestions():
583 act = menu.addAction(suggestion) 621 act = menu.addAction(suggestion)
584 act.setFont(boldFont) 622 act.setFont(boldFont)
585 act.triggered.connect( 623 act.triggered.connect(
586 functools.partial(self.__replaceMisspelledWord, act)) 624 functools.partial(self.__replaceMisspelledWord, act)
587 625 )
626
588 if not bool(menu.actions()): 627 if not bool(menu.actions()):
589 menu.addAction(self.tr("No suggestions")).setEnabled(False) 628 menu.addAction(self.tr("No suggestions")).setEnabled(False)
590 629
591 menu.addSeparator() 630 menu.addSeparator()
592 spellCheckActionCount = len(menu.actions()) 631 spellCheckActionCount = len(menu.actions())
593 632
594 if ( 633 if (
595 not hitTest.linkUrl().isEmpty() and 634 not hitTest.linkUrl().isEmpty()
596 hitTest.linkUrl().scheme() != "javascript" 635 and hitTest.linkUrl().scheme() != "javascript"
597 ): 636 ):
598 self.__createLinkContextMenu(menu, hitTest) 637 self.__createLinkContextMenu(menu, hitTest)
599 638
600 if not hitTest.imageUrl().isEmpty(): 639 if not hitTest.imageUrl().isEmpty():
601 self.__createImageContextMenu(menu, hitTest) 640 self.__createImageContextMenu(menu, hitTest)
602 641
603 if not hitTest.mediaUrl().isEmpty(): 642 if not hitTest.mediaUrl().isEmpty():
604 self.__createMediaContextMenu(menu, hitTest) 643 self.__createMediaContextMenu(menu, hitTest)
605 644
606 if hitTest.isContentEditable(): 645 if hitTest.isContentEditable():
607 # check, if only spell checker actions were added 646 # check, if only spell checker actions were added
608 if len(menu.actions()) == spellCheckActionCount: 647 if len(menu.actions()) == spellCheckActionCount:
609 menu.addAction(self.__mw.undoAct) 648 menu.addAction(self.__mw.undoAct)
610 menu.addAction(self.__mw.redoAct) 649 menu.addAction(self.__mw.redoAct)
612 menu.addAction(self.__mw.cutAct) 651 menu.addAction(self.__mw.cutAct)
613 menu.addAction(self.__mw.copyAct) 652 menu.addAction(self.__mw.copyAct)
614 menu.addAction(self.__mw.pasteAct) 653 menu.addAction(self.__mw.pasteAct)
615 menu.addSeparator() 654 menu.addSeparator()
616 self.__mw.personalInformationManager().createSubMenu( 655 self.__mw.personalInformationManager().createSubMenu(
617 menu, self, hitTest) 656 menu, self, hitTest
618 657 )
658
619 if hitTest.tagName() == "input": 659 if hitTest.tagName() == "input":
620 menu.addSeparator() 660 menu.addSeparator()
621 act = menu.addAction("") 661 act = menu.addAction("")
622 act.setVisible(False) 662 act.setVisible(False)
623 self.__checkForForm(act, hitTest.pos()) 663 self.__checkForForm(act, hitTest.pos())
624 664
625 if self.selectedText(): 665 if self.selectedText():
626 self.__createSelectedTextContextMenu(menu, hitTest) 666 self.__createSelectedTextContextMenu(menu, hitTest)
627 667
628 if self.__menu.isEmpty(): 668 if self.__menu.isEmpty():
629 self.__createPageContextMenu(menu) 669 self.__createPageContextMenu(menu)
630 670
631 def __createLinkContextMenu(self, menu, hitTest): 671 def __createLinkContextMenu(self, menu, hitTest):
632 """ 672 """
633 Private method to populate the context menu for URLs. 673 Private method to populate the context menu for URLs.
634 674
635 @param menu reference to the menu to be populated 675 @param menu reference to the menu to be populated
636 @type QMenu 676 @type QMenu
637 @param hitTest reference to the hit test object 677 @param hitTest reference to the hit test object
638 @type WebHitTestResult 678 @type WebHitTestResult
639 """ 679 """
640 if not menu.isEmpty(): 680 if not menu.isEmpty():
641 menu.addSeparator() 681 menu.addSeparator()
642 682
643 act = menu.addAction( 683 act = menu.addAction(
644 UI.PixmapCache.getIcon("openNewTab"), 684 UI.PixmapCache.getIcon("openNewTab"),
645 self.tr("Open Link in New Tab\tCtrl+LMB")) 685 self.tr("Open Link in New Tab\tCtrl+LMB"),
686 )
646 act.setData(hitTest.linkUrl()) 687 act.setData(hitTest.linkUrl())
647 act.triggered.connect( 688 act.triggered.connect(functools.partial(self.__openLinkInNewTab, act))
648 functools.partial(self.__openLinkInNewTab, act))
649 act = menu.addAction( 689 act = menu.addAction(
650 UI.PixmapCache.getIcon("newWindow"), 690 UI.PixmapCache.getIcon("newWindow"), self.tr("Open Link in New Window")
651 self.tr("Open Link in New Window")) 691 )
652 act.setData(hitTest.linkUrl()) 692 act.setData(hitTest.linkUrl())
653 act.triggered.connect( 693 act.triggered.connect(functools.partial(self.__openLinkInNewWindow, act))
654 functools.partial(self.__openLinkInNewWindow, act))
655 act = menu.addAction( 694 act = menu.addAction(
656 UI.PixmapCache.getIcon("privateMode"), 695 UI.PixmapCache.getIcon("privateMode"),
657 self.tr("Open Link in New Private Window")) 696 self.tr("Open Link in New Private Window"),
697 )
658 act.setData(hitTest.linkUrl()) 698 act.setData(hitTest.linkUrl())
659 act.triggered.connect( 699 act.triggered.connect(functools.partial(self.__openLinkInNewPrivateWindow, act))
660 functools.partial(self.__openLinkInNewPrivateWindow, act))
661 menu.addSeparator() 700 menu.addSeparator()
662 menu.addAction( 701 menu.addAction(
663 UI.PixmapCache.getIcon("download"), 702 UI.PixmapCache.getIcon("download"),
664 self.tr("Save Lin&k"), self.__downloadLink) 703 self.tr("Save Lin&k"),
704 self.__downloadLink,
705 )
665 act = menu.addAction( 706 act = menu.addAction(
666 UI.PixmapCache.getIcon("bookmark22"), 707 UI.PixmapCache.getIcon("bookmark22"), self.tr("Bookmark this Link")
667 self.tr("Bookmark this Link")) 708 )
668 act.setData(hitTest.linkUrl()) 709 act.setData(hitTest.linkUrl())
669 act.triggered.connect( 710 act.triggered.connect(functools.partial(self.__bookmarkLink, act))
670 functools.partial(self.__bookmarkLink, act))
671 menu.addSeparator() 711 menu.addSeparator()
672 act = menu.addAction( 712 act = menu.addAction(
673 UI.PixmapCache.getIcon("editCopy"), 713 UI.PixmapCache.getIcon("editCopy"), self.tr("Copy URL to Clipboard")
674 self.tr("Copy URL to Clipboard")) 714 )
675 act.setData(hitTest.linkUrl()) 715 act.setData(hitTest.linkUrl())
676 act.triggered.connect( 716 act.triggered.connect(functools.partial(self.__copyLink, act))
677 functools.partial(self.__copyLink, act)) 717 act = menu.addAction(UI.PixmapCache.getIcon("mailSend"), self.tr("Send URL"))
678 act = menu.addAction(
679 UI.PixmapCache.getIcon("mailSend"),
680 self.tr("Send URL"))
681 act.setData(hitTest.linkUrl()) 718 act.setData(hitTest.linkUrl())
682 act.triggered.connect( 719 act.triggered.connect(functools.partial(self.__sendLink, act))
683 functools.partial(self.__sendLink, act))
684 if ( 720 if (
685 Preferences.getWebBrowser("VirusTotalEnabled") and 721 Preferences.getWebBrowser("VirusTotalEnabled")
686 Preferences.getWebBrowser("VirusTotalServiceKey") != "" 722 and Preferences.getWebBrowser("VirusTotalServiceKey") != ""
687 ): 723 ):
688 act = menu.addAction( 724 act = menu.addAction(
689 UI.PixmapCache.getIcon("virustotal"), 725 UI.PixmapCache.getIcon("virustotal"),
690 self.tr("Scan Link with VirusTotal")) 726 self.tr("Scan Link with VirusTotal"),
727 )
691 act.setData(hitTest.linkUrl()) 728 act.setData(hitTest.linkUrl())
692 act.triggered.connect( 729 act.triggered.connect(functools.partial(self.__virusTotal, act))
693 functools.partial(self.__virusTotal, act)) 730
694
695 def __createImageContextMenu(self, menu, hitTest): 731 def __createImageContextMenu(self, menu, hitTest):
696 """ 732 """
697 Private method to populate the context menu for images. 733 Private method to populate the context menu for images.
698 734
699 @param menu reference to the menu to be populated 735 @param menu reference to the menu to be populated
700 @type QMenu 736 @type QMenu
701 @param hitTest reference to the hit test object 737 @param hitTest reference to the hit test object
702 @type WebHitTestResult 738 @type WebHitTestResult
703 """ 739 """
704 if not menu.isEmpty(): 740 if not menu.isEmpty():
705 menu.addSeparator() 741 menu.addSeparator()
706 742
707 act = menu.addAction( 743 act = menu.addAction(
708 UI.PixmapCache.getIcon("openNewTab"), 744 UI.PixmapCache.getIcon("openNewTab"), self.tr("Open Image in New Tab")
709 self.tr("Open Image in New Tab")) 745 )
710 act.setData(hitTest.imageUrl()) 746 act.setData(hitTest.imageUrl())
711 act.triggered.connect( 747 act.triggered.connect(functools.partial(self.__openLinkInNewTab, act))
712 functools.partial(self.__openLinkInNewTab, act))
713 menu.addSeparator() 748 menu.addSeparator()
714 menu.addAction( 749 menu.addAction(
715 UI.PixmapCache.getIcon("download"), 750 UI.PixmapCache.getIcon("download"),
716 self.tr("Save Image"), self.__downloadImage) 751 self.tr("Save Image"),
717 menu.addAction( 752 self.__downloadImage,
718 self.tr("Copy Image to Clipboard"), self.__copyImage) 753 )
754 menu.addAction(self.tr("Copy Image to Clipboard"), self.__copyImage)
719 act = menu.addAction( 755 act = menu.addAction(
720 UI.PixmapCache.getIcon("editCopy"), 756 UI.PixmapCache.getIcon("editCopy"), self.tr("Copy Image URL to Clipboard")
721 self.tr("Copy Image URL to Clipboard")) 757 )
722 act.setData(hitTest.imageUrl()) 758 act.setData(hitTest.imageUrl())
723 act.triggered.connect( 759 act.triggered.connect(functools.partial(self.__copyLink, act))
724 functools.partial(self.__copyLink, act))
725 act = menu.addAction( 760 act = menu.addAction(
726 UI.PixmapCache.getIcon("mailSend"), 761 UI.PixmapCache.getIcon("mailSend"), self.tr("Send Image URL")
727 self.tr("Send Image URL")) 762 )
728 act.setData(hitTest.imageUrl()) 763 act.setData(hitTest.imageUrl())
729 act.triggered.connect( 764 act.triggered.connect(functools.partial(self.__sendLink, act))
730 functools.partial(self.__sendLink, act)) 765
731
732 if hitTest.imageUrl().scheme() in ["http", "https"]: 766 if hitTest.imageUrl().scheme() in ["http", "https"]:
733 menu.addSeparator() 767 menu.addSeparator()
734 engine = WebBrowserWindow.imageSearchEngine() 768 engine = WebBrowserWindow.imageSearchEngine()
735 searchEngineName = engine.searchEngine() 769 searchEngineName = engine.searchEngine()
736 act = menu.addAction( 770 act = menu.addAction(
737 UI.PixmapCache.getIcon("{0}".format( 771 UI.PixmapCache.getIcon("{0}".format(searchEngineName.lower())),
738 searchEngineName.lower())), 772 self.tr("Search image in {0}").format(searchEngineName),
739 self.tr("Search image in {0}").format(searchEngineName)) 773 )
740 act.setData(engine.getSearchQuery(hitTest.imageUrl())) 774 act.setData(engine.getSearchQuery(hitTest.imageUrl()))
741 act.triggered.connect( 775 act.triggered.connect(functools.partial(self.__searchImage, act))
742 functools.partial(self.__searchImage, act)) 776 self.__imageSearchMenu = menu.addMenu(self.tr("Search image with..."))
743 self.__imageSearchMenu = menu.addMenu(
744 self.tr("Search image with..."))
745 for searchEngineName in engine.searchEngineNames(): 777 for searchEngineName in engine.searchEngineNames():
746 act = self.__imageSearchMenu.addAction( 778 act = self.__imageSearchMenu.addAction(
747 UI.PixmapCache.getIcon("{0}".format( 779 UI.PixmapCache.getIcon("{0}".format(searchEngineName.lower())),
748 searchEngineName.lower())), 780 self.tr("Search image in {0}").format(searchEngineName),
749 self.tr("Search image in {0}").format(searchEngineName)) 781 )
750 act.setData(engine.getSearchQuery( 782 act.setData(engine.getSearchQuery(hitTest.imageUrl(), searchEngineName))
751 hitTest.imageUrl(), searchEngineName)) 783 act.triggered.connect(functools.partial(self.__searchImage, act))
752 act.triggered.connect( 784
753 functools.partial(self.__searchImage, act))
754
755 menu.addSeparator() 785 menu.addSeparator()
756 act = menu.addAction( 786 act = menu.addAction(
757 UI.PixmapCache.getIcon("adBlockPlus"), 787 UI.PixmapCache.getIcon("adBlockPlus"), self.tr("Block Image")
758 self.tr("Block Image")) 788 )
759 act.setData(hitTest.imageUrl().toString()) 789 act.setData(hitTest.imageUrl().toString())
760 act.triggered.connect( 790 act.triggered.connect(functools.partial(self.__blockImage, act))
761 functools.partial(self.__blockImage, act))
762 if ( 791 if (
763 Preferences.getWebBrowser("VirusTotalEnabled") and 792 Preferences.getWebBrowser("VirusTotalEnabled")
764 Preferences.getWebBrowser("VirusTotalServiceKey") != "" 793 and Preferences.getWebBrowser("VirusTotalServiceKey") != ""
765 ): 794 ):
766 act = menu.addAction( 795 act = menu.addAction(
767 UI.PixmapCache.getIcon("virustotal"), 796 UI.PixmapCache.getIcon("virustotal"),
768 self.tr("Scan Image with VirusTotal")) 797 self.tr("Scan Image with VirusTotal"),
798 )
769 act.setData(hitTest.imageUrl()) 799 act.setData(hitTest.imageUrl())
770 act.triggered.connect( 800 act.triggered.connect(functools.partial(self.__virusTotal, act))
771 functools.partial(self.__virusTotal, act)) 801
772
773 def __createMediaContextMenu(self, menu, hitTest): 802 def __createMediaContextMenu(self, menu, hitTest):
774 """ 803 """
775 Private method to populate the context menu for media elements. 804 Private method to populate the context menu for media elements.
776 805
777 @param menu reference to the menu to be populated 806 @param menu reference to the menu to be populated
778 @type QMenu 807 @type QMenu
779 @param hitTest reference to the hit test object 808 @param hitTest reference to the hit test object
780 @type WebHitTestResult 809 @type WebHitTestResult
781 """ 810 """
782 if not menu.isEmpty(): 811 if not menu.isEmpty():
783 menu.addSeparator() 812 menu.addSeparator()
784 813
785 if hitTest.mediaPaused(): 814 if hitTest.mediaPaused():
786 menu.addAction( 815 menu.addAction(
787 UI.PixmapCache.getIcon("mediaPlaybackStart"), 816 UI.PixmapCache.getIcon("mediaPlaybackStart"),
788 self.tr("Play"), self.__pauseMedia) 817 self.tr("Play"),
818 self.__pauseMedia,
819 )
789 else: 820 else:
790 menu.addAction( 821 menu.addAction(
791 UI.PixmapCache.getIcon("mediaPlaybackPause"), 822 UI.PixmapCache.getIcon("mediaPlaybackPause"),
792 self.tr("Pause"), self.__pauseMedia) 823 self.tr("Pause"),
824 self.__pauseMedia,
825 )
793 if hitTest.mediaMuted(): 826 if hitTest.mediaMuted():
794 menu.addAction( 827 menu.addAction(
795 UI.PixmapCache.getIcon("audioVolumeHigh"), 828 UI.PixmapCache.getIcon("audioVolumeHigh"),
796 self.tr("Unmute"), self.__muteMedia) 829 self.tr("Unmute"),
830 self.__muteMedia,
831 )
797 else: 832 else:
798 menu.addAction( 833 menu.addAction(
799 UI.PixmapCache.getIcon("audioVolumeMuted"), 834 UI.PixmapCache.getIcon("audioVolumeMuted"),
800 self.tr("Mute"), self.__muteMedia) 835 self.tr("Mute"),
836 self.__muteMedia,
837 )
801 menu.addSeparator() 838 menu.addSeparator()
802 act = menu.addAction( 839 act = menu.addAction(
803 UI.PixmapCache.getIcon("editCopy"), 840 UI.PixmapCache.getIcon("editCopy"), self.tr("Copy Media URL to Clipboard")
804 self.tr("Copy Media URL to Clipboard")) 841 )
805 act.setData(hitTest.mediaUrl()) 842 act.setData(hitTest.mediaUrl())
806 act.triggered.connect( 843 act.triggered.connect(functools.partial(self.__copyLink, act))
807 functools.partial(self.__copyLink, act))
808 act = menu.addAction( 844 act = menu.addAction(
809 UI.PixmapCache.getIcon("mailSend"), 845 UI.PixmapCache.getIcon("mailSend"), self.tr("Send Media URL")
810 self.tr("Send Media URL")) 846 )
811 act.setData(hitTest.mediaUrl()) 847 act.setData(hitTest.mediaUrl())
812 act.triggered.connect( 848 act.triggered.connect(functools.partial(self.__sendLink, act))
813 functools.partial(self.__sendLink, act))
814 menu.addAction( 849 menu.addAction(
815 UI.PixmapCache.getIcon("download"), 850 UI.PixmapCache.getIcon("download"),
816 self.tr("Save Media"), self.__downloadMedia) 851 self.tr("Save Media"),
817 852 self.__downloadMedia,
853 )
854
818 def __createSelectedTextContextMenu(self, menu, hitTest): 855 def __createSelectedTextContextMenu(self, menu, hitTest):
819 """ 856 """
820 Private method to populate the context menu for selected text. 857 Private method to populate the context menu for selected text.
821 858
822 @param menu reference to the menu to be populated 859 @param menu reference to the menu to be populated
823 @type QMenu 860 @type QMenu
824 @param hitTest reference to the hit test object 861 @param hitTest reference to the hit test object
825 @type WebHitTestResult 862 @type WebHitTestResult
826 """ 863 """
827 if not menu.isEmpty(): 864 if not menu.isEmpty():
828 menu.addSeparator() 865 menu.addSeparator()
829 866
830 menu.addAction(self.__mw.copyAct) 867 menu.addAction(self.__mw.copyAct)
831 menu.addSeparator() 868 menu.addSeparator()
832 act = menu.addAction( 869 act = menu.addAction(UI.PixmapCache.getIcon("mailSend"), self.tr("Send Text"))
833 UI.PixmapCache.getIcon("mailSend"),
834 self.tr("Send Text"))
835 act.setData(self.selectedText()) 870 act.setData(self.selectedText())
836 act.triggered.connect( 871 act.triggered.connect(functools.partial(self.__sendLink, act))
837 functools.partial(self.__sendLink, act)) 872
838
839 engineName = self.__mw.openSearchManager().currentEngineName() 873 engineName = self.__mw.openSearchManager().currentEngineName()
840 if engineName: 874 if engineName:
841 menu.addAction(self.tr("Search with '{0}'").format(engineName), 875 menu.addAction(
842 self.__searchDefaultRequested) 876 self.tr("Search with '{0}'").format(engineName),
843 877 self.__searchDefaultRequested,
844 from .OpenSearch.OpenSearchEngineAction import ( 878 )
845 OpenSearchEngineAction 879
846 ) 880 from .OpenSearch.OpenSearchEngineAction import OpenSearchEngineAction
847 881
848 self.__searchMenu = menu.addMenu(self.tr("Search with...")) 882 self.__searchMenu = menu.addMenu(self.tr("Search with..."))
849 engineNames = self.__mw.openSearchManager().allEnginesNames() 883 engineNames = self.__mw.openSearchManager().allEnginesNames()
850 for engineName in engineNames: 884 for engineName in engineNames:
851 engine = self.__mw.openSearchManager().engine(engineName) 885 engine = self.__mw.openSearchManager().engine(engineName)
852 act = OpenSearchEngineAction(engine, self.__searchMenu) 886 act = OpenSearchEngineAction(engine, self.__searchMenu)
853 act.setData(engineName) 887 act.setData(engineName)
854 self.__searchMenu.addAction(act) 888 self.__searchMenu.addAction(act)
855 self.__searchMenu.triggered.connect(self.__searchRequested) 889 self.__searchMenu.triggered.connect(self.__searchRequested)
856 890
857 menu.addSeparator() 891 menu.addSeparator()
858 892
859 from .WebBrowserLanguagesDialog import WebBrowserLanguagesDialog 893 from .WebBrowserLanguagesDialog import WebBrowserLanguagesDialog
894
860 languages = Preferences.toList( 895 languages = Preferences.toList(
861 Preferences.getSettings().value( 896 Preferences.getSettings().value(
862 "WebBrowser/AcceptLanguages", 897 "WebBrowser/AcceptLanguages",
863 WebBrowserLanguagesDialog.defaultAcceptLanguages())) 898 WebBrowserLanguagesDialog.defaultAcceptLanguages(),
899 )
900 )
864 if languages: 901 if languages:
865 language = languages[0] 902 language = languages[0]
866 langCode = language.split("[")[1][:2] 903 langCode = language.split("[")[1][:2]
867 googleTranslatorUrl = QUrl( 904 googleTranslatorUrl = QUrl(
868 "http://translate.google.com/#auto/{0}/{1}".format( 905 "http://translate.google.com/#auto/{0}/{1}".format(
869 langCode, self.selectedText())) 906 langCode, self.selectedText()
907 )
908 )
870 act = menu.addAction( 909 act = menu.addAction(
871 UI.PixmapCache.getIcon("translate"), 910 UI.PixmapCache.getIcon("translate"), self.tr("Google Translate")
872 self.tr("Google Translate")) 911 )
873 act.setData(googleTranslatorUrl) 912 act.setData(googleTranslatorUrl)
874 act.triggered.connect( 913 act.triggered.connect(functools.partial(self.__openLinkInNewTab, act))
875 functools.partial(self.__openLinkInNewTab, act))
876 wiktionaryUrl = QUrl( 914 wiktionaryUrl = QUrl(
877 "http://{0}.wiktionary.org/wiki/Special:Search?search={1}" 915 "http://{0}.wiktionary.org/wiki/Special:Search?search={1}".format(
878 .format(langCode, self.selectedText())) 916 langCode, self.selectedText()
917 )
918 )
879 act = menu.addAction( 919 act = menu.addAction(
880 UI.PixmapCache.getIcon("wikipedia"), 920 UI.PixmapCache.getIcon("wikipedia"), self.tr("Dictionary")
881 self.tr("Dictionary")) 921 )
882 act.setData(wiktionaryUrl) 922 act.setData(wiktionaryUrl)
883 act.triggered.connect( 923 act.triggered.connect(functools.partial(self.__openLinkInNewTab, act))
884 functools.partial(self.__openLinkInNewTab, act))
885 menu.addSeparator() 924 menu.addSeparator()
886 925
887 guessedUrl = QUrl.fromUserInput(self.selectedText().strip()) 926 guessedUrl = QUrl.fromUserInput(self.selectedText().strip())
888 if self.__isUrlValid(guessedUrl): 927 if self.__isUrlValid(guessedUrl):
889 act = menu.addAction(self.tr("Go to web address")) 928 act = menu.addAction(self.tr("Go to web address"))
890 act.setData(guessedUrl) 929 act.setData(guessedUrl)
891 act.triggered.connect( 930 act.triggered.connect(functools.partial(self.__openLinkInNewTab, act))
892 functools.partial(self.__openLinkInNewTab, act)) 931
893
894 def __createPageContextMenu(self, menu): 932 def __createPageContextMenu(self, menu):
895 """ 933 """
896 Private method to populate the basic context menu. 934 Private method to populate the basic context menu.
897 935
898 @param menu reference to the menu to be populated 936 @param menu reference to the menu to be populated
899 @type QMenu 937 @type QMenu
900 """ 938 """
901 menu.addAction(self.__mw.newTabAct) 939 menu.addAction(self.__mw.newTabAct)
902 menu.addAction(self.__mw.newAct) 940 menu.addAction(self.__mw.newAct)
903 menu.addSeparator() 941 menu.addSeparator()
904 if self.__mw.saveAsAct is not None: 942 if self.__mw.saveAsAct is not None:
905 menu.addAction(self.__mw.saveAsAct) 943 menu.addAction(self.__mw.saveAsAct)
906 menu.addAction(self.__mw.saveVisiblePageScreenAct) 944 menu.addAction(self.__mw.saveVisiblePageScreenAct)
907 menu.addSeparator() 945 menu.addSeparator()
908 946
909 if self.url().toString() == "eric:speeddial": 947 if self.url().toString() == "eric:speeddial":
910 # special menu for the spedd dial page 948 # special menu for the spedd dial page
911 menu.addAction(self.__mw.backAct) 949 menu.addAction(self.__mw.backAct)
912 menu.addAction(self.__mw.forwardAct) 950 menu.addAction(self.__mw.forwardAct)
913 menu.addSeparator() 951 menu.addSeparator()
914 menu.addAction( 952 menu.addAction(
915 UI.PixmapCache.getIcon("plus"), 953 UI.PixmapCache.getIcon("plus"),
916 self.tr("Add New Page"), self.__addSpeedDial) 954 self.tr("Add New Page"),
955 self.__addSpeedDial,
956 )
917 menu.addAction( 957 menu.addAction(
918 UI.PixmapCache.getIcon("preferences-general"), 958 UI.PixmapCache.getIcon("preferences-general"),
919 self.tr("Configure Speed Dial"), self.__configureSpeedDial) 959 self.tr("Configure Speed Dial"),
960 self.__configureSpeedDial,
961 )
920 menu.addSeparator() 962 menu.addSeparator()
921 menu.addAction( 963 menu.addAction(
922 UI.PixmapCache.getIcon("reload"), 964 UI.PixmapCache.getIcon("reload"),
923 self.tr("Reload All Dials"), self.__reloadAllSpeedDials) 965 self.tr("Reload All Dials"),
966 self.__reloadAllSpeedDials,
967 )
924 menu.addSeparator() 968 menu.addSeparator()
925 menu.addAction( 969 menu.addAction(self.tr("Reset to Default Dials"), self.__resetSpeedDials)
926 self.tr("Reset to Default Dials"), self.__resetSpeedDials)
927 return 970 return
928 971
929 menu.addAction( 972 menu.addAction(
930 UI.PixmapCache.getIcon("bookmark22"), 973 UI.PixmapCache.getIcon("bookmark22"),
931 self.tr("Bookmark this Page"), self.addBookmark) 974 self.tr("Bookmark this Page"),
975 self.addBookmark,
976 )
932 act = menu.addAction( 977 act = menu.addAction(
933 UI.PixmapCache.getIcon("editCopy"), 978 UI.PixmapCache.getIcon("editCopy"), self.tr("Copy Page URL to Clipboard")
934 self.tr("Copy Page URL to Clipboard")) 979 )
935 act.setData(self.url()) 980 act.setData(self.url())
936 act.triggered.connect( 981 act.triggered.connect(functools.partial(self.__copyLink, act))
937 functools.partial(self.__copyLink, act))
938 act = menu.addAction( 982 act = menu.addAction(
939 UI.PixmapCache.getIcon("mailSend"), 983 UI.PixmapCache.getIcon("mailSend"), self.tr("Send Page URL")
940 self.tr("Send Page URL")) 984 )
941 act.setData(self.url()) 985 act.setData(self.url())
942 act.triggered.connect( 986 act.triggered.connect(functools.partial(self.__sendLink, act))
943 functools.partial(self.__sendLink, act))
944 menu.addSeparator() 987 menu.addSeparator()
945 988
946 from .UserAgent.UserAgentMenu import UserAgentMenu 989 from .UserAgent.UserAgentMenu import UserAgentMenu
947 self.__userAgentMenu = UserAgentMenu(self.tr("User Agent"), 990
948 url=self.url()) 991 self.__userAgentMenu = UserAgentMenu(self.tr("User Agent"), url=self.url())
949 menu.addMenu(self.__userAgentMenu) 992 menu.addMenu(self.__userAgentMenu)
950 menu.addSeparator() 993 menu.addSeparator()
951 menu.addAction(self.__mw.backAct) 994 menu.addAction(self.__mw.backAct)
952 menu.addAction(self.__mw.forwardAct) 995 menu.addAction(self.__mw.forwardAct)
953 menu.addAction(self.__mw.homeAct) 996 menu.addAction(self.__mw.homeAct)
965 menu.addAction(self.__mw.pageSourceAct) 1008 menu.addAction(self.__mw.pageSourceAct)
966 menu.addSeparator() 1009 menu.addSeparator()
967 menu.addAction(self.__mw.siteInfoAct) 1010 menu.addAction(self.__mw.siteInfoAct)
968 if self.url().scheme() in ["http", "https"]: 1011 if self.url().scheme() in ["http", "https"]:
969 menu.addSeparator() 1012 menu.addSeparator()
970 1013
971 w3url = QUrl.fromEncoded( 1014 w3url = QUrl.fromEncoded(
972 b"http://validator.w3.org/check?uri=" + 1015 b"http://validator.w3.org/check?uri="
973 QUrl.toPercentEncoding(bytes(self.url().toEncoded()).decode())) 1016 + QUrl.toPercentEncoding(bytes(self.url().toEncoded()).decode())
974 act = menu.addAction( 1017 )
975 UI.PixmapCache.getIcon("w3"), 1018 act = menu.addAction(UI.PixmapCache.getIcon("w3"), self.tr("Validate Page"))
976 self.tr("Validate Page"))
977 act.setData(w3url) 1019 act.setData(w3url)
978 act.triggered.connect( 1020 act.triggered.connect(functools.partial(self.__openLinkInNewTab, act))
979 functools.partial(self.__openLinkInNewTab, act)) 1021
980
981 from .WebBrowserLanguagesDialog import WebBrowserLanguagesDialog 1022 from .WebBrowserLanguagesDialog import WebBrowserLanguagesDialog
1023
982 languages = Preferences.toList( 1024 languages = Preferences.toList(
983 Preferences.getSettings().value( 1025 Preferences.getSettings().value(
984 "WebBrowser/AcceptLanguages", 1026 "WebBrowser/AcceptLanguages",
985 WebBrowserLanguagesDialog.defaultAcceptLanguages())) 1027 WebBrowserLanguagesDialog.defaultAcceptLanguages(),
1028 )
1029 )
986 if languages: 1030 if languages:
987 language = languages[0] 1031 language = languages[0]
988 langCode = language.split("[")[1][:2] 1032 langCode = language.split("[")[1][:2]
989 googleTranslatorUrl = QUrl.fromEncoded( 1033 googleTranslatorUrl = QUrl.fromEncoded(
990 b"http://translate.google.com/translate?sl=auto&tl=" + 1034 b"http://translate.google.com/translate?sl=auto&tl="
991 langCode.encode() + 1035 + langCode.encode()
992 b"&u=" + 1036 + b"&u="
993 QUrl.toPercentEncoding( 1037 + QUrl.toPercentEncoding(bytes(self.url().toEncoded()).decode())
994 bytes(self.url().toEncoded()).decode())) 1038 )
995 act = menu.addAction( 1039 act = menu.addAction(
996 UI.PixmapCache.getIcon("translate"), 1040 UI.PixmapCache.getIcon("translate"), self.tr("Google Translate")
997 self.tr("Google Translate")) 1041 )
998 act.setData(googleTranslatorUrl) 1042 act.setData(googleTranslatorUrl)
999 act.triggered.connect( 1043 act.triggered.connect(functools.partial(self.__openLinkInNewTab, act))
1000 functools.partial(self.__openLinkInNewTab, act)) 1044
1001
1002 def __checkForForm(self, act, pos): 1045 def __checkForForm(self, act, pos):
1003 """ 1046 """
1004 Private method to check the given position for an open search form. 1047 Private method to check the given position for an open search form.
1005 1048
1006 @param act reference to the action to be populated upon success 1049 @param act reference to the action to be populated upon success
1007 @type QAction 1050 @type QAction
1008 @param pos position to be tested 1051 @param pos position to be tested
1009 @type QPoint 1052 @type QPoint
1010 """ 1053 """
1011 self.__clickedPos = self.mapToViewport(pos) 1054 self.__clickedPos = self.mapToViewport(pos)
1012 1055
1013 from .Tools import Scripts 1056 from .Tools import Scripts
1057
1014 script = Scripts.getFormData(self.__clickedPos) 1058 script = Scripts.getFormData(self.__clickedPos)
1015 self.page().runJavaScript( 1059 self.page().runJavaScript(
1016 script, 1060 script,
1017 WebBrowserPage.SafeJsWorld, 1061 WebBrowserPage.SafeJsWorld,
1018 lambda res: self.__checkForFormCallback(res, act)) 1062 lambda res: self.__checkForFormCallback(res, act),
1019 1063 )
1064
1020 def __checkForFormCallback(self, res, act): 1065 def __checkForFormCallback(self, res, act):
1021 """ 1066 """
1022 Private method handling the __checkForForm result. 1067 Private method handling the __checkForForm result.
1023 1068
1024 @param res result dictionary generated by JavaScript 1069 @param res result dictionary generated by JavaScript
1025 @type dict 1070 @type dict
1026 @param act reference to the action to be populated upon success 1071 @param act reference to the action to be populated upon success
1027 @type QAction 1072 @type QAction
1028 """ 1073 """
1029 if act is None or not bool(res): 1074 if act is None or not bool(res):
1030 return 1075 return
1031 1076
1032 url = QUrl(res["action"]) 1077 url = QUrl(res["action"])
1033 method = res["method"] 1078 method = res["method"]
1034 1079
1035 if not url.isEmpty() and method in ["get", "post"]: 1080 if not url.isEmpty() and method in ["get", "post"]:
1036 act.setVisible(True) 1081 act.setVisible(True)
1037 act.setText(self.tr("Add to web search toolbar")) 1082 act.setText(self.tr("Add to web search toolbar"))
1038 act.triggered.connect(self.__addSearchEngine) 1083 act.triggered.connect(self.__addSearchEngine)
1039 1084
1040 def __isUrlValid(self, url): 1085 def __isUrlValid(self, url):
1041 """ 1086 """
1042 Private method to check a URL for validity. 1087 Private method to check a URL for validity.
1043 1088
1044 @param url URL to be checked (QUrl) 1089 @param url URL to be checked (QUrl)
1045 @return flag indicating a valid URL (boolean) 1090 @return flag indicating a valid URL (boolean)
1046 """ 1091 """
1047 return ( 1092 return (
1048 url.isValid() and 1093 url.isValid()
1049 bool(url.host()) and 1094 and bool(url.host())
1050 bool(url.scheme()) and 1095 and bool(url.scheme())
1051 "." in url.host() 1096 and "." in url.host()
1052 ) 1097 )
1053 1098
1054 def __replaceMisspelledWord(self, act): 1099 def __replaceMisspelledWord(self, act):
1055 """ 1100 """
1056 Private slot to replace a misspelled word under the context menu. 1101 Private slot to replace a misspelled word under the context menu.
1057 1102
1058 @param act reference to the action that triggered 1103 @param act reference to the action that triggered
1059 @type QAction 1104 @type QAction
1060 """ 1105 """
1061 suggestion = act.text() 1106 suggestion = act.text()
1062 self.page().replaceMisspelledWord(suggestion) 1107 self.page().replaceMisspelledWord(suggestion)
1063 1108
1064 def __openLinkInNewTab(self, act): 1109 def __openLinkInNewTab(self, act):
1065 """ 1110 """
1066 Private method called by the context menu to open a link in a new 1111 Private method called by the context menu to open a link in a new
1067 tab. 1112 tab.
1068 1113
1069 @param act reference to the action that triggered 1114 @param act reference to the action that triggered
1070 @type QAction 1115 @type QAction
1071 """ 1116 """
1072 url = act.data() 1117 url = act.data()
1073 if url.isEmpty(): 1118 if url.isEmpty():
1074 return 1119 return
1075 1120
1076 self.setSource(url, newTab=True) 1121 self.setSource(url, newTab=True)
1077 1122
1078 def __openLinkInNewWindow(self, act): 1123 def __openLinkInNewWindow(self, act):
1079 """ 1124 """
1080 Private slot called by the context menu to open a link in a new 1125 Private slot called by the context menu to open a link in a new
1081 window. 1126 window.
1082 1127
1083 @param act reference to the action that triggered 1128 @param act reference to the action that triggered
1084 @type QAction 1129 @type QAction
1085 """ 1130 """
1086 url = act.data() 1131 url = act.data()
1087 if url.isEmpty(): 1132 if url.isEmpty():
1088 return 1133 return
1089 1134
1090 self.__mw.newWindow(url) 1135 self.__mw.newWindow(url)
1091 1136
1092 def __openLinkInNewPrivateWindow(self, act): 1137 def __openLinkInNewPrivateWindow(self, act):
1093 """ 1138 """
1094 Private slot called by the context menu to open a link in a new 1139 Private slot called by the context menu to open a link in a new
1095 private window. 1140 private window.
1096 1141
1097 @param act reference to the action that triggered 1142 @param act reference to the action that triggered
1098 @type QAction 1143 @type QAction
1099 """ 1144 """
1100 url = act.data() 1145 url = act.data()
1101 if url.isEmpty(): 1146 if url.isEmpty():
1102 return 1147 return
1103 1148
1104 self.__mw.newPrivateWindow(url) 1149 self.__mw.newPrivateWindow(url)
1105 1150
1106 def __bookmarkLink(self, act): 1151 def __bookmarkLink(self, act):
1107 """ 1152 """
1108 Private slot to bookmark a link via the context menu. 1153 Private slot to bookmark a link via the context menu.
1109 1154
1110 @param act reference to the action that triggered 1155 @param act reference to the action that triggered
1111 @type QAction 1156 @type QAction
1112 """ 1157 """
1113 url = act.data() 1158 url = act.data()
1114 if url.isEmpty(): 1159 if url.isEmpty():
1115 return 1160 return
1116 1161
1117 from .Bookmarks.AddBookmarkDialog import AddBookmarkDialog 1162 from .Bookmarks.AddBookmarkDialog import AddBookmarkDialog
1163
1118 dlg = AddBookmarkDialog() 1164 dlg = AddBookmarkDialog()
1119 dlg.setUrl(bytes(url.toEncoded()).decode()) 1165 dlg.setUrl(bytes(url.toEncoded()).decode())
1120 dlg.exec() 1166 dlg.exec()
1121 1167
1122 def __sendLink(self, act): 1168 def __sendLink(self, act):
1123 """ 1169 """
1124 Private slot to send a link via email. 1170 Private slot to send a link via email.
1125 1171
1126 @param act reference to the action that triggered 1172 @param act reference to the action that triggered
1127 @type QAction 1173 @type QAction
1128 """ 1174 """
1129 data = act.data() 1175 data = act.data()
1130 if isinstance(data, QUrl) and data.isEmpty(): 1176 if isinstance(data, QUrl) and data.isEmpty():
1131 return 1177 return
1132 1178
1133 if isinstance(data, QUrl): 1179 if isinstance(data, QUrl):
1134 data = data.toString() 1180 data = data.toString()
1135 QDesktopServices.openUrl(QUrl("mailto:?body=" + data)) 1181 QDesktopServices.openUrl(QUrl("mailto:?body=" + data))
1136 1182
1137 def __copyLink(self, act): 1183 def __copyLink(self, act):
1138 """ 1184 """
1139 Private slot to copy a link to the clipboard. 1185 Private slot to copy a link to the clipboard.
1140 1186
1141 @param act reference to the action that triggered 1187 @param act reference to the action that triggered
1142 @type QAction 1188 @type QAction
1143 """ 1189 """
1144 data = act.data() 1190 data = act.data()
1145 if isinstance(data, QUrl) and data.isEmpty(): 1191 if isinstance(data, QUrl) and data.isEmpty():
1146 return 1192 return
1147 1193
1148 if isinstance(data, QUrl): 1194 if isinstance(data, QUrl):
1149 data = data.toString() 1195 data = data.toString()
1150 1196
1151 # copy the URL to both clipboard areas 1197 # copy the URL to both clipboard areas
1152 QApplication.clipboard().setText(data, QClipboard.Mode.Clipboard) 1198 QApplication.clipboard().setText(data, QClipboard.Mode.Clipboard)
1153 QApplication.clipboard().setText(data, QClipboard.Mode.Selection) 1199 QApplication.clipboard().setText(data, QClipboard.Mode.Selection)
1154 1200
1155 def __downloadLink(self): 1201 def __downloadLink(self):
1156 """ 1202 """
1157 Private slot to download a link and save it to disk. 1203 Private slot to download a link and save it to disk.
1158 """ 1204 """
1159 self.triggerPageAction(QWebEnginePage.WebAction.DownloadLinkToDisk) 1205 self.triggerPageAction(QWebEnginePage.WebAction.DownloadLinkToDisk)
1160 1206
1161 def __downloadImage(self): 1207 def __downloadImage(self):
1162 """ 1208 """
1163 Private slot to download an image and save it to disk. 1209 Private slot to download an image and save it to disk.
1164 """ 1210 """
1165 self.triggerPageAction(QWebEnginePage.WebAction.DownloadImageToDisk) 1211 self.triggerPageAction(QWebEnginePage.WebAction.DownloadImageToDisk)
1166 1212
1167 def __copyImage(self): 1213 def __copyImage(self):
1168 """ 1214 """
1169 Private slot to copy an image to the clipboard. 1215 Private slot to copy an image to the clipboard.
1170 """ 1216 """
1171 self.triggerPageAction(QWebEnginePage.WebAction.CopyImageToClipboard) 1217 self.triggerPageAction(QWebEnginePage.WebAction.CopyImageToClipboard)
1172 1218
1173 def __blockImage(self, act): 1219 def __blockImage(self, act):
1174 """ 1220 """
1175 Private slot to add a block rule for an image URL. 1221 Private slot to add a block rule for an image URL.
1176 1222
1177 @param act reference to the action that triggered 1223 @param act reference to the action that triggered
1178 @type QAction 1224 @type QAction
1179 """ 1225 """
1180 url = act.data() 1226 url = act.data()
1181 dlg = WebBrowserWindow.adBlockManager().showDialog() 1227 dlg = WebBrowserWindow.adBlockManager().showDialog()
1182 dlg.addCustomRule(url) 1228 dlg.addCustomRule(url)
1183 1229
1184 def __searchImage(self, act): 1230 def __searchImage(self, act):
1185 """ 1231 """
1186 Private slot to search for an image URL. 1232 Private slot to search for an image URL.
1187 1233
1188 @param act reference to the action that triggered 1234 @param act reference to the action that triggered
1189 @type QAction 1235 @type QAction
1190 """ 1236 """
1191 url = act.data() 1237 url = act.data()
1192 self.setSource(url, newTab=True) 1238 self.setSource(url, newTab=True)
1193 1239
1194 def __downloadMedia(self): 1240 def __downloadMedia(self):
1195 """ 1241 """
1196 Private slot to download a media and save it to disk. 1242 Private slot to download a media and save it to disk.
1197 """ 1243 """
1198 self.triggerPageAction(QWebEnginePage.WebAction.DownloadMediaToDisk) 1244 self.triggerPageAction(QWebEnginePage.WebAction.DownloadMediaToDisk)
1199 1245
1200 def __pauseMedia(self): 1246 def __pauseMedia(self):
1201 """ 1247 """
1202 Private slot to pause or play the selected media. 1248 Private slot to pause or play the selected media.
1203 """ 1249 """
1204 self.triggerPageAction(QWebEnginePage.WebAction.ToggleMediaPlayPause) 1250 self.triggerPageAction(QWebEnginePage.WebAction.ToggleMediaPlayPause)
1205 1251
1206 def __muteMedia(self): 1252 def __muteMedia(self):
1207 """ 1253 """
1208 Private slot to (un)mute the selected media. 1254 Private slot to (un)mute the selected media.
1209 """ 1255 """
1210 self.triggerPageAction(QWebEnginePage.WebAction.ToggleMediaMute) 1256 self.triggerPageAction(QWebEnginePage.WebAction.ToggleMediaMute)
1211 1257
1212 def __virusTotal(self, act): 1258 def __virusTotal(self, act):
1213 """ 1259 """
1214 Private slot to scan the selected URL with VirusTotal. 1260 Private slot to scan the selected URL with VirusTotal.
1215 1261
1216 @param act reference to the action that triggered 1262 @param act reference to the action that triggered
1217 @type QAction 1263 @type QAction
1218 """ 1264 """
1219 url = act.data() 1265 url = act.data()
1220 self.__mw.requestVirusTotalScan(url) 1266 self.__mw.requestVirusTotalScan(url)
1221 1267
1222 def __searchDefaultRequested(self): 1268 def __searchDefaultRequested(self):
1223 """ 1269 """
1224 Private slot to search for some text with the current search engine. 1270 Private slot to search for some text with the current search engine.
1225 """ 1271 """
1226 searchText = self.selectedText() 1272 searchText = self.selectedText()
1227 1273
1228 if not searchText: 1274 if not searchText:
1229 return 1275 return
1230 1276
1231 engine = self.__mw.openSearchManager().currentEngine() 1277 engine = self.__mw.openSearchManager().currentEngine()
1232 if engine: 1278 if engine:
1233 self.search.emit(engine.searchUrl(searchText)) 1279 self.search.emit(engine.searchUrl(searchText))
1234 1280
1235 def __searchRequested(self, act): 1281 def __searchRequested(self, act):
1236 """ 1282 """
1237 Private slot to search for some text with a selected search engine. 1283 Private slot to search for some text with a selected search engine.
1238 1284
1239 @param act reference to the action that triggered this slot (QAction) 1285 @param act reference to the action that triggered this slot (QAction)
1240 """ 1286 """
1241 searchText = self.selectedText() 1287 searchText = self.selectedText()
1242 1288
1243 if not searchText: 1289 if not searchText:
1244 return 1290 return
1245 1291
1246 engineName = act.data() 1292 engineName = act.data()
1247 engine = ( 1293 engine = (
1248 self.__mw.openSearchManager().engine(engineName) 1294 self.__mw.openSearchManager().engine(engineName)
1249 if engineName else 1295 if engineName
1250 self.__mw.openSearchManager().currentEngine() 1296 else self.__mw.openSearchManager().currentEngine()
1251 ) 1297 )
1252 if engine: 1298 if engine:
1253 self.search.emit(engine.searchUrl(searchText)) 1299 self.search.emit(engine.searchUrl(searchText))
1254 1300
1255 def __addSearchEngine(self): 1301 def __addSearchEngine(self):
1256 """ 1302 """
1257 Private slot to add a new search engine. 1303 Private slot to add a new search engine.
1258 """ 1304 """
1259 from .Tools import Scripts 1305 from .Tools import Scripts
1306
1260 script = Scripts.getFormData(self.__clickedPos) 1307 script = Scripts.getFormData(self.__clickedPos)
1261 self.page().runJavaScript( 1308 self.page().runJavaScript(
1262 script, 1309 script,
1263 WebBrowserPage.SafeJsWorld, 1310 WebBrowserPage.SafeJsWorld,
1264 lambda res: self.__mw.openSearchManager().addEngineFromForm( 1311 lambda res: self.__mw.openSearchManager().addEngineFromForm(res, self),
1265 res, self)) 1312 )
1266 1313
1267 def __webInspector(self): 1314 def __webInspector(self):
1268 """ 1315 """
1269 Private slot to show the web inspector window. 1316 Private slot to show the web inspector window.
1270 """ 1317 """
1271 from .WebInspector import WebInspector 1318 from .WebInspector import WebInspector
1319
1272 if WebInspector.isEnabled(): 1320 if WebInspector.isEnabled():
1273 if self.__inspector is None: 1321 if self.__inspector is None:
1274 self.__inspector = WebInspector() 1322 self.__inspector = WebInspector()
1275 self.__inspector.setView(self, True) 1323 self.__inspector.setView(self, True)
1276 self.__inspector.inspectorClosed.connect( 1324 self.__inspector.inspectorClosed.connect(self.closeWebInspector)
1277 self.closeWebInspector)
1278 self.__inspector.show() 1325 self.__inspector.show()
1279 else: 1326 else:
1280 self.closeWebInspector() 1327 self.closeWebInspector()
1281 1328
1282 def closeWebInspector(self): 1329 def closeWebInspector(self):
1283 """ 1330 """
1284 Public slot to close the web inspector. 1331 Public slot to close the web inspector.
1285 """ 1332 """
1286 if self.__inspector is not None: 1333 if self.__inspector is not None:
1287 if self.__inspector.isVisible(): 1334 if self.__inspector.isVisible():
1288 self.__inspector.hide() 1335 self.__inspector.hide()
1289 WebInspector.unregisterView(self.__inspector) 1336 WebInspector.unregisterView(self.__inspector)
1290 self.__inspector.deleteLater() 1337 self.__inspector.deleteLater()
1291 self.__inspector = None 1338 self.__inspector = None
1292 1339
1293 def addBookmark(self): 1340 def addBookmark(self):
1294 """ 1341 """
1295 Public slot to bookmark the current page. 1342 Public slot to bookmark the current page.
1296 """ 1343 """
1297 from .Tools import Scripts 1344 from .Tools import Scripts
1345
1298 script = Scripts.getAllMetaAttributes() 1346 script = Scripts.getAllMetaAttributes()
1299 self.page().runJavaScript( 1347 self.page().runJavaScript(
1300 script, WebBrowserPage.SafeJsWorld, self.__addBookmarkCallback) 1348 script, WebBrowserPage.SafeJsWorld, self.__addBookmarkCallback
1301 1349 )
1350
1302 def __addBookmarkCallback(self, res): 1351 def __addBookmarkCallback(self, res):
1303 """ 1352 """
1304 Private callback method of __addBookmark(). 1353 Private callback method of __addBookmark().
1305 1354
1306 @param res reference to the result list containing all 1355 @param res reference to the result list containing all
1307 meta attributes 1356 meta attributes
1308 @type list 1357 @type list
1309 """ 1358 """
1310 description = "" 1359 description = ""
1311 for meta in res: 1360 for meta in res:
1312 if meta["name"] == "description": 1361 if meta["name"] == "description":
1313 description = meta["content"] 1362 description = meta["content"]
1314 1363
1315 from .Bookmarks.AddBookmarkDialog import AddBookmarkDialog 1364 from .Bookmarks.AddBookmarkDialog import AddBookmarkDialog
1365
1316 dlg = AddBookmarkDialog() 1366 dlg = AddBookmarkDialog()
1317 dlg.setUrl(bytes(self.url().toEncoded()).decode()) 1367 dlg.setUrl(bytes(self.url().toEncoded()).decode())
1318 dlg.setTitle(self.title()) 1368 dlg.setTitle(self.title())
1319 dlg.setDescription(description) 1369 dlg.setDescription(description)
1320 dlg.exec() 1370 dlg.exec()
1321 1371
1322 def dragEnterEvent(self, evt): 1372 def dragEnterEvent(self, evt):
1323 """ 1373 """
1324 Protected method called by a drag enter event. 1374 Protected method called by a drag enter event.
1325 1375
1326 @param evt reference to the drag enter event (QDragEnterEvent) 1376 @param evt reference to the drag enter event (QDragEnterEvent)
1327 """ 1377 """
1328 evt.acceptProposedAction() 1378 evt.acceptProposedAction()
1329 1379
1330 def dragMoveEvent(self, evt): 1380 def dragMoveEvent(self, evt):
1331 """ 1381 """
1332 Protected method called by a drag move event. 1382 Protected method called by a drag move event.
1333 1383
1334 @param evt reference to the drag move event (QDragMoveEvent) 1384 @param evt reference to the drag move event (QDragMoveEvent)
1335 """ 1385 """
1336 evt.ignore() 1386 evt.ignore()
1337 if evt.source() != self: 1387 if evt.source() != self:
1338 if len(evt.mimeData().urls()) > 0: 1388 if len(evt.mimeData().urls()) > 0:
1339 evt.acceptProposedAction() 1389 evt.acceptProposedAction()
1340 else: 1390 else:
1341 url = QUrl(evt.mimeData().text()) 1391 url = QUrl(evt.mimeData().text())
1342 if url.isValid(): 1392 if url.isValid():
1343 evt.acceptProposedAction() 1393 evt.acceptProposedAction()
1344 1394
1345 if not evt.isAccepted(): 1395 if not evt.isAccepted():
1346 super().dragMoveEvent(evt) 1396 super().dragMoveEvent(evt)
1347 1397
1348 def dropEvent(self, evt): 1398 def dropEvent(self, evt):
1349 """ 1399 """
1350 Protected method called by a drop event. 1400 Protected method called by a drop event.
1351 1401
1352 @param evt reference to the drop event (QDropEvent) 1402 @param evt reference to the drop event (QDropEvent)
1353 """ 1403 """
1354 super().dropEvent(evt) 1404 super().dropEvent(evt)
1355 if ( 1405 if (
1356 not evt.isAccepted() and 1406 not evt.isAccepted()
1357 evt.source() != self and 1407 and evt.source() != self
1358 evt.possibleActions() & Qt.DropAction.CopyAction 1408 and evt.possibleActions() & Qt.DropAction.CopyAction
1359 ): 1409 ):
1360 url = QUrl() 1410 url = QUrl()
1361 if len(evt.mimeData().urls()) > 0: 1411 if len(evt.mimeData().urls()) > 0:
1362 url = evt.mimeData().urls()[0] 1412 url = evt.mimeData().urls()[0]
1363 if not url.isValid(): 1413 if not url.isValid():
1364 url = QUrl(evt.mimeData().text()) 1414 url = QUrl(evt.mimeData().text())
1365 if url.isValid(): 1415 if url.isValid():
1366 self.setSource(url) 1416 self.setSource(url)
1367 evt.acceptProposedAction() 1417 evt.acceptProposedAction()
1368 1418
1369 def _mousePressEvent(self, evt): 1419 def _mousePressEvent(self, evt):
1370 """ 1420 """
1371 Protected method called by a mouse press event. 1421 Protected method called by a mouse press event.
1372 1422
1373 @param evt reference to the mouse event (QMouseEvent) 1423 @param evt reference to the mouse event (QMouseEvent)
1374 """ 1424 """
1375 if WebBrowserWindow.autoScroller().mousePress(self, evt): 1425 if WebBrowserWindow.autoScroller().mousePress(self, evt):
1376 evt.accept() 1426 evt.accept()
1377 return 1427 return
1378 1428
1379 def _mouseReleaseEvent(self, evt): 1429 def _mouseReleaseEvent(self, evt):
1380 """ 1430 """
1381 Protected method called by a mouse release event. 1431 Protected method called by a mouse release event.
1382 1432
1383 @param evt reference to the mouse event (QMouseEvent) 1433 @param evt reference to the mouse event (QMouseEvent)
1384 """ 1434 """
1385 if WebBrowserWindow.autoScroller().mouseRelease(evt): 1435 if WebBrowserWindow.autoScroller().mouseRelease(evt):
1386 evt.accept() 1436 evt.accept()
1387 return 1437 return
1388 1438
1389 accepted = evt.isAccepted() 1439 accepted = evt.isAccepted()
1390 self.__page.event(evt) 1440 self.__page.event(evt)
1391 if ( 1441 if not evt.isAccepted() and evt.button() == Qt.MouseButton.MiddleButton:
1392 not evt.isAccepted() and 1442 url = QUrl(QApplication.clipboard().text(QClipboard.Mode.Selection))
1393 evt.button() == Qt.MouseButton.MiddleButton 1443 if not url.isEmpty() and url.isValid() and url.scheme() != "":
1394 ):
1395 url = QUrl(QApplication.clipboard().text(
1396 QClipboard.Mode.Selection))
1397 if (
1398 not url.isEmpty() and
1399 url.isValid() and
1400 url.scheme() != ""
1401 ):
1402 self.setSource(url) 1444 self.setSource(url)
1403 evt.setAccepted(accepted) 1445 evt.setAccepted(accepted)
1404 1446
1405 def _mouseMoveEvent(self, evt): 1447 def _mouseMoveEvent(self, evt):
1406 """ 1448 """
1407 Protected method to handle mouse move events. 1449 Protected method to handle mouse move events.
1408 1450
1409 @param evt reference to the mouse event (QMouseEvent) 1451 @param evt reference to the mouse event (QMouseEvent)
1410 """ 1452 """
1411 if self.__mw and self.__mw.isFullScreen(): 1453 if self.__mw and self.__mw.isFullScreen():
1412 if self.__mw.isFullScreenNavigationVisible(): 1454 if self.__mw.isFullScreenNavigationVisible():
1413 self.__mw.hideFullScreenNavigation() 1455 self.__mw.hideFullScreenNavigation()
1414 elif evt.y() < 10: 1456 elif evt.y() < 10:
1415 # mouse is within 10px to the top 1457 # mouse is within 10px to the top
1416 self.__mw.showFullScreenNavigation() 1458 self.__mw.showFullScreenNavigation()
1417 1459
1418 if WebBrowserWindow.autoScroller().mouseMove(evt): 1460 if WebBrowserWindow.autoScroller().mouseMove(evt):
1419 evt.accept() 1461 evt.accept()
1420 1462
1421 def _wheelEvent(self, evt): 1463 def _wheelEvent(self, evt):
1422 """ 1464 """
1423 Protected method to handle wheel events. 1465 Protected method to handle wheel events.
1424 1466
1425 @param evt reference to the wheel event (QWheelEvent) 1467 @param evt reference to the wheel event (QWheelEvent)
1426 """ 1468 """
1427 if WebBrowserWindow.autoScroller().wheel(): 1469 if WebBrowserWindow.autoScroller().wheel():
1428 evt.accept() 1470 evt.accept()
1429 return 1471 return
1430 1472
1431 delta = evt.angleDelta().y() 1473 delta = evt.angleDelta().y()
1432 if evt.modifiers() & Qt.KeyboardModifier.ControlModifier: 1474 if evt.modifiers() & Qt.KeyboardModifier.ControlModifier:
1433 if delta < 0: 1475 if delta < 0:
1434 self.zoomOut() 1476 self.zoomOut()
1435 elif delta > 0: 1477 elif delta > 0:
1436 self.zoomIn() 1478 self.zoomIn()
1437 evt.accept() 1479 evt.accept()
1438 1480
1439 elif evt.modifiers() & Qt.KeyboardModifier.ShiftModifier: 1481 elif evt.modifiers() & Qt.KeyboardModifier.ShiftModifier:
1440 if delta < 0: 1482 if delta < 0:
1441 self.backward() 1483 self.backward()
1442 elif delta > 0: 1484 elif delta > 0:
1443 self.forward() 1485 self.forward()
1444 evt.accept() 1486 evt.accept()
1445 1487
1446 def _keyPressEvent(self, evt): 1488 def _keyPressEvent(self, evt):
1447 """ 1489 """
1448 Protected method called by a key press. 1490 Protected method called by a key press.
1449 1491
1450 @param evt reference to the key event (QKeyEvent) 1492 @param evt reference to the key event (QKeyEvent)
1451 """ 1493 """
1452 if self.__mw.personalInformationManager().viewKeyPressEvent(self, evt): 1494 if self.__mw.personalInformationManager().viewKeyPressEvent(self, evt):
1453 evt.accept() 1495 evt.accept()
1454 return 1496 return
1455 1497
1456 if evt.key() == Qt.Key.Key_ZoomIn: 1498 if evt.key() == Qt.Key.Key_ZoomIn:
1457 self.zoomIn() 1499 self.zoomIn()
1458 evt.accept() 1500 evt.accept()
1459 elif evt.key() == Qt.Key.Key_ZoomOut: 1501 elif evt.key() == Qt.Key.Key_ZoomOut:
1460 self.zoomOut() 1502 self.zoomOut()
1480 pos = self.mapFromGlobal(pos) 1522 pos = self.mapFromGlobal(pos)
1481 hitTest = self.page().hitTestContent(pos) 1523 hitTest = self.page().hitTestContent(pos)
1482 if not hitTest.isContentEditable(): 1524 if not hitTest.isContentEditable():
1483 self.pageAction(QWebEnginePage.WebAction.Back).trigger() 1525 self.pageAction(QWebEnginePage.WebAction.Back).trigger()
1484 evt.accept() 1526 evt.accept()
1485 1527
1486 def _keyReleaseEvent(self, evt): 1528 def _keyReleaseEvent(self, evt):
1487 """ 1529 """
1488 Protected method called by a key release. 1530 Protected method called by a key release.
1489 1531
1490 @param evt reference to the key event (QKeyEvent) 1532 @param evt reference to the key event (QKeyEvent)
1491 """ 1533 """
1492 if evt.key() == Qt.Key.Key_Escape and self.isFullScreen(): 1534 if evt.key() == Qt.Key.Key_Escape and self.isFullScreen():
1493 self.triggerPageAction(QWebEnginePage.WebAction.ExitFullScreen) 1535 self.triggerPageAction(QWebEnginePage.WebAction.ExitFullScreen)
1494 evt.accept() 1536 evt.accept()
1495 self.requestFullScreen(False) 1537 self.requestFullScreen(False)
1496 1538
1497 def _gestureEvent(self, evt): 1539 def _gestureEvent(self, evt):
1498 """ 1540 """
1499 Protected method handling gesture events. 1541 Protected method handling gesture events.
1500 1542
1501 @param evt reference to the gesture event 1543 @param evt reference to the gesture event
1502 @type QGestureEvent 1544 @type QGestureEvent
1503 """ 1545 """
1504 pinch = evt.gesture(Qt.GestureType.PinchGesture) 1546 pinch = evt.gesture(Qt.GestureType.PinchGesture)
1505 if pinch: 1547 if pinch:
1507 pinch.setTotalScaleFactor(self.__currentZoom / 100.0) 1549 pinch.setTotalScaleFactor(self.__currentZoom / 100.0)
1508 elif pinch.state() == Qt.GestureState.GestureUpdated: 1550 elif pinch.state() == Qt.GestureState.GestureUpdated:
1509 scaleFactor = pinch.totalScaleFactor() 1551 scaleFactor = pinch.totalScaleFactor()
1510 self.setZoomValue(int(scaleFactor * 100)) 1552 self.setZoomValue(int(scaleFactor * 100))
1511 evt.accept() 1553 evt.accept()
1512 1554
1513 def eventFilter(self, obj, evt): 1555 def eventFilter(self, obj, evt):
1514 """ 1556 """
1515 Public method to process event for other objects. 1557 Public method to process event for other objects.
1516 1558
1517 @param obj reference to object to process events for 1559 @param obj reference to object to process events for
1518 @type QObject 1560 @type QObject
1519 @param evt reference to event to be processed 1561 @param evt reference to event to be processed
1520 @type QEvent 1562 @type QEvent
1521 @return flag indicating that the event should be filtered out 1563 @return flag indicating that the event should be filtered out
1522 @rtype bool 1564 @rtype bool
1523 """ 1565 """
1524 if ( 1566 if (
1525 obj is self and 1567 obj is self
1526 evt.type() == QEvent.Type.ParentChange and 1568 and evt.type() == QEvent.Type.ParentChange
1527 self.parentWidget() is not None 1569 and self.parentWidget() is not None
1528 ): 1570 ):
1529 self.parentWidget().installEventFilter(self) 1571 self.parentWidget().installEventFilter(self)
1530 1572
1531 # find the render widget receiving events for the web page 1573 # find the render widget receiving events for the web page
1532 if obj is self and evt.type() == QEvent.Type.ChildAdded: 1574 if obj is self and evt.type() == QEvent.Type.ChildAdded:
1533 QTimer.singleShot(0, self.__setRwhvqt) 1575 QTimer.singleShot(0, self.__setRwhvqt)
1534 1576
1535 # forward events to WebBrowserView 1577 # forward events to WebBrowserView
1536 if ( 1578 if obj is self.__rwhvqt and evt.type() in [
1537 obj is self.__rwhvqt and 1579 QEvent.Type.KeyPress,
1538 evt.type() in [QEvent.Type.KeyPress, 1580 QEvent.Type.KeyRelease,
1539 QEvent.Type.KeyRelease, 1581 QEvent.Type.MouseButtonPress,
1540 QEvent.Type.MouseButtonPress, 1582 QEvent.Type.MouseButtonRelease,
1541 QEvent.Type.MouseButtonRelease, 1583 QEvent.Type.MouseMove,
1542 QEvent.Type.MouseMove, 1584 QEvent.Type.Wheel,
1543 QEvent.Type.Wheel, 1585 QEvent.Type.Gesture,
1544 QEvent.Type.Gesture] 1586 ]:
1545 ):
1546 wasAccepted = evt.isAccepted() 1587 wasAccepted = evt.isAccepted()
1547 evt.setAccepted(False) 1588 evt.setAccepted(False)
1548 if evt.type() == QEvent.Type.KeyPress: 1589 if evt.type() == QEvent.Type.KeyPress:
1549 self._keyPressEvent(evt) 1590 self._keyPressEvent(evt)
1550 elif evt.type() == QEvent.Type.KeyRelease: 1591 elif evt.type() == QEvent.Type.KeyRelease:
1560 elif evt.type() == QEvent.Type.Gesture: 1601 elif evt.type() == QEvent.Type.Gesture:
1561 self._gestureEvent(evt) 1602 self._gestureEvent(evt)
1562 ret = evt.isAccepted() 1603 ret = evt.isAccepted()
1563 evt.setAccepted(wasAccepted) 1604 evt.setAccepted(wasAccepted)
1564 return ret 1605 return ret
1565 1606
1566 if ( 1607 if obj is self.parentWidget() and evt.type() in [
1567 obj is self.parentWidget() and 1608 QEvent.Type.KeyPress,
1568 evt.type() in [QEvent.Type.KeyPress, QEvent.Type.KeyRelease] 1609 QEvent.Type.KeyRelease,
1569 ): 1610 ]:
1570 wasAccepted = evt.isAccepted() 1611 wasAccepted = evt.isAccepted()
1571 evt.setAccepted(False) 1612 evt.setAccepted(False)
1572 if evt.type() == QEvent.Type.KeyPress: 1613 if evt.type() == QEvent.Type.KeyPress:
1573 self._keyPressEvent(evt) 1614 self._keyPressEvent(evt)
1574 elif evt.type() == QEvent.Type.KeyRelease: 1615 elif evt.type() == QEvent.Type.KeyRelease:
1575 self._keyReleaseEvent(evt) 1616 self._keyReleaseEvent(evt)
1576 ret = evt.isAccepted() 1617 ret = evt.isAccepted()
1577 evt.setAccepted(wasAccepted) 1618 evt.setAccepted(wasAccepted)
1578 return ret 1619 return ret
1579 1620
1580 # block already handled events 1621 # block already handled events
1581 if obj is self: 1622 if obj is self:
1582 if evt.type() in [QEvent.Type.KeyPress, 1623 if evt.type() in [
1583 QEvent.Type.KeyRelease, 1624 QEvent.Type.KeyPress,
1584 QEvent.Type.MouseButtonPress, 1625 QEvent.Type.KeyRelease,
1585 QEvent.Type.MouseButtonRelease, 1626 QEvent.Type.MouseButtonPress,
1586 QEvent.Type.MouseMove, 1627 QEvent.Type.MouseButtonRelease,
1587 QEvent.Type.Wheel, 1628 QEvent.Type.MouseMove,
1588 QEvent.Type.Gesture]: 1629 QEvent.Type.Wheel,
1630 QEvent.Type.Gesture,
1631 ]:
1589 return True 1632 return True
1590 1633
1591 elif evt.type() == QEvent.Type.Hide and self.isFullScreen(): 1634 elif evt.type() == QEvent.Type.Hide and self.isFullScreen():
1592 self.triggerPageAction(QWebEnginePage.WebAction.ExitFullScreen) 1635 self.triggerPageAction(QWebEnginePage.WebAction.ExitFullScreen)
1593 1636
1594 return super().eventFilter(obj, evt) 1637 return super().eventFilter(obj, evt)
1595 1638
1596 def event(self, evt): 1639 def event(self, evt):
1597 """ 1640 """
1598 Public method handling events. 1641 Public method handling events.
1599 1642
1600 @param evt reference to the event (QEvent) 1643 @param evt reference to the event (QEvent)
1601 @return flag indicating, if the event was handled (boolean) 1644 @return flag indicating, if the event was handled (boolean)
1602 """ 1645 """
1603 if evt.type() == QEvent.Type.Gesture: 1646 if evt.type() == QEvent.Type.Gesture:
1604 self._gestureEvent(evt) 1647 self._gestureEvent(evt)
1605 return True 1648 return True
1606 1649
1607 return super().event(evt) 1650 return super().event(evt)
1608 1651
1609 def inputWidget(self): 1652 def inputWidget(self):
1610 """ 1653 """
1611 Public method to get a reference to the render widget. 1654 Public method to get a reference to the render widget.
1612 1655
1613 @return reference to the render widget 1656 @return reference to the render widget
1614 @rtype QWidget 1657 @rtype QWidget
1615 """ 1658 """
1616 return self.__rwhvqt 1659 return self.__rwhvqt
1617 1660
1618 def clearHistory(self): 1661 def clearHistory(self):
1619 """ 1662 """
1620 Public slot to clear the history. 1663 Public slot to clear the history.
1621 """ 1664 """
1622 self.history().clear() 1665 self.history().clear()
1623 self.__urlChanged(self.history().currentItem().url()) 1666 self.__urlChanged(self.history().currentItem().url())
1624 1667
1625 ########################################################################### 1668 ###########################################################################
1626 ## Signal converters below 1669 ## Signal converters below
1627 ########################################################################### 1670 ###########################################################################
1628 1671
1629 def __urlChanged(self, url): 1672 def __urlChanged(self, url):
1630 """ 1673 """
1631 Private slot to handle the urlChanged signal. 1674 Private slot to handle the urlChanged signal.
1632 1675
1633 @param url the new url (QUrl) 1676 @param url the new url (QUrl)
1634 """ 1677 """
1635 self.sourceChanged.emit(url) 1678 self.sourceChanged.emit(url)
1636 1679
1637 self.forwardAvailable.emit(self.isForwardAvailable()) 1680 self.forwardAvailable.emit(self.isForwardAvailable())
1638 self.backwardAvailable.emit(self.isBackwardAvailable()) 1681 self.backwardAvailable.emit(self.isBackwardAvailable())
1639 1682
1640 def __iconUrlChanged(self, url): 1683 def __iconUrlChanged(self, url):
1641 """ 1684 """
1642 Private slot to handle the iconUrlChanged signal. 1685 Private slot to handle the iconUrlChanged signal.
1643 1686
1644 @param url URL to get web site icon from 1687 @param url URL to get web site icon from
1645 @type QUrl 1688 @type QUrl
1646 """ 1689 """
1647 self.__siteIcon = QIcon() 1690 self.__siteIcon = QIcon()
1648 if self.__siteIconLoader is not None: 1691 if self.__siteIconLoader is not None:
1649 self.__siteIconLoader.deleteLater() 1692 self.__siteIconLoader.deleteLater()
1650 self.__siteIconLoader = WebIconLoader(url, self) 1693 self.__siteIconLoader = WebIconLoader(url, self)
1651 self.__siteIconLoader.iconLoaded.connect(self.__iconLoaded) 1694 self.__siteIconLoader.iconLoaded.connect(self.__iconLoaded)
1652 with contextlib.suppress(AttributeError): 1695 with contextlib.suppress(AttributeError):
1653 self.__siteIconLoader.sslConfiguration.connect( 1696 self.__siteIconLoader.sslConfiguration.connect(
1654 self.page().setSslConfiguration) 1697 self.page().setSslConfiguration
1698 )
1655 self.__siteIconLoader.clearSslConfiguration.connect( 1699 self.__siteIconLoader.clearSslConfiguration.connect(
1656 self.page().clearSslConfiguration) 1700 self.page().clearSslConfiguration
1657 1701 )
1702
1658 def __iconLoaded(self, icon): 1703 def __iconLoaded(self, icon):
1659 """ 1704 """
1660 Private slot handling the loaded web site icon. 1705 Private slot handling the loaded web site icon.
1661 1706
1662 @param icon web site icon 1707 @param icon web site icon
1663 @type QIcon 1708 @type QIcon
1664 """ 1709 """
1665 self.__siteIcon = icon 1710 self.__siteIcon = icon
1666 1711
1667 from .Tools import WebIconProvider 1712 from .Tools import WebIconProvider
1713
1668 WebIconProvider.instance().saveIcon(self) 1714 WebIconProvider.instance().saveIcon(self)
1669 1715
1670 self.faviconChanged.emit() 1716 self.faviconChanged.emit()
1671 1717
1672 def icon(self): 1718 def icon(self):
1673 """ 1719 """
1674 Public method to get the web site icon. 1720 Public method to get the web site icon.
1675 1721
1676 @return web site icon 1722 @return web site icon
1677 @rtype QIcon 1723 @rtype QIcon
1678 """ 1724 """
1679 if not self.__siteIcon.isNull(): 1725 if not self.__siteIcon.isNull():
1680 return QIcon(self.__siteIcon) 1726 return QIcon(self.__siteIcon)
1681 1727
1682 from .Tools import WebIconProvider 1728 from .Tools import WebIconProvider
1729
1683 return WebIconProvider.instance().iconForUrl(self.url()) 1730 return WebIconProvider.instance().iconForUrl(self.url())
1684 1731
1685 def title(self): 1732 def title(self):
1686 """ 1733 """
1687 Public method to get the view title. 1734 Public method to get the view title.
1688 1735
1689 @return view title 1736 @return view title
1690 @rtype str 1737 @rtype str
1691 """ 1738 """
1692 titleStr = super().title() 1739 titleStr = super().title()
1693 if not titleStr: 1740 if not titleStr:
1694 if self.url().isEmpty(): 1741 if self.url().isEmpty():
1695 url = self.__page.requestedUrl() 1742 url = self.__page.requestedUrl()
1696 else: 1743 else:
1697 url = self.url() 1744 url = self.url()
1698 1745
1699 titleStr = url.host() 1746 titleStr = url.host()
1700 if not titleStr: 1747 if not titleStr:
1701 titleStr = url.toString( 1748 titleStr = url.toString(QUrl.UrlFormattingOption.RemoveFragment)
1702 QUrl.UrlFormattingOption.RemoveFragment) 1749
1703
1704 if not titleStr or titleStr == "about:blank": 1750 if not titleStr or titleStr == "about:blank":
1705 titleStr = self.tr("Empty Page") 1751 titleStr = self.tr("Empty Page")
1706 1752
1707 return titleStr 1753 return titleStr
1708 1754
1709 def __linkHovered(self, link): 1755 def __linkHovered(self, link):
1710 """ 1756 """
1711 Private slot to handle the linkHovered signal. 1757 Private slot to handle the linkHovered signal.
1712 1758
1713 @param link the URL of the link (string) 1759 @param link the URL of the link (string)
1714 """ 1760 """
1715 self.highlighted.emit(link) 1761 self.highlighted.emit(link)
1716 1762
1717 ########################################################################### 1763 ###########################################################################
1718 ## Signal handlers below 1764 ## Signal handlers below
1719 ########################################################################### 1765 ###########################################################################
1720 1766
1721 def __renderProcessTerminated(self, status, exitCode): 1767 def __renderProcessTerminated(self, status, exitCode):
1722 """ 1768 """
1723 Private slot handling a crash of the web page render process. 1769 Private slot handling a crash of the web page render process.
1724 1770
1725 @param status termination status 1771 @param status termination status
1726 @type QWebEnginePage.RenderProcessTerminationStatus 1772 @type QWebEnginePage.RenderProcessTerminationStatus
1727 @param exitCode exit code of the process 1773 @param exitCode exit code of the process
1728 @type int 1774 @type int
1729 """ 1775 """
1730 if ( 1776 if (
1731 status == 1777 status
1732 QWebEnginePage.RenderProcessTerminationStatus 1778 == QWebEnginePage.RenderProcessTerminationStatus.NormalTerminationStatus
1733 .NormalTerminationStatus
1734 ): 1779 ):
1735 return 1780 return
1736 1781
1737 QTimer.singleShot(0, 1782 QTimer.singleShot(0, functools.partial(self.__showTabCrashPage, status))
1738 functools.partial(self.__showTabCrashPage, status)) 1783
1739
1740 def __showTabCrashPage(self, status): 1784 def __showTabCrashPage(self, status):
1741 """ 1785 """
1742 Private slot to show the tab crash page. 1786 Private slot to show the tab crash page.
1743 1787
1744 @param status termination status 1788 @param status termination status
1745 @type QWebEnginePage.RenderProcessTerminationStatus 1789 @type QWebEnginePage.RenderProcessTerminationStatus
1746 """ 1790 """
1747 self.page().deleteLater() 1791 self.page().deleteLater()
1748 self.__createNewPage() 1792 self.__createNewPage()
1749 1793
1750 html = getHtmlPage("tabCrashPage.html") 1794 html = getHtmlPage("tabCrashPage.html")
1751 html = html.replace("@IMAGE@", pixmapToDataUrl(
1752 ericApp().style().standardIcon(
1753 QStyle.StandardPixmap.SP_MessageBoxWarning).pixmap(48, 48)
1754 ).toString())
1755 html = html.replace("@FAVICON@", pixmapToDataUrl(
1756 ericApp().style() .standardIcon(
1757 QStyle.StandardPixmap.SP_MessageBoxWarning).pixmap(16, 16)
1758 ).toString())
1759 html = html.replace( 1795 html = html.replace(
1760 "@TITLE@", self.tr("Render Process terminated abnormally")) 1796 "@IMAGE@",
1797 pixmapToDataUrl(
1798 ericApp()
1799 .style()
1800 .standardIcon(QStyle.StandardPixmap.SP_MessageBoxWarning)
1801 .pixmap(48, 48)
1802 ).toString(),
1803 )
1761 html = html.replace( 1804 html = html.replace(
1762 "@H1@", self.tr("Render Process terminated abnormally")) 1805 "@FAVICON@",
1806 pixmapToDataUrl(
1807 ericApp()
1808 .style()
1809 .standardIcon(QStyle.StandardPixmap.SP_MessageBoxWarning)
1810 .pixmap(16, 16)
1811 ).toString(),
1812 )
1813 html = html.replace("@TITLE@", self.tr("Render Process terminated abnormally"))
1814 html = html.replace("@H1@", self.tr("Render Process terminated abnormally"))
1763 if ( 1815 if (
1764 status == 1816 status
1765 QWebEnginePage.RenderProcessTerminationStatus 1817 == QWebEnginePage.RenderProcessTerminationStatus.CrashedTerminationStatus
1766 .CrashedTerminationStatus
1767 ): 1818 ):
1768 msg = self.tr("The render process crashed while" 1819 msg = self.tr("The render process crashed while" " loading this page.")
1769 " loading this page.")
1770 elif ( 1820 elif (
1771 status == 1821 status
1772 QWebEnginePage.RenderProcessTerminationStatus 1822 == QWebEnginePage.RenderProcessTerminationStatus.KilledTerminationStatus
1773 .KilledTerminationStatus
1774 ): 1823 ):
1775 msg = self.tr("The render process was killed.") 1824 msg = self.tr("The render process was killed.")
1776 else: 1825 else:
1777 msg = self.tr("The render process terminated while" 1826 msg = self.tr("The render process terminated while" " loading this page.")
1778 " loading this page.")
1779 html = html.replace("@LI-1@", msg) 1827 html = html.replace("@LI-1@", msg)
1780 html = html.replace( 1828 html = html.replace(
1781 "@LI-2@", 1829 "@LI-2@",
1782 self.tr( 1830 self.tr(
1783 "Try reloading the page or closing some tabs to make more" 1831 "Try reloading the page or closing some tabs to make more"
1784 " memory available.")) 1832 " memory available."
1833 ),
1834 )
1785 self.page().setHtml(html, self.url()) 1835 self.page().setHtml(html, self.url())
1786 1836
1787 def __loadStarted(self): 1837 def __loadStarted(self):
1788 """ 1838 """
1789 Private method to handle the loadStarted signal. 1839 Private method to handle the loadStarted signal.
1790 """ 1840 """
1791 # reset search 1841 # reset search
1792 self.findText("") 1842 self.findText("")
1793 self.__isLoading = True 1843 self.__isLoading = True
1794 self.__progress = 0 1844 self.__progress = 0
1795 1845
1796 def __loadProgress(self, progress): 1846 def __loadProgress(self, progress):
1797 """ 1847 """
1798 Private method to handle the loadProgress signal. 1848 Private method to handle the loadProgress signal.
1799 1849
1800 @param progress progress value (integer) 1850 @param progress progress value (integer)
1801 """ 1851 """
1802 self.__progress = progress 1852 self.__progress = progress
1803 1853
1804 def __loadFinished(self, ok): 1854 def __loadFinished(self, ok):
1805 """ 1855 """
1806 Private method to handle the loadFinished signal. 1856 Private method to handle the loadFinished signal.
1807 1857
1808 @param ok flag indicating the result (boolean) 1858 @param ok flag indicating the result (boolean)
1809 """ 1859 """
1810 self.__isLoading = False 1860 self.__isLoading = False
1811 self.__progress = 0 1861 self.__progress = 0
1812 1862
1813 QApplication.processEvents() 1863 QApplication.processEvents()
1814 QTimer.singleShot(200, self.__renderPreview) 1864 QTimer.singleShot(200, self.__renderPreview)
1815 1865
1816 from .ZoomManager import ZoomManager 1866 from .ZoomManager import ZoomManager
1867
1817 zoomValue = ZoomManager.instance().zoomValue(self.url()) 1868 zoomValue = ZoomManager.instance().zoomValue(self.url())
1818 self.setZoomValue(zoomValue) 1869 self.setZoomValue(zoomValue)
1819 1870
1820 if ok: 1871 if ok:
1821 self.__mw.historyManager().addHistoryEntry(self) 1872 self.__mw.historyManager().addHistoryEntry(self)
1822 self.__mw.adBlockManager().page().hideBlockedPageEntries( 1873 self.__mw.adBlockManager().page().hideBlockedPageEntries(self.page())
1823 self.page())
1824 self.__mw.passwordManager().completePage(self.page()) 1874 self.__mw.passwordManager().completePage(self.page())
1825 1875
1826 self.page().runJavaScript( 1876 self.page().runJavaScript(
1827 "document.lastModified", WebBrowserPage.SafeJsWorld, 1877 "document.lastModified",
1828 lambda res: self.__adjustBookmark(res)) 1878 WebBrowserPage.SafeJsWorld,
1829 1879 lambda res: self.__adjustBookmark(res),
1880 )
1881
1830 def __adjustBookmark(self, lastModified): 1882 def __adjustBookmark(self, lastModified):
1831 """ 1883 """
1832 Private slot to adjust the 'lastModified' value of bookmarks. 1884 Private slot to adjust the 'lastModified' value of bookmarks.
1833 1885
1834 @param lastModified last modified value 1886 @param lastModified last modified value
1835 @type str 1887 @type str
1836 """ 1888 """
1837 modified = QDateTime.fromString(lastModified, "MM/dd/yyyy hh:mm:ss") 1889 modified = QDateTime.fromString(lastModified, "MM/dd/yyyy hh:mm:ss")
1838 if modified.isValid(): 1890 if modified.isValid():
1839 from WebBrowser.WebBrowserWindow import WebBrowserWindow 1891 from WebBrowser.WebBrowserWindow import WebBrowserWindow
1840 from .Bookmarks.BookmarkNode import BookmarkNode 1892 from .Bookmarks.BookmarkNode import BookmarkNode
1893
1841 manager = WebBrowserWindow.bookmarksManager() 1894 manager = WebBrowserWindow.bookmarksManager()
1842 for bookmark in manager.bookmarksForUrl(self.url()): 1895 for bookmark in manager.bookmarksForUrl(self.url()):
1843 manager.setTimestamp(bookmark, BookmarkNode.TsModified, 1896 manager.setTimestamp(bookmark, BookmarkNode.TsModified, modified)
1844 modified) 1897
1845
1846 def isLoading(self): 1898 def isLoading(self):
1847 """ 1899 """
1848 Public method to get the loading state. 1900 Public method to get the loading state.
1849 1901
1850 @return flag indicating the loading state (boolean) 1902 @return flag indicating the loading state (boolean)
1851 """ 1903 """
1852 return self.__isLoading 1904 return self.__isLoading
1853 1905
1854 def progress(self): 1906 def progress(self):
1855 """ 1907 """
1856 Public method to get the load progress. 1908 Public method to get the load progress.
1857 1909
1858 @return load progress (integer) 1910 @return load progress (integer)
1859 """ 1911 """
1860 return self.__progress 1912 return self.__progress
1861 1913
1862 def __renderPreview(self): 1914 def __renderPreview(self):
1863 """ 1915 """
1864 Private slot to render a preview pixmap after the page was loaded. 1916 Private slot to render a preview pixmap after the page was loaded.
1865 """ 1917 """
1866 from .WebBrowserSnap import renderTabPreview 1918 from .WebBrowserSnap import renderTabPreview
1867 w = 600 # some default width, the preview gets scaled when shown 1919
1920 w = 600 # some default width, the preview gets scaled when shown
1868 h = int(w * self.height() / self.width()) 1921 h = int(w * self.height() / self.width())
1869 self.__preview = renderTabPreview(self, w, h) 1922 self.__preview = renderTabPreview(self, w, h)
1870 1923
1871 def getPreview(self): 1924 def getPreview(self):
1872 """ 1925 """
1873 Public method to get the preview pixmap. 1926 Public method to get the preview pixmap.
1874 1927
1875 @return preview pixmap 1928 @return preview pixmap
1876 @rtype QPixmap 1929 @rtype QPixmap
1877 """ 1930 """
1878 return self.__preview 1931 return self.__preview
1879 1932
1880 def saveAs(self): 1933 def saveAs(self):
1881 """ 1934 """
1882 Public method to save the current page to a file. 1935 Public method to save the current page to a file.
1883 """ 1936 """
1884 url = self.url() 1937 url = self.url()
1885 if url.isEmpty(): 1938 if url.isEmpty():
1886 return 1939 return
1887 1940
1888 fileName, savePageFormat = self.__getSavePageFileNameAndFormat() 1941 fileName, savePageFormat = self.__getSavePageFileNameAndFormat()
1889 if fileName: 1942 if fileName:
1890 self.page().save(fileName, savePageFormat) 1943 self.page().save(fileName, savePageFormat)
1891 1944
1892 def __getSavePageFileNameAndFormat(self): 1945 def __getSavePageFileNameAndFormat(self):
1893 """ 1946 """
1894 Private method to get the file name to save the page to. 1947 Private method to get the file name to save the page to.
1895 1948
1896 @return tuple containing the file name to save to and the 1949 @return tuple containing the file name to save to and the
1897 save page format 1950 save page format
1898 @rtype tuple of (str, QWebEngineDownloadRequest.SavePageFormat) 1951 @rtype tuple of (str, QWebEngineDownloadRequest.SavePageFormat)
1899 """ 1952 """
1900 documentLocation = QStandardPaths.writableLocation( 1953 documentLocation = QStandardPaths.writableLocation(
1901 QStandardPaths.StandardLocation.DocumentsLocation) 1954 QStandardPaths.StandardLocation.DocumentsLocation
1955 )
1902 filterList = [ 1956 filterList = [
1903 self.tr("Web Archive (*.mhtml *.mht)"), 1957 self.tr("Web Archive (*.mhtml *.mht)"),
1904 self.tr("HTML File (*.html *.htm)"), 1958 self.tr("HTML File (*.html *.htm)"),
1905 self.tr("HTML File with all resources (*.html *.htm)"), 1959 self.tr("HTML File with all resources (*.html *.htm)"),
1906 ] 1960 ]
1910 (".mhtml", ".mht"), 1964 (".mhtml", ".mht"),
1911 (".html", ".htm"), 1965 (".html", ".htm"),
1912 (".html", ".htm"), 1966 (".html", ".htm"),
1913 ] 1967 ]
1914 if self.url().fileName(): 1968 if self.url().fileName():
1915 defaultFileName = os.path.join(documentLocation, 1969 defaultFileName = os.path.join(documentLocation, self.url().fileName())
1916 self.url().fileName())
1917 else: 1970 else:
1918 defaultFileName = os.path.join(documentLocation, 1971 defaultFileName = os.path.join(documentLocation, self.page().title())
1919 self.page().title())
1920 if Utilities.isWindowsPlatform(): 1972 if Utilities.isWindowsPlatform():
1921 defaultFileName += ".mht" 1973 defaultFileName += ".mht"
1922 else: 1974 else:
1923 defaultFileName += ".mhtml" 1975 defaultFileName += ".mhtml"
1924 1976
1925 fileName = "" 1977 fileName = ""
1926 saveFormat = ( 1978 saveFormat = QWebEngineDownloadRequest.SavePageFormat.MimeHtmlSaveFormat
1927 QWebEngineDownloadRequest.SavePageFormat.MimeHtmlSaveFormat 1979
1928 )
1929
1930 fileName, selectedFilter = EricFileDialog.getSaveFileNameAndFilter( 1980 fileName, selectedFilter = EricFileDialog.getSaveFileNameAndFilter(
1931 None, 1981 None, self.tr("Save Web Page"), defaultFileName, ";;".join(filterList), None
1932 self.tr("Save Web Page"), 1982 )
1933 defaultFileName,
1934 ";;".join(filterList),
1935 None)
1936 if fileName: 1983 if fileName:
1937 index = filterList.index(selectedFilter) 1984 index = filterList.index(selectedFilter)
1938 if index == 0: 1985 if index == 0:
1939 saveFormat = ( 1986 saveFormat = QWebEngineDownloadRequest.SavePageFormat.MimeHtmlSaveFormat
1940 QWebEngineDownloadRequest.SavePageFormat.MimeHtmlSaveFormat
1941 )
1942 elif index == 1: 1987 elif index == 1:
1943 saveFormat = ( 1988 saveFormat = (
1944 QWebEngineDownloadRequest.SavePageFormat 1989 QWebEngineDownloadRequest.SavePageFormat.SingleHtmlSaveFormat
1945 .SingleHtmlSaveFormat
1946 ) 1990 )
1947 else: 1991 else:
1948 saveFormat = ( 1992 saveFormat = (
1949 QWebEngineDownloadRequest.SavePageFormat 1993 QWebEngineDownloadRequest.SavePageFormat.CompleteHtmlSaveFormat
1950 .CompleteHtmlSaveFormat
1951 ) 1994 )
1952 1995
1953 extension = os.path.splitext(fileName)[1] 1996 extension = os.path.splitext(fileName)[1]
1954 if not extension: 1997 if not extension:
1955 # add the platform specific default extension 1998 # add the platform specific default extension
1956 if Utilities.isWindowsPlatform(): 1999 if Utilities.isWindowsPlatform():
1957 extensionsIndex = 1 2000 extensionsIndex = 1
1958 else: 2001 else:
1959 extensionsIndex = 0 2002 extensionsIndex = 0
1960 extensions = extensionsList[index] 2003 extensions = extensionsList[index]
1961 fileName += extensions[extensionsIndex] 2004 fileName += extensions[extensionsIndex]
1962 2005
1963 return fileName, saveFormat 2006 return fileName, saveFormat
1964 2007
1965 ########################################################################### 2008 ###########################################################################
1966 ## Miscellaneous methods below 2009 ## Miscellaneous methods below
1967 ########################################################################### 2010 ###########################################################################
1968 2011
1969 def createWindow(self, windowType): 2012 def createWindow(self, windowType):
1970 """ 2013 """
1971 Public method called, when a new window should be created. 2014 Public method called, when a new window should be created.
1972 2015
1973 @param windowType type of the requested window 2016 @param windowType type of the requested window
1974 (QWebEnginePage.WebWindowType) 2017 (QWebEnginePage.WebWindowType)
1975 @return reference to the created browser window (WebBrowserView) 2018 @return reference to the created browser window (WebBrowserView)
1976 """ 2019 """
1977 if windowType in [QWebEnginePage.WebWindowType.WebBrowserTab, 2020 if windowType in [
1978 QWebEnginePage.WebWindowType.WebDialog]: 2021 QWebEnginePage.WebWindowType.WebBrowserTab,
2022 QWebEnginePage.WebWindowType.WebDialog,
2023 ]:
1979 return self.__mw.newTab(addNextTo=self) 2024 return self.__mw.newTab(addNextTo=self)
1980 elif windowType == QWebEnginePage.WebWindowType.WebBrowserWindow: 2025 elif windowType == QWebEnginePage.WebWindowType.WebBrowserWindow:
1981 return self.__mw.newWindow().currentBrowser() 2026 return self.__mw.newWindow().currentBrowser()
1982 elif ( 2027 elif windowType == QWebEnginePage.WebWindowType.WebBrowserBackgroundTab:
1983 windowType == QWebEnginePage.WebWindowType.WebBrowserBackgroundTab
1984 ):
1985 return self.__mw.newTab(addNextTo=self, background=True) 2028 return self.__mw.newTab(addNextTo=self, background=True)
1986 else: 2029 else:
1987 # default for unknow/new window types 2030 # default for unknow/new window types
1988 return self.__mw.newTab(addNextTo=self) 2031 return self.__mw.newTab(addNextTo=self)
1989 2032
1990 def preferencesChanged(self): 2033 def preferencesChanged(self):
1991 """ 2034 """
1992 Public method to indicate a change of the settings. 2035 Public method to indicate a change of the settings.
1993 """ 2036 """
1994 self.reload() 2037 self.reload()
1995 2038
1996 ########################################################################### 2039 ###########################################################################
1997 ## RSS related methods below 2040 ## RSS related methods below
1998 ########################################################################### 2041 ###########################################################################
1999 2042
2000 def checkRSS(self): 2043 def checkRSS(self):
2001 """ 2044 """
2002 Public method to check, if the loaded page contains feed links. 2045 Public method to check, if the loaded page contains feed links.
2003 2046
2004 @return flag indicating the existence of feed links (boolean) 2047 @return flag indicating the existence of feed links (boolean)
2005 """ 2048 """
2006 self.__rss = [] 2049 self.__rss = []
2007 2050
2008 script = Scripts.getFeedLinks() 2051 script = Scripts.getFeedLinks()
2009 feeds = self.page().execJavaScript(script) 2052 feeds = self.page().execJavaScript(script)
2010 2053
2011 if feeds is not None: 2054 if feeds is not None:
2012 for feed in feeds: 2055 for feed in feeds:
2013 if feed["url"] and feed["title"]: 2056 if feed["url"] and feed["title"]:
2014 self.__rss.append((feed["title"], feed["url"])) 2057 self.__rss.append((feed["title"], feed["url"]))
2015 2058
2016 return len(self.__rss) > 0 2059 return len(self.__rss) > 0
2017 2060
2018 def getRSS(self): 2061 def getRSS(self):
2019 """ 2062 """
2020 Public method to get the extracted RSS feeds. 2063 Public method to get the extracted RSS feeds.
2021 2064
2022 @return list of RSS feeds (list of tuples of two strings) 2065 @return list of RSS feeds (list of tuples of two strings)
2023 """ 2066 """
2024 return self.__rss 2067 return self.__rss
2025 2068
2026 def hasRSS(self): 2069 def hasRSS(self):
2027 """ 2070 """
2028 Public method to check, if the loaded page has RSS links. 2071 Public method to check, if the loaded page has RSS links.
2029 2072
2030 @return flag indicating the presence of RSS links (boolean) 2073 @return flag indicating the presence of RSS links (boolean)
2031 """ 2074 """
2032 return len(self.__rss) > 0 2075 return len(self.__rss) > 0
2033 2076
2034 ########################################################################### 2077 ###########################################################################
2035 ## Full Screen handling below 2078 ## Full Screen handling below
2036 ########################################################################### 2079 ###########################################################################
2037 2080
2038 def isFullScreen(self): 2081 def isFullScreen(self):
2039 """ 2082 """
2040 Public method to check, if full screen mode is active. 2083 Public method to check, if full screen mode is active.
2041 2084
2042 @return flag indicating full screen mode 2085 @return flag indicating full screen mode
2043 @rtype bool 2086 @rtype bool
2044 """ 2087 """
2045 return self.__mw.isFullScreen() 2088 return self.__mw.isFullScreen()
2046 2089
2047 def requestFullScreen(self, enable): 2090 def requestFullScreen(self, enable):
2048 """ 2091 """
2049 Public method to request full screen mode. 2092 Public method to request full screen mode.
2050 2093
2051 @param enable flag indicating full screen mode on or off 2094 @param enable flag indicating full screen mode on or off
2052 @type bool 2095 @type bool
2053 """ 2096 """
2054 if enable: 2097 if enable:
2055 self.__mw.enterHtmlFullScreen() 2098 self.__mw.enterHtmlFullScreen()
2056 else: 2099 else:
2057 self.__mw.showNormal() 2100 self.__mw.showNormal()
2058 2101
2059 ########################################################################### 2102 ###########################################################################
2060 ## Speed Dial slots below 2103 ## Speed Dial slots below
2061 ########################################################################### 2104 ###########################################################################
2062 2105
2063 def __addSpeedDial(self): 2106 def __addSpeedDial(self):
2064 """ 2107 """
2065 Private slot to add a new speed dial. 2108 Private slot to add a new speed dial.
2066 """ 2109 """
2067 self.__page.runJavaScript("addSpeedDial();", 2110 self.__page.runJavaScript("addSpeedDial();", WebBrowserPage.SafeJsWorld)
2068 WebBrowserPage.SafeJsWorld) 2111
2069
2070 def __configureSpeedDial(self): 2112 def __configureSpeedDial(self):
2071 """ 2113 """
2072 Private slot to configure the speed dial. 2114 Private slot to configure the speed dial.
2073 """ 2115 """
2074 self.page().runJavaScript("configureSpeedDial();", 2116 self.page().runJavaScript("configureSpeedDial();", WebBrowserPage.SafeJsWorld)
2075 WebBrowserPage.SafeJsWorld) 2117
2076
2077 def __reloadAllSpeedDials(self): 2118 def __reloadAllSpeedDials(self):
2078 """ 2119 """
2079 Private slot to reload all speed dials. 2120 Private slot to reload all speed dials.
2080 """ 2121 """
2081 self.page().runJavaScript("reloadAll();", WebBrowserPage.SafeJsWorld) 2122 self.page().runJavaScript("reloadAll();", WebBrowserPage.SafeJsWorld)
2082 2123
2083 def __resetSpeedDials(self): 2124 def __resetSpeedDials(self):
2084 """ 2125 """
2085 Private slot to reset all speed dials to the default pages. 2126 Private slot to reset all speed dials to the default pages.
2086 """ 2127 """
2087 self.__speedDial.resetDials() 2128 self.__speedDial.resetDials()
2088 2129
2089 ########################################################################### 2130 ###########################################################################
2090 ## Methods below implement session related functions 2131 ## Methods below implement session related functions
2091 ########################################################################### 2132 ###########################################################################
2092 2133
2093 def storeSessionData(self, data): 2134 def storeSessionData(self, data):
2094 """ 2135 """
2095 Public method to store session data to be restored later on. 2136 Public method to store session data to be restored later on.
2096 2137
2097 @param data dictionary with session data to be restored 2138 @param data dictionary with session data to be restored
2098 @type dict 2139 @type dict
2099 """ 2140 """
2100 self.__restoreData = data 2141 self.__restoreData = data
2101 2142
2102 def __showEventSlot(self): 2143 def __showEventSlot(self):
2103 """ 2144 """
2104 Private slot to perform actions when the view is shown and the event 2145 Private slot to perform actions when the view is shown and the event
2105 loop is running. 2146 loop is running.
2106 """ 2147 """
2107 if self.__restoreData: 2148 if self.__restoreData:
2108 sessionData, self.__restoreData = self.__restoreData, None 2149 sessionData, self.__restoreData = self.__restoreData, None
2109 self.loadFromSessionData(sessionData) 2150 self.loadFromSessionData(sessionData)
2110 2151
2111 def showEvent(self, evt): 2152 def showEvent(self, evt):
2112 """ 2153 """
2113 Protected method to handle show events. 2154 Protected method to handle show events.
2114 2155
2115 @param evt reference to the show event object 2156 @param evt reference to the show event object
2116 @type QShowEvent 2157 @type QShowEvent
2117 """ 2158 """
2118 super().showEvent(evt) 2159 super().showEvent(evt)
2119 self.activateSession() 2160 self.activateSession()
2120 2161
2121 def activateSession(self): 2162 def activateSession(self):
2122 """ 2163 """
2123 Public slot to activate a restored session. 2164 Public slot to activate a restored session.
2124 """ 2165 """
2125 if self.__restoreData and not self.__mw.isClosing(): 2166 if self.__restoreData and not self.__mw.isClosing():
2126 QTimer.singleShot(0, self.__showEventSlot) 2167 QTimer.singleShot(0, self.__showEventSlot)
2127 2168
2128 def getSessionData(self): 2169 def getSessionData(self):
2129 """ 2170 """
2130 Public method to populate the session data. 2171 Public method to populate the session data.
2131 2172
2132 @return dictionary containing the session data 2173 @return dictionary containing the session data
2133 @rtype dict 2174 @rtype dict
2134 """ 2175 """
2135 if self.__restoreData: 2176 if self.__restoreData:
2136 # page has not been shown yet 2177 # page has not been shown yet
2137 return self.__restoreData 2178 return self.__restoreData
2138 2179
2139 sessionData = {} 2180 sessionData = {}
2140 page = self.page() 2181 page = self.page()
2141 2182
2142 # 1. zoom factor 2183 # 1. zoom factor
2143 sessionData["ZoomFactor"] = page.zoomFactor() 2184 sessionData["ZoomFactor"] = page.zoomFactor()
2144 2185
2145 # 2. scroll position 2186 # 2. scroll position
2146 scrollPos = page.scrollPosition() 2187 scrollPos = page.scrollPosition()
2147 sessionData["ScrollPosition"] = { 2188 sessionData["ScrollPosition"] = {
2148 "x": scrollPos.x(), 2189 "x": scrollPos.x(),
2149 "y": scrollPos.y(), 2190 "y": scrollPos.y(),
2150 } 2191 }
2151 2192
2152 # 3. page history 2193 # 3. page history
2153 historyArray = QByteArray() 2194 historyArray = QByteArray()
2154 stream = QDataStream(historyArray, QIODevice.OpenModeFlag.WriteOnly) 2195 stream = QDataStream(historyArray, QIODevice.OpenModeFlag.WriteOnly)
2155 stream << page.history() 2196 stream << page.history()
2156 sessionData["History"] = str( 2197 sessionData["History"] = str(
2157 historyArray.toBase64(QByteArray.Base64Option.Base64UrlEncoding), 2198 historyArray.toBase64(QByteArray.Base64Option.Base64UrlEncoding),
2158 encoding="ascii") 2199 encoding="ascii",
2200 )
2159 sessionData["HistoryIndex"] = page.history().currentItemIndex() 2201 sessionData["HistoryIndex"] = page.history().currentItemIndex()
2160 2202
2161 # 4. current URL and title 2203 # 4. current URL and title
2162 sessionData["Url"] = self.url().toString() 2204 sessionData["Url"] = self.url().toString()
2163 sessionData["Title"] = self.title() 2205 sessionData["Title"] = self.title()
2164 2206
2165 # 5. web icon 2207 # 5. web icon
2166 iconArray = QByteArray() 2208 iconArray = QByteArray()
2167 stream = QDataStream(iconArray, QIODevice.OpenModeFlag.WriteOnly) 2209 stream = QDataStream(iconArray, QIODevice.OpenModeFlag.WriteOnly)
2168 stream << page.icon() 2210 stream << page.icon()
2169 sessionData["Icon"] = str(iconArray.toBase64(), encoding="ascii") 2211 sessionData["Icon"] = str(iconArray.toBase64(), encoding="ascii")
2170 2212
2171 return sessionData 2213 return sessionData
2172 2214
2173 def loadFromSessionData(self, sessionData): 2215 def loadFromSessionData(self, sessionData):
2174 """ 2216 """
2175 Public method to load the session data. 2217 Public method to load the session data.
2176 2218
2177 @param sessionData dictionary containing the session data as 2219 @param sessionData dictionary containing the session data as
2178 generated by getSessionData() 2220 generated by getSessionData()
2179 @type dict 2221 @type dict
2180 """ 2222 """
2181 page = self.page() 2223 page = self.page()
2182 # blank the page 2224 # blank the page
2183 page.setUrl(QUrl("about:blank")) 2225 page.setUrl(QUrl("about:blank"))
2184 2226
2185 # 1. page history 2227 # 1. page history
2186 if "History" in sessionData: 2228 if "History" in sessionData:
2187 historyArray = QByteArray.fromBase64( 2229 historyArray = QByteArray.fromBase64(
2188 sessionData["History"].encode("ascii"), 2230 sessionData["History"].encode("ascii"),
2189 QByteArray.Base64Option.Base64UrlEncoding) 2231 QByteArray.Base64Option.Base64UrlEncoding,
2232 )
2190 stream = QDataStream(historyArray, QIODevice.OpenModeFlag.ReadOnly) 2233 stream = QDataStream(historyArray, QIODevice.OpenModeFlag.ReadOnly)
2191 stream >> page.history() 2234 stream >> page.history()
2192 2235
2193 if "HistoryIndex" in sessionData: 2236 if "HistoryIndex" in sessionData:
2194 item = page.history().itemAt(sessionData["HistoryIndex"]) 2237 item = page.history().itemAt(sessionData["HistoryIndex"])
2195 if item is not None: 2238 if item is not None:
2196 page.history().goToItem(item) 2239 page.history().goToItem(item)
2197 2240
2198 # 2. zoom factor 2241 # 2. zoom factor
2199 if "ZoomFactor" in sessionData: 2242 if "ZoomFactor" in sessionData:
2200 page.setZoomFactor(sessionData["ZoomFactor"]) 2243 page.setZoomFactor(sessionData["ZoomFactor"])
2201 2244
2202 # 3. scroll position 2245 # 3. scroll position
2203 if "ScrollPosition" in sessionData: 2246 if "ScrollPosition" in sessionData:
2204 scrollPos = sessionData["ScrollPosition"] 2247 scrollPos = sessionData["ScrollPosition"]
2205 page.scrollTo(QPointF(scrollPos["x"], scrollPos["y"])) 2248 page.scrollTo(QPointF(scrollPos["x"], scrollPos["y"]))
2206 2249
2207 def extractSessionMetaData(self, sessionData): 2250 def extractSessionMetaData(self, sessionData):
2208 """ 2251 """
2209 Public method to extract some session meta data elements needed by the 2252 Public method to extract some session meta data elements needed by the
2210 tab widget in case of deferred loading. 2253 tab widget in case of deferred loading.
2211 2254
2212 @param sessionData dictionary containing the session data as 2255 @param sessionData dictionary containing the session data as
2213 generated by getSessionData() 2256 generated by getSessionData()
2214 @type dict 2257 @type dict
2215 @return tuple containing the title, URL and web icon 2258 @return tuple containing the title, URL and web icon
2216 @rtype tuple of (str, str, QIcon) 2259 @rtype tuple of (str, str, QIcon)
2217 """ 2260 """
2218 title = sessionData.get("Title", "") 2261 title = sessionData.get("Title", "")
2219 urlStr = sessionData.get("Url", "") 2262 urlStr = sessionData.get("Url", "")
2220 2263
2221 if "Icon" in sessionData: 2264 if "Icon" in sessionData:
2222 iconArray = QByteArray.fromBase64( 2265 iconArray = QByteArray.fromBase64(sessionData["Icon"].encode("ascii"))
2223 sessionData["Icon"].encode("ascii"))
2224 stream = QDataStream(iconArray, QIODevice.OpenModeFlag.ReadOnly) 2266 stream = QDataStream(iconArray, QIODevice.OpenModeFlag.ReadOnly)
2225 icon = QIcon() 2267 icon = QIcon()
2226 stream >> icon 2268 stream >> icon
2227 else: 2269 else:
2228 from .Tools import WebIconProvider 2270 from .Tools import WebIconProvider
2229 icon = WebIconProvider.instance().iconForUrl( 2271
2230 QUrl.fromUserInput(urlStr)) 2272 icon = WebIconProvider.instance().iconForUrl(QUrl.fromUserInput(urlStr))
2231 2273
2232 return title, urlStr, icon 2274 return title, urlStr, icon
2233 2275
2234 ########################################################################### 2276 ###########################################################################
2235 ## Methods below implement safe browsing related functions 2277 ## Methods below implement safe browsing related functions
2236 ########################################################################### 2278 ###########################################################################
2237 2279
2238 def getSafeBrowsingStatus(self): 2280 def getSafeBrowsingStatus(self):
2239 """ 2281 """
2240 Public method to get the safe browsing status of the current page. 2282 Public method to get the safe browsing status of the current page.
2241 2283
2242 @return flag indicating a safe site 2284 @return flag indicating a safe site
2243 @rtype bool 2285 @rtype bool
2244 """ 2286 """
2245 if self.__page: 2287 if self.__page:
2246 return self.__page.getSafeBrowsingStatus() 2288 return self.__page.getSafeBrowsingStatus()
2247 else: 2289 else:
2248 return True 2290 return True
2249 2291
2250 ########################################################################### 2292 ###########################################################################
2251 ## Methods below implement print support from the page 2293 ## Methods below implement print support from the page
2252 ########################################################################### 2294 ###########################################################################
2253 2295
2254 @pyqtSlot() 2296 @pyqtSlot()
2255 def __printPage(self): 2297 def __printPage(self):
2256 """ 2298 """
2257 Private slot to support printing from the web page. 2299 Private slot to support printing from the web page.
2258 """ 2300 """
2259 self.__mw.tabWidget.printBrowser(browser=self) 2301 self.__mw.tabWidget.printBrowser(browser=self)
2260 2302
2261 ########################################################################### 2303 ###########################################################################
2262 ## Methods below implement slots for Qt 5.11+ 2304 ## Methods below implement slots for Qt 5.11+
2263 ########################################################################### 2305 ###########################################################################
2264 2306
2265 @pyqtSlot("QWebEngineQuotaRequest") 2307 @pyqtSlot("QWebEngineQuotaRequest")
2266 def __quotaRequested(self, quotaRequest): 2308 def __quotaRequested(self, quotaRequest):
2267 """ 2309 """
2268 Private slot to handle quota requests of the web page. 2310 Private slot to handle quota requests of the web page.
2269 2311
2270 @param quotaRequest reference to the quota request object 2312 @param quotaRequest reference to the quota request object
2271 @type QWebEngineQuotaRequest 2313 @type QWebEngineQuotaRequest
2272 """ 2314 """
2273 acceptRequest = Preferences.getWebBrowser("AcceptQuotaRequest") 2315 acceptRequest = Preferences.getWebBrowser("AcceptQuotaRequest")
2274 # map yes/no/ask from (0, 1, 2) 2316 # map yes/no/ask from (0, 1, 2)
2279 # always no 2321 # always no
2280 ok = False 2322 ok = False
2281 else: 2323 else:
2282 # ask user 2324 # ask user
2283 from .Download.DownloadUtilities import dataString 2325 from .Download.DownloadUtilities import dataString
2326
2284 sizeStr = dataString(quotaRequest.requestedSize()) 2327 sizeStr = dataString(quotaRequest.requestedSize())
2285 2328
2286 ok = EricMessageBox.yesNo( 2329 ok = EricMessageBox.yesNo(
2287 self, 2330 self,
2288 self.tr("Quota Request"), 2331 self.tr("Quota Request"),
2289 self.tr("""<p> Allow the website at <b>{0}</b> to use""" 2332 self.tr(
2290 """ <b>{1}</b> of persistent storage?</p>""") 2333 """<p> Allow the website at <b>{0}</b> to use"""
2291 .format(quotaRequest.origin().host(), sizeStr) 2334 """ <b>{1}</b> of persistent storage?</p>"""
2292 ) 2335 ).format(quotaRequest.origin().host(), sizeStr),
2293 2336 )
2337
2294 if ok: 2338 if ok:
2295 quotaRequest.accept() 2339 quotaRequest.accept()
2296 else: 2340 else:
2297 quotaRequest.reject() 2341 quotaRequest.reject()
2298 2342
2299 ########################################################################### 2343 ###########################################################################
2300 ## Methods below implement slots for Qt 5.12+ 2344 ## Methods below implement slots for Qt 5.12+
2301 ########################################################################### 2345 ###########################################################################
2302 2346
2303 @pyqtSlot("QWebEngineClientCertificateSelection") 2347 @pyqtSlot("QWebEngineClientCertificateSelection")
2304 def __selectClientCertificate(self, clientCertificateSelection): 2348 def __selectClientCertificate(self, clientCertificateSelection):
2305 """ 2349 """
2306 Private slot to handle the client certificate selection request. 2350 Private slot to handle the client certificate selection request.
2307 2351
2308 @param clientCertificateSelection list of client SSL certificates 2352 @param clientCertificateSelection list of client SSL certificates
2309 found in system's client certificate store 2353 found in system's client certificate store
2310 @type QWebEngineClientCertificateSelection 2354 @type QWebEngineClientCertificateSelection
2311 """ 2355 """
2312 certificates = clientCertificateSelection.certificates() 2356 certificates = clientCertificateSelection.certificates()
2315 elif len(certificates) == 1: 2359 elif len(certificates) == 1:
2316 clientCertificateSelection.select(certificates[0]) 2360 clientCertificateSelection.select(certificates[0])
2317 else: 2361 else:
2318 certificate = None 2362 certificate = None
2319 from EricNetwork.EricSslCertificateSelectionDialog import ( 2363 from EricNetwork.EricSslCertificateSelectionDialog import (
2320 EricSslCertificateSelectionDialog 2364 EricSslCertificateSelectionDialog,
2321 ) 2365 )
2366
2322 dlg = EricSslCertificateSelectionDialog(certificates, self) 2367 dlg = EricSslCertificateSelectionDialog(certificates, self)
2323 if dlg.exec() == QDialog.DialogCode.Accepted: 2368 if dlg.exec() == QDialog.DialogCode.Accepted:
2324 certificate = dlg.getSelectedCertificate() 2369 certificate = dlg.getSelectedCertificate()
2325 2370
2326 if certificate is None: 2371 if certificate is None:
2327 clientCertificateSelection.selectNone() 2372 clientCertificateSelection.selectNone()
2328 else: 2373 else:
2329 clientCertificateSelection.select(certificate) 2374 clientCertificateSelection.select(certificate)

eric ide

mercurial