src/eric7/HelpViewer/HelpViewerImplQWE.py

branch
eric7
changeset 9221
bf71ee032bb4
parent 9209
b99e7fd55fd3
child 9413
80c06d472826
equal deleted inserted replaced
9220:e9e7eca7efee 9221:bf71ee032bb4
24 24
25 class HelpViewerImplQWE(HelpViewerImpl, QWebEngineView): 25 class HelpViewerImplQWE(HelpViewerImpl, QWebEngineView):
26 """ 26 """
27 Class implementing the QTextBrowser based help viewer class. 27 Class implementing the QTextBrowser based help viewer class.
28 """ 28 """
29
29 ZoomLevels = [ 30 ZoomLevels = [
30 30, 40, 50, 67, 80, 90, 31 30,
32 40,
33 50,
34 67,
35 80,
36 90,
31 100, 37 100,
32 110, 120, 133, 150, 170, 200, 220, 233, 250, 270, 285, 300, 38 110,
39 120,
40 133,
41 150,
42 170,
43 200,
44 220,
45 233,
46 250,
47 270,
48 285,
49 300,
33 ] 50 ]
34 ZoomLevelDefault = 100 51 ZoomLevelDefault = 100
35 52
36 def __init__(self, engine, parent=None): 53 def __init__(self, engine, parent=None):
37 """ 54 """
38 Constructor 55 Constructor
39 56
40 @param engine reference to the help engine 57 @param engine reference to the help engine
41 @type QHelpEngine 58 @type QHelpEngine
42 @param parent reference to the parent widget 59 @param parent reference to the parent widget
43 @type QWidget 60 @type QWidget
44 """ 61 """
45 QWebEngineView.__init__(self, parent=parent) 62 QWebEngineView.__init__(self, parent=parent)
46 HelpViewerImpl.__init__(self, engine) 63 HelpViewerImpl.__init__(self, engine)
47 64
48 self.__helpViewerWidget = parent 65 self.__helpViewerWidget = parent
49 66
50 self.__rwhvqt = None 67 self.__rwhvqt = None
51 self.installEventFilter(self) 68 self.installEventFilter(self)
52 69
53 self.__page = None 70 self.__page = None
54 self.__createNewPage() 71 self.__createNewPage()
55 72
56 self.__currentScale = 100 73 self.__currentScale = 100
57 74
58 self.__menu = QMenu(self) 75 self.__menu = QMenu(self)
59 76
60 def __createNewPage(self): 77 def __createNewPage(self):
61 """ 78 """
62 Private method to create a new page object. 79 Private method to create a new page object.
63 """ 80 """
64 self.__page = QWebEnginePage(self.__helpViewerWidget.webProfile()) 81 self.__page = QWebEnginePage(self.__helpViewerWidget.webProfile())
65 self.setPage(self.__page) 82 self.setPage(self.__page)
66 83
67 self.__page.titleChanged.connect(self.__titleChanged) 84 self.__page.titleChanged.connect(self.__titleChanged)
68 self.__page.urlChanged.connect(self.__titleChanged) 85 self.__page.urlChanged.connect(self.__titleChanged)
69 self.__page.newWindowRequested.connect(self.__newWindowRequested) 86 self.__page.newWindowRequested.connect(self.__newWindowRequested)
70 87
71 def __newWindowRequested(self, request): 88 def __newWindowRequested(self, request):
72 """ 89 """
73 Private slot handling new window requests of the web page. 90 Private slot handling new window requests of the web page.
74 91
75 @param request reference to the new window request 92 @param request reference to the new window request
76 @type QWebEngineNewWindowRequest 93 @type QWebEngineNewWindowRequest
77 """ 94 """
78 background = ( 95 background = (
79 request.destination() == 96 request.destination()
80 QWebEngineNewWindowRequest.DestinationType.InNewBackgroundTab 97 == QWebEngineNewWindowRequest.DestinationType.InNewBackgroundTab
81 ) 98 )
82 newViewer = self.__helpViewerWidget.addPage(background=background) 99 newViewer = self.__helpViewerWidget.addPage(background=background)
83 request.openIn(newViewer.page()) 100 request.openIn(newViewer.page())
84 101
85 def __setRwhvqt(self): 102 def __setRwhvqt(self):
86 """ 103 """
87 Private slot to set widget that receives input events. 104 Private slot to set widget that receives input events.
88 """ 105 """
89 self.grabGesture(Qt.GestureType.PinchGesture) 106 self.grabGesture(Qt.GestureType.PinchGesture)
90 self.__rwhvqt = self.focusProxy() 107 self.__rwhvqt = self.focusProxy()
91 if self.__rwhvqt: 108 if self.__rwhvqt:
92 self.__rwhvqt.grabGesture(Qt.GestureType.PinchGesture) 109 self.__rwhvqt.grabGesture(Qt.GestureType.PinchGesture)
93 self.__rwhvqt.installEventFilter(self) 110 self.__rwhvqt.installEventFilter(self)
94 else: 111 else:
95 print("Focus proxy is null!") # __IGNORE_WARNING_M801__ 112 print("Focus proxy is null!") # __IGNORE_WARNING_M801__
96 113
97 def setLink(self, url): 114 def setLink(self, url):
98 """ 115 """
99 Public method to set the URL of the document to be shown. 116 Public method to set the URL of the document to be shown.
100 117
101 @param url URL of the document 118 @param url URL of the document
102 @type QUrl 119 @type QUrl
103 """ 120 """
104 if url.toString() == "about:blank": 121 if url.toString() == "about:blank":
105 self.setHtml(self.__helpViewerWidget.emptyDocument()) 122 self.setHtml(self.__helpViewerWidget.emptyDocument())
106 else: 123 else:
107 super().setUrl(url) 124 super().setUrl(url)
108 125
109 def link(self): 126 def link(self):
110 """ 127 """
111 Public method to get the URL of the shown document. 128 Public method to get the URL of the shown document.
112 129
113 @return url URL of the document 130 @return url URL of the document
114 @rtype QUrl 131 @rtype QUrl
115 """ 132 """
116 return super().url() 133 return super().url()
117 134
118 @pyqtSlot() 135 @pyqtSlot()
119 def __titleChanged(self): 136 def __titleChanged(self):
120 """ 137 """
121 Private method to handle a change of the web page title. 138 Private method to handle a change of the web page title.
122 """ 139 """
123 super().titleChanged.emit() 140 super().titleChanged.emit()
124 141
125 def pageTitle(self): 142 def pageTitle(self):
126 """ 143 """
127 Public method get the page title. 144 Public method get the page title.
128 145
129 @return page title 146 @return page title
130 @rtype str 147 @rtype str
131 """ 148 """
132 titleStr = super().title() 149 titleStr = super().title()
133 if not titleStr: 150 if not titleStr:
134 if self.link().isEmpty(): 151 if self.link().isEmpty():
135 url = self.__page.requestedUrl() 152 url = self.__page.requestedUrl()
136 else: 153 else:
137 url = self.link() 154 url = self.link()
138 155
139 titleStr = url.host() 156 titleStr = url.host()
140 if not titleStr: 157 if not titleStr:
141 titleStr = url.toString( 158 titleStr = url.toString(QUrl.UrlFormattingOption.RemoveFragment)
142 QUrl.UrlFormattingOption.RemoveFragment) 159
143
144 if not titleStr or titleStr == "about:blank": 160 if not titleStr or titleStr == "about:blank":
145 titleStr = self.tr("Empty Page") 161 titleStr = self.tr("Empty Page")
146 162
147 return titleStr 163 return titleStr
148 164
149 def isEmptyPage(self): 165 def isEmptyPage(self):
150 """ 166 """
151 Public method to check, if the current page is the empty page. 167 Public method to check, if the current page is the empty page.
152 168
153 @return flag indicating an empty page is loaded 169 @return flag indicating an empty page is loaded
154 @rtype bool 170 @rtype bool
155 """ 171 """
156 return self.pageTitle() == self.tr("Empty Page") 172 return self.pageTitle() == self.tr("Empty Page")
157 173
158 ####################################################################### 174 #######################################################################
159 ## History related methods below 175 ## History related methods below
160 ####################################################################### 176 #######################################################################
161 177
162 def isBackwardAvailable(self): 178 def isBackwardAvailable(self):
163 """ 179 """
164 Public method to check, if stepping backward through the history is 180 Public method to check, if stepping backward through the history is
165 available. 181 available.
166 182
167 @return flag indicating backward stepping is available 183 @return flag indicating backward stepping is available
168 @rtype bool 184 @rtype bool
169 """ 185 """
170 return self.history().canGoBack() 186 return self.history().canGoBack()
171 187
172 def isForwardAvailable(self): 188 def isForwardAvailable(self):
173 """ 189 """
174 Public method to check, if stepping forward through the history is 190 Public method to check, if stepping forward through the history is
175 available. 191 available.
176 192
177 @return flag indicating forward stepping is available 193 @return flag indicating forward stepping is available
178 @rtype bool 194 @rtype bool
179 """ 195 """
180 return self.history().canGoForward() 196 return self.history().canGoForward()
181 197
182 def backward(self): 198 def backward(self):
183 """ 199 """
184 Public slot to move backwards in history. 200 Public slot to move backwards in history.
185 """ 201 """
186 self.triggerPageAction(QWebEnginePage.WebAction.Back) 202 self.triggerPageAction(QWebEnginePage.WebAction.Back)
187 203
188 def forward(self): 204 def forward(self):
189 """ 205 """
190 Public slot to move forward in history. 206 Public slot to move forward in history.
191 """ 207 """
192 self.triggerPageAction(QWebEnginePage.WebAction.Forward) 208 self.triggerPageAction(QWebEnginePage.WebAction.Forward)
193 209
194 def reload(self): 210 def reload(self):
195 """ 211 """
196 Public slot to reload the current page. 212 Public slot to reload the current page.
197 """ 213 """
198 self.triggerPageAction(QWebEnginePage.WebAction.Reload) 214 self.triggerPageAction(QWebEnginePage.WebAction.Reload)
199 215
200 def backwardHistoryCount(self): 216 def backwardHistoryCount(self):
201 """ 217 """
202 Public method to get the number of available back history items. 218 Public method to get the number of available back history items.
203 219
204 Note: For performance reasons this is limited to the maximum number of 220 Note: For performance reasons this is limited to the maximum number of
205 history items the help viewer is interested in. 221 history items the help viewer is interested in.
206 222
207 @return count of available back history items 223 @return count of available back history items
208 @rtype int 224 @rtype int
209 """ 225 """
210 history = self.history() 226 history = self.history()
211 return len(history.backItems(HelpViewerWidget.MaxHistoryItems)) 227 return len(history.backItems(HelpViewerWidget.MaxHistoryItems))
212 228
213 def forwardHistoryCount(self): 229 def forwardHistoryCount(self):
214 """ 230 """
215 Public method to get the number of available forward history items. 231 Public method to get the number of available forward history items.
216 232
217 Note: For performance reasons this is limited to the maximum number of 233 Note: For performance reasons this is limited to the maximum number of
218 history items the help viewer is interested in. 234 history items the help viewer is interested in.
219 235
220 @return count of available forward history items 236 @return count of available forward history items
221 @rtype int 237 @rtype int
222 """ 238 """
223 history = self.history() 239 history = self.history()
224 return len(history.forwardItems(HelpViewerWidget.MaxHistoryItems)) 240 return len(history.forwardItems(HelpViewerWidget.MaxHistoryItems))
225 241
226 def historyTitle(self, offset): 242 def historyTitle(self, offset):
227 """ 243 """
228 Public method to get the title of a history item. 244 Public method to get the title of a history item.
229 245
230 @param offset offset of the item with respect to the current page 246 @param offset offset of the item with respect to the current page
231 @type int 247 @type int
232 @return title of the requeted item in history 248 @return title of the requeted item in history
233 @rtype str 249 @rtype str
234 """ 250 """
235 history = self.history() 251 history = self.history()
236 currentIndex = history.currentItemIndex() 252 currentIndex = history.currentItemIndex()
237 itm = self.history().itemAt(currentIndex + offset) 253 itm = self.history().itemAt(currentIndex + offset)
238 return itm.title() 254 return itm.title()
239 255
240 def gotoHistory(self, offset): 256 def gotoHistory(self, offset):
241 """ 257 """
242 Public method to go to a history item. 258 Public method to go to a history item.
243 259
244 @param offset offset of the item with respect to the current page 260 @param offset offset of the item with respect to the current page
245 @type int 261 @type int
246 """ 262 """
247 history = self.history() 263 history = self.history()
248 currentIndex = history.currentItemIndex() 264 currentIndex = history.currentItemIndex()
249 itm = self.history().itemAt(currentIndex + offset) 265 itm = self.history().itemAt(currentIndex + offset)
250 history.goToItem(itm) 266 history.goToItem(itm)
251 267
252 def clearHistory(self): 268 def clearHistory(self):
253 """ 269 """
254 Public method to clear the history. 270 Public method to clear the history.
255 """ 271 """
256 self.history().clear() 272 self.history().clear()
257 273
258 ####################################################################### 274 #######################################################################
259 ## Zoom related methods below 275 ## Zoom related methods below
260 ####################################################################### 276 #######################################################################
261 277
262 def __levelForScale(self, scale): 278 def __levelForScale(self, scale):
263 """ 279 """
264 Private method determining the zoom level index given a zoom factor. 280 Private method determining the zoom level index given a zoom factor.
265 281
266 @param scale zoom factor 282 @param scale zoom factor
267 @type int 283 @type int
268 @return index of zoom factor 284 @return index of zoom factor
269 @rtype int 285 @rtype int
270 """ 286 """
273 except ValueError: 289 except ValueError:
274 for _index in range(len(self.ZoomLevels)): 290 for _index in range(len(self.ZoomLevels)):
275 if scale <= self.ZoomLevels[scale]: 291 if scale <= self.ZoomLevels[scale]:
276 break 292 break
277 return index 293 return index
278 294
279 def scaleUp(self): 295 def scaleUp(self):
280 """ 296 """
281 Public method to zoom in. 297 Public method to zoom in.
282 """ 298 """
283 index = self.__levelForScale(self.__currentScale) 299 index = self.__levelForScale(self.__currentScale)
284 if index < len(self.ZoomLevels) - 1: 300 if index < len(self.ZoomLevels) - 1:
285 self.setScale(self.ZoomLevels[index + 1]) 301 self.setScale(self.ZoomLevels[index + 1])
286 302
287 def scaleDown(self): 303 def scaleDown(self):
288 """ 304 """
289 Public method to zoom out. 305 Public method to zoom out.
290 """ 306 """
291 index = self.__levelForScale(self.__currentScale) 307 index = self.__levelForScale(self.__currentScale)
292 if index > 0: 308 if index > 0:
293 self.setScale(self.ZoomLevels[index - 1]) 309 self.setScale(self.ZoomLevels[index - 1])
294 310
295 def setScale(self, scale): 311 def setScale(self, scale):
296 """ 312 """
297 Public method to set the zoom level. 313 Public method to set the zoom level.
298 314
299 @param scale zoom level to set 315 @param scale zoom level to set
300 @type int 316 @type int
301 """ 317 """
302 if scale != self.__currentScale: 318 if scale != self.__currentScale:
303 self.setZoomFactor(scale / 100.0) 319 self.setZoomFactor(scale / 100.0)
304 self.__currentScale = scale 320 self.__currentScale = scale
305 self.zoomChanged.emit() 321 self.zoomChanged.emit()
306 322
307 def resetScale(self): 323 def resetScale(self):
308 """ 324 """
309 Public method to reset the zoom level. 325 Public method to reset the zoom level.
310 """ 326 """
311 index = self.__levelForScale(self.ZoomLevelDefault) 327 index = self.__levelForScale(self.ZoomLevelDefault)
312 self.setScale(self.ZoomLevels[index]) 328 self.setScale(self.ZoomLevels[index])
313 329
314 def scale(self): 330 def scale(self):
315 """ 331 """
316 Public method to get the zoom level. 332 Public method to get the zoom level.
317 333
318 @return current zoom level 334 @return current zoom level
319 @rtype int 335 @rtype int
320 """ 336 """
321 return self.__currentScale 337 return self.__currentScale
322 338
323 def isScaleUpAvailable(self): 339 def isScaleUpAvailable(self):
324 """ 340 """
325 Public method to check, if the max. zoom level is reached. 341 Public method to check, if the max. zoom level is reached.
326 342
327 @return flag indicating scale up is available 343 @return flag indicating scale up is available
328 @rtype bool 344 @rtype bool
329 """ 345 """
330 index = self.__levelForScale(self.__currentScale) 346 index = self.__levelForScale(self.__currentScale)
331 return index < len(self.ZoomLevels) - 1 347 return index < len(self.ZoomLevels) - 1
332 348
333 def isScaleDownAvailable(self): 349 def isScaleDownAvailable(self):
334 """ 350 """
335 Public method to check, if the min. zoom level is reached. 351 Public method to check, if the min. zoom level is reached.
336 352
337 @return flag indicating scale down is available 353 @return flag indicating scale down is available
338 @rtype bool 354 @rtype bool
339 """ 355 """
340 index = self.__levelForScale(self.__currentScale) 356 index = self.__levelForScale(self.__currentScale)
341 return index > 0 357 return index > 0
342 358
343 ####################################################################### 359 #######################################################################
344 ## Event handlers below 360 ## Event handlers below
345 ####################################################################### 361 #######################################################################
346 362
347 def eventFilter(self, obj, evt): 363 def eventFilter(self, obj, evt):
348 """ 364 """
349 Public method to process event for other objects. 365 Public method to process event for other objects.
350 366
351 @param obj reference to object to process events for 367 @param obj reference to object to process events for
352 @type QObject 368 @type QObject
353 @param evt reference to event to be processed 369 @param evt reference to event to be processed
354 @type QEvent 370 @type QEvent
355 @return flag indicating that the event should be filtered out 371 @return flag indicating that the event should be filtered out
356 @rtype bool 372 @rtype bool
357 """ 373 """
358 if ( 374 if (
359 obj is self and 375 obj is self
360 evt.type() == QEvent.Type.ParentChange and 376 and evt.type() == QEvent.Type.ParentChange
361 self.parentWidget() is not None 377 and self.parentWidget() is not None
362 ): 378 ):
363 self.parentWidget().installEventFilter(self) 379 self.parentWidget().installEventFilter(self)
364 380
365 # find the render widget receiving events for the web page 381 # find the render widget receiving events for the web page
366 if obj is self and evt.type() == QEvent.Type.ChildAdded: 382 if obj is self and evt.type() == QEvent.Type.ChildAdded:
367 QTimer.singleShot(0, self.__setRwhvqt) 383 QTimer.singleShot(0, self.__setRwhvqt)
368 384
369 # forward events to WebBrowserView 385 # forward events to WebBrowserView
370 if ( 386 if obj is self.__rwhvqt and evt.type() in [
371 obj is self.__rwhvqt and 387 QEvent.Type.KeyPress,
372 evt.type() in [QEvent.Type.KeyPress, 388 QEvent.Type.MouseButtonRelease,
373 QEvent.Type.MouseButtonRelease, 389 QEvent.Type.Wheel,
374 QEvent.Type.Wheel, 390 QEvent.Type.Gesture,
375 QEvent.Type.Gesture] 391 ]:
376 ):
377 wasAccepted = evt.isAccepted() 392 wasAccepted = evt.isAccepted()
378 evt.setAccepted(False) 393 evt.setAccepted(False)
379 if evt.type() == QEvent.Type.KeyPress: 394 if evt.type() == QEvent.Type.KeyPress:
380 self._keyPressEvent(evt) 395 self._keyPressEvent(evt)
381 elif evt.type() == QEvent.Type.MouseButtonRelease: 396 elif evt.type() == QEvent.Type.MouseButtonRelease:
385 elif evt.type() == QEvent.Type.Gesture: 400 elif evt.type() == QEvent.Type.Gesture:
386 self._gestureEvent(evt) 401 self._gestureEvent(evt)
387 ret = evt.isAccepted() 402 ret = evt.isAccepted()
388 evt.setAccepted(wasAccepted) 403 evt.setAccepted(wasAccepted)
389 return ret 404 return ret
390 405
391 if ( 406 if obj is self.parentWidget() and evt.type() in [
392 obj is self.parentWidget() and 407 QEvent.Type.KeyPress,
393 evt.type() in [QEvent.Type.KeyPress, QEvent.Type.KeyRelease] 408 QEvent.Type.KeyRelease,
394 ): 409 ]:
395 wasAccepted = evt.isAccepted() 410 wasAccepted = evt.isAccepted()
396 evt.setAccepted(False) 411 evt.setAccepted(False)
397 if evt.type() == QEvent.Type.KeyPress: 412 if evt.type() == QEvent.Type.KeyPress:
398 self._keyPressEvent(evt) 413 self._keyPressEvent(evt)
399 ret = evt.isAccepted() 414 ret = evt.isAccepted()
400 evt.setAccepted(wasAccepted) 415 evt.setAccepted(wasAccepted)
401 return ret 416 return ret
402 417
403 # block already handled events 418 # block already handled events
404 if ( 419 if obj is self and evt.type() in [
405 obj is self and 420 QEvent.Type.KeyPress,
406 evt.type() in [QEvent.Type.KeyPress, 421 QEvent.Type.MouseButtonRelease,
407 QEvent.Type.MouseButtonRelease, 422 QEvent.Type.Wheel,
408 QEvent.Type.Wheel, 423 QEvent.Type.Gesture,
409 QEvent.Type.Gesture] 424 ]:
410 ):
411 return True 425 return True
412 426
413 return super().eventFilter(obj, evt) 427 return super().eventFilter(obj, evt)
414 428
415 def _keyPressEvent(self, evt): 429 def _keyPressEvent(self, evt):
416 """ 430 """
417 Protected method called by a key press. 431 Protected method called by a key press.
418 432
419 @param evt reference to the key event 433 @param evt reference to the key event
420 @type QKeyEvent 434 @type QKeyEvent
421 """ 435 """
422 key = evt.key() 436 key = evt.key()
423 isControlModifier = ( 437 isControlModifier = evt.modifiers() == Qt.KeyboardModifier.ControlModifier
424 evt.modifiers() == Qt.KeyboardModifier.ControlModifier 438
425 ) 439 if key == Qt.Key.Key_ZoomIn or (key == Qt.Key.Key_Plus and isControlModifier):
426
427 if (
428 key == Qt.Key.Key_ZoomIn or
429 (key == Qt.Key.Key_Plus and isControlModifier)
430 ):
431 self.scaleUp() 440 self.scaleUp()
432 evt.accept() 441 evt.accept()
433 elif ( 442 elif key == Qt.Key.Key_ZoomOut or (
434 key == Qt.Key.Key_ZoomOut or 443 key == Qt.Key.Key_Minus and isControlModifier
435 (key == Qt.Key.Key_Minus and isControlModifier)
436 ): 444 ):
437 self.scaleDown() 445 self.scaleDown()
438 evt.accept() 446 evt.accept()
439 elif key == Qt.Key.Key_0 and isControlModifier: 447 elif key == Qt.Key.Key_0 and isControlModifier:
440 self.resetScale() 448 self.resetScale()
441 evt.accept() 449 evt.accept()
442 elif ( 450 elif key == Qt.Key.Key_Backspace or (
443 key == Qt.Key.Key_Backspace or 451 key == Qt.Key.Key_Left and isControlModifier
444 (key == Qt.Key.Key_Left and isControlModifier)
445 ): 452 ):
446 self.backward() 453 self.backward()
447 evt.accept() 454 evt.accept()
448 elif key == Qt.Key.Key_Right and isControlModifier: 455 elif key == Qt.Key.Key_Right and isControlModifier:
449 self.forward() 456 self.forward()
450 evt.accept() 457 evt.accept()
451 elif key == Qt.Key.Key_F and isControlModifier: 458 elif key == Qt.Key.Key_F and isControlModifier:
452 self.__helpViewerWidget.showHideSearch(True) 459 self.__helpViewerWidget.showHideSearch(True)
453 evt.accept() 460 evt.accept()
461 elif key == Qt.Key.Key_F3 and evt.modifiers() == Qt.KeyboardModifier.NoModifier:
462 self.__helpViewerWidget.searchNext()
463 evt.accept()
454 elif ( 464 elif (
455 key == Qt.Key.Key_F3 and 465 key == Qt.Key.Key_F3
456 evt.modifiers() == Qt.KeyboardModifier.NoModifier 466 and evt.modifiers() == Qt.KeyboardModifier.ShiftModifier
457 ):
458 self.__helpViewerWidget.searchNext()
459 evt.accept()
460 elif (
461 key == Qt.Key.Key_F3 and
462 evt.modifiers() == Qt.KeyboardModifier.ShiftModifier
463 ): 467 ):
464 self.__helpViewerWidget.searchPrev() 468 self.__helpViewerWidget.searchPrev()
465 evt.accept() 469 evt.accept()
466 470
467 def _mouseReleaseEvent(self, evt): 471 def _mouseReleaseEvent(self, evt):
468 """ 472 """
469 Protected method called by a mouse release event. 473 Protected method called by a mouse release event.
470 474
471 @param evt reference to the mouse event 475 @param evt reference to the mouse event
472 @type QMouseEvent 476 @type QMouseEvent
473 """ 477 """
474 accepted = evt.isAccepted() 478 accepted = evt.isAccepted()
475 self.__page.event(evt) 479 self.__page.event(evt)
476 if ( 480 if not evt.isAccepted() and evt.button() == Qt.MouseButton.MiddleButton:
477 not evt.isAccepted() and 481 url = QUrl(QGuiApplication.clipboard().text(QClipboard.Mode.Selection))
478 evt.button() == Qt.MouseButton.MiddleButton 482 if not url.isEmpty() and url.isValid() and url.scheme() != "":
479 ):
480 url = QUrl(QGuiApplication.clipboard().text(
481 QClipboard.Mode.Selection))
482 if (
483 not url.isEmpty() and
484 url.isValid() and
485 url.scheme() != ""
486 ):
487 self.setLink(url) 483 self.setLink(url)
488 accepted = True 484 accepted = True
489 evt.setAccepted(accepted) 485 evt.setAccepted(accepted)
490 486
491 def _wheelEvent(self, evt): 487 def _wheelEvent(self, evt):
492 """ 488 """
493 Protected method to handle wheel events. 489 Protected method to handle wheel events.
494 490
495 @param evt reference to the wheel event 491 @param evt reference to the wheel event
496 @type QWheelEvent 492 @type QWheelEvent
497 """ 493 """
498 delta = evt.angleDelta().y() 494 delta = evt.angleDelta().y()
499 if evt.modifiers() & Qt.KeyboardModifier.ControlModifier: 495 if evt.modifiers() & Qt.KeyboardModifier.ControlModifier:
500 if delta < 0: 496 if delta < 0:
501 self.scaleDown() 497 self.scaleDown()
502 elif delta > 0: 498 elif delta > 0:
503 self.scaleUp() 499 self.scaleUp()
504 evt.accept() 500 evt.accept()
505 501
506 elif evt.modifiers() & Qt.KeyboardModifier.ShiftModifier: 502 elif evt.modifiers() & Qt.KeyboardModifier.ShiftModifier:
507 if delta < 0: 503 if delta < 0:
508 self.backward() 504 self.backward()
509 elif delta > 0: 505 elif delta > 0:
510 self.forward() 506 self.forward()
511 evt.accept() 507 evt.accept()
512 508
513 def _gestureEvent(self, evt): 509 def _gestureEvent(self, evt):
514 """ 510 """
515 Protected method handling gesture events. 511 Protected method handling gesture events.
516 512
517 @param evt reference to the gesture event 513 @param evt reference to the gesture event
518 @type QGestureEvent 514 @type QGestureEvent
519 """ 515 """
520 pinch = evt.gesture(Qt.GestureType.PinchGesture) 516 pinch = evt.gesture(Qt.GestureType.PinchGesture)
521 if pinch: 517 if pinch:
523 pinch.setTotalScaleFactor(self.__currentScale / 100.0) 519 pinch.setTotalScaleFactor(self.__currentScale / 100.0)
524 elif pinch.state() == Qt.GestureState.GestureUpdated: 520 elif pinch.state() == Qt.GestureState.GestureUpdated:
525 scaleFactor = pinch.totalScaleFactor() 521 scaleFactor = pinch.totalScaleFactor()
526 self.setScale(int(scaleFactor * 100)) 522 self.setScale(int(scaleFactor * 100))
527 evt.accept() 523 evt.accept()
528 524
529 def event(self, evt): 525 def event(self, evt):
530 """ 526 """
531 Public method handling events. 527 Public method handling events.
532 528
533 @param evt reference to the event (QEvent) 529 @param evt reference to the event (QEvent)
534 @return flag indicating, if the event was handled (boolean) 530 @return flag indicating, if the event was handled (boolean)
535 """ 531 """
536 if evt.type() == QEvent.Type.Gesture: 532 if evt.type() == QEvent.Type.Gesture:
537 self._gestureEvent(evt) 533 self._gestureEvent(evt)
538 return True 534 return True
539 535
540 return super().event(evt) 536 return super().event(evt)
541 537
542 ####################################################################### 538 #######################################################################
543 ## Context menu related methods below 539 ## Context menu related methods below
544 ####################################################################### 540 #######################################################################
545 541
546 def contextMenuEvent(self, evt): 542 def contextMenuEvent(self, evt):
547 """ 543 """
548 Protected method called to create a context menu. 544 Protected method called to create a context menu.
549 545
550 This method is overridden from QWebEngineView. 546 This method is overridden from QWebEngineView.
551 547
552 @param evt reference to the context menu event object 548 @param evt reference to the context menu event object
553 @type QContextMenuEvent 549 @type QContextMenuEvent
554 """ 550 """
555 pos = evt.pos() 551 pos = evt.pos()
556 reason = evt.reason() 552 reason = evt.reason()
557 QTimer.singleShot( 553 QTimer.singleShot(
558 0, 554 0, lambda: self._contextMenuEvent(QContextMenuEvent(reason, pos))
559 lambda: self._contextMenuEvent(QContextMenuEvent(reason, pos))) 555 )
560 # needs to be done this way because contextMenuEvent is blocking 556 # needs to be done this way because contextMenuEvent is blocking
561 # the main loop 557 # the main loop
562 558
563 def _contextMenuEvent(self, evt): 559 def _contextMenuEvent(self, evt):
564 """ 560 """
565 Protected method called to create a context menu. 561 Protected method called to create a context menu.
566 562
567 @param evt reference to the context menu event object 563 @param evt reference to the context menu event object
568 (QContextMenuEvent) 564 (QContextMenuEvent)
569 """ 565 """
570 self.__menu.clear() 566 self.__menu.clear()
571 567
572 self.__createContextMenu(self.__menu) 568 self.__createContextMenu(self.__menu)
573 569
574 if not self.__menu.isEmpty(): 570 if not self.__menu.isEmpty():
575 pos = evt.globalPos() 571 pos = evt.globalPos()
576 self.__menu.popup(QPoint(pos.x(), pos.y() + 1)) 572 self.__menu.popup(QPoint(pos.x(), pos.y() + 1))
577 573
578 def __createContextMenu(self, menu): 574 def __createContextMenu(self, menu):
579 """ 575 """
580 Private method to populate the context menu. 576 Private method to populate the context menu.
581 577
582 @param menu reference to the menu to be populated 578 @param menu reference to the menu to be populated
583 @type QMenu 579 @type QMenu
584 """ 580 """
585 contextMenuData = self.lastContextMenuRequest() 581 contextMenuData = self.lastContextMenuRequest()
586 582
587 act = menu.addAction( 583 act = menu.addAction(
588 UI.PixmapCache.getIcon("back"), 584 UI.PixmapCache.getIcon("back"), self.tr("Backward"), self.backward
589 self.tr("Backward"), 585 )
590 self.backward)
591 act.setEnabled(self.isBackwardAvailable()) 586 act.setEnabled(self.isBackwardAvailable())
592 587
593 act = menu.addAction( 588 act = menu.addAction(
594 UI.PixmapCache.getIcon("forward"), 589 UI.PixmapCache.getIcon("forward"), self.tr("Forward"), self.forward
595 self.tr("Forward"), 590 )
596 self.forward)
597 act.setEnabled(self.isForwardAvailable()) 591 act.setEnabled(self.isForwardAvailable())
598 592
599 act = menu.addAction( 593 act = menu.addAction(
600 UI.PixmapCache.getIcon("reload"), 594 UI.PixmapCache.getIcon("reload"), self.tr("Reload"), self.reload
601 self.tr("Reload"), 595 )
602 self.reload) 596
603
604 if ( 597 if (
605 not contextMenuData.linkUrl().isEmpty() and 598 not contextMenuData.linkUrl().isEmpty()
606 contextMenuData.linkUrl().scheme() != "javascript" 599 and contextMenuData.linkUrl().scheme() != "javascript"
607 ): 600 ):
608 self.__createLinkContextMenu(menu, contextMenuData) 601 self.__createLinkContextMenu(menu, contextMenuData)
609 602
610 menu.addSeparator() 603 menu.addSeparator()
611 604
612 act = menu.addAction( 605 act = menu.addAction(
613 UI.PixmapCache.getIcon("editCopy"), 606 UI.PixmapCache.getIcon("editCopy"), self.tr("Copy Page URL to Clipboard")
614 self.tr("Copy Page URL to Clipboard")) 607 )
615 act.setData(self.link()) 608 act.setData(self.link())
616 act.triggered.connect( 609 act.triggered.connect(functools.partial(self.__copyLink, act))
617 functools.partial(self.__copyLink, act)) 610
618 611 act = menu.addAction(
619 act = menu.addAction( 612 UI.PixmapCache.getIcon("bookmark22"), self.tr("Bookmark Page")
620 UI.PixmapCache.getIcon("bookmark22"), 613 )
621 self.tr("Bookmark Page")) 614 act.setData({"title": self.pageTitle(), "url": self.link()})
622 act.setData({ 615 act.triggered.connect(functools.partial(self.__bookmarkPage, act))
623 "title": self.pageTitle(), 616
624 "url": self.link()
625 })
626 act.triggered.connect(
627 functools.partial(self.__bookmarkPage, act))
628
629 menu.addSeparator() 617 menu.addSeparator()
630 618
631 act = menu.addAction( 619 act = menu.addAction(
632 UI.PixmapCache.getIcon("zoomIn"), 620 UI.PixmapCache.getIcon("zoomIn"), self.tr("Zoom in"), self.scaleUp
633 self.tr("Zoom in"), 621 )
634 self.scaleUp)
635 act.setEnabled(self.isScaleUpAvailable()) 622 act.setEnabled(self.isScaleUpAvailable())
636 623
637 act = menu.addAction( 624 act = menu.addAction(
638 UI.PixmapCache.getIcon("zoomOut"), 625 UI.PixmapCache.getIcon("zoomOut"), self.tr("Zoom out"), self.scaleDown
639 self.tr("Zoom out"), 626 )
640 self.scaleDown)
641 act.setEnabled(self.isScaleDownAvailable()) 627 act.setEnabled(self.isScaleDownAvailable())
642 628
643 menu.addAction( 629 menu.addAction(
644 UI.PixmapCache.getIcon("zoomReset"), 630 UI.PixmapCache.getIcon("zoomReset"), self.tr("Zoom reset"), self.resetScale
645 self.tr("Zoom reset"), 631 )
646 self.resetScale) 632
647
648 menu.addSeparator() 633 menu.addSeparator()
649 634
650 act = menu.addAction( 635 act = menu.addAction(
651 UI.PixmapCache.getIcon("editCopy"), 636 UI.PixmapCache.getIcon("editCopy"), self.tr("Copy"), self.__copyText
652 self.tr("Copy"), 637 )
653 self.__copyText)
654 act.setEnabled(bool(contextMenuData.selectedText())) 638 act.setEnabled(bool(contextMenuData.selectedText()))
655 639
656 menu.addAction( 640 menu.addAction(
657 UI.PixmapCache.getIcon("editSelectAll"), 641 UI.PixmapCache.getIcon("editSelectAll"),
658 self.tr("Select All"), 642 self.tr("Select All"),
659 self.__selectAll) 643 self.__selectAll,
660 644 )
645
661 menu.addSeparator() 646 menu.addSeparator()
662 647
663 menu.addAction( 648 menu.addAction(
664 UI.PixmapCache.getIcon("tabClose"), 649 UI.PixmapCache.getIcon("tabClose"), self.tr("Close"), self.__closePage
665 self.tr('Close'), 650 )
666 self.__closePage) 651
667
668 act = menu.addAction( 652 act = menu.addAction(
669 UI.PixmapCache.getIcon("tabCloseOther"), 653 UI.PixmapCache.getIcon("tabCloseOther"),
670 self.tr("Close Others"), 654 self.tr("Close Others"),
671 self.__closeOtherPages) 655 self.__closeOtherPages,
656 )
672 act.setEnabled(self.__helpViewerWidget.openPagesCount() > 1) 657 act.setEnabled(self.__helpViewerWidget.openPagesCount() > 1)
673 658
674 def __createLinkContextMenu(self, menu, contextMenuData): 659 def __createLinkContextMenu(self, menu, contextMenuData):
675 """ 660 """
676 Private method to populate the context menu for URLs. 661 Private method to populate the context menu for URLs.
677 662
678 @param menu reference to the menu to be populated 663 @param menu reference to the menu to be populated
679 @type QMenu 664 @type QMenu
680 @param contextMenuData data of the last context menu request 665 @param contextMenuData data of the last context menu request
681 @type QWebEngineContextMenuRequest 666 @type QWebEngineContextMenuRequest
682 """ 667 """
683 if not menu.isEmpty(): 668 if not menu.isEmpty():
684 menu.addSeparator() 669 menu.addSeparator()
685 670
686 act = menu.addAction( 671 act = menu.addAction(
687 UI.PixmapCache.getIcon("openNewTab"), 672 UI.PixmapCache.getIcon("openNewTab"), self.tr("Open Link in New Page")
688 self.tr("Open Link in New Page")) 673 )
689 act.setData(contextMenuData.linkUrl()) 674 act.setData(contextMenuData.linkUrl())
690 act.triggered.connect( 675 act.triggered.connect(functools.partial(self.__openLinkInNewPage, act))
691 functools.partial(self.__openLinkInNewPage, act)) 676
692 677 act = menu.addAction(
693 act = menu.addAction( 678 UI.PixmapCache.getIcon("newWindow"), self.tr("Open Link in Background Page")
694 UI.PixmapCache.getIcon("newWindow"), 679 )
695 self.tr("Open Link in Background Page"))
696 act.setData(contextMenuData.linkUrl()) 680 act.setData(contextMenuData.linkUrl())
697 act.triggered.connect( 681 act.triggered.connect(functools.partial(self.__openLinkInBackgroundPage, act))
698 functools.partial(self.__openLinkInBackgroundPage, act)) 682
699
700 menu.addSeparator() 683 menu.addSeparator()
701 684
702 act = menu.addAction( 685 act = menu.addAction(
703 UI.PixmapCache.getIcon("editCopy"), 686 UI.PixmapCache.getIcon("editCopy"), self.tr("Copy URL to Clipboard")
704 self.tr("Copy URL to Clipboard")) 687 )
705 act.setData(contextMenuData.linkUrl()) 688 act.setData(contextMenuData.linkUrl())
706 act.triggered.connect( 689 act.triggered.connect(functools.partial(self.__copyLink, act))
707 functools.partial(self.__copyLink, act)) 690
708
709 def __openLinkInNewPage(self, act): 691 def __openLinkInNewPage(self, act):
710 """ 692 """
711 Private method called by the context menu to open a link in a new page. 693 Private method called by the context menu to open a link in a new page.
712 694
713 @param act reference to the action that triggered 695 @param act reference to the action that triggered
714 @type QAction 696 @type QAction
715 """ 697 """
716 url = act.data() 698 url = act.data()
717 if url.isEmpty(): 699 if url.isEmpty():
718 return 700 return
719 701
720 self.__helpViewerWidget.openUrlNewPage(url) 702 self.__helpViewerWidget.openUrlNewPage(url)
721 703
722 def __openLinkInBackgroundPage(self, act): 704 def __openLinkInBackgroundPage(self, act):
723 """ 705 """
724 Private method called by the context menu to open a link in a 706 Private method called by the context menu to open a link in a
725 background page. 707 background page.
726 708
727 @param act reference to the action that triggered 709 @param act reference to the action that triggered
728 @type QAction 710 @type QAction
729 """ 711 """
730 url = act.data() 712 url = act.data()
731 if url.isEmpty(): 713 if url.isEmpty():
732 return 714 return
733 715
734 self.__helpViewerWidget.openUrlNewBackgroundPage(url) 716 self.__helpViewerWidget.openUrlNewBackgroundPage(url)
735 717
736 def __bookmarkPage(self, act): 718 def __bookmarkPage(self, act):
737 """ 719 """
738 Private method called by the context menu to bookmark the page. 720 Private method called by the context menu to bookmark the page.
739 721
740 @param act reference to the action that triggered 722 @param act reference to the action that triggered
741 @type QAction 723 @type QAction
742 """ 724 """
743 data = act.data() 725 data = act.data()
744 if data: 726 if data:
745 with contextlib.suppress(KeyError): 727 with contextlib.suppress(KeyError):
746 url = data["url"] 728 url = data["url"]
747 title = data["title"] 729 title = data["title"]
748 730
749 self.__helpViewerWidget.bookmarkPage(title, url) 731 self.__helpViewerWidget.bookmarkPage(title, url)
750 732
751 def __copyLink(self, act): 733 def __copyLink(self, act):
752 """ 734 """
753 Private method called by the context menu to copy a link to the 735 Private method called by the context menu to copy a link to the
754 clipboard. 736 clipboard.
755 737
756 @param act reference to the action that triggered 738 @param act reference to the action that triggered
757 @type QAction 739 @type QAction
758 """ 740 """
759 data = act.data() 741 data = act.data()
760 if isinstance(data, QUrl) and data.isEmpty(): 742 if isinstance(data, QUrl) and data.isEmpty():
761 return 743 return
762 744
763 if isinstance(data, QUrl): 745 if isinstance(data, QUrl):
764 data = data.toString() 746 data = data.toString()
765 747
766 # copy the URL to both clipboard areas 748 # copy the URL to both clipboard areas
767 QGuiApplication.clipboard().setText(data, QClipboard.Mode.Clipboard) 749 QGuiApplication.clipboard().setText(data, QClipboard.Mode.Clipboard)
768 QGuiApplication.clipboard().setText(data, QClipboard.Mode.Selection) 750 QGuiApplication.clipboard().setText(data, QClipboard.Mode.Selection)
769 751
770 def __copyText(self): 752 def __copyText(self):
771 """ 753 """
772 Private method called by the context menu to copy selected text to the 754 Private method called by the context menu to copy selected text to the
773 clipboard. 755 clipboard.
774 """ 756 """
775 self.triggerPageAction(QWebEnginePage.WebAction.Copy) 757 self.triggerPageAction(QWebEnginePage.WebAction.Copy)
776 758
777 def __selectAll(self): 759 def __selectAll(self):
778 """ 760 """
779 Private method called by the context menu to select all text. 761 Private method called by the context menu to select all text.
780 """ 762 """
781 self.triggerPageAction(QWebEnginePage.WebAction.SelectAll) 763 self.triggerPageAction(QWebEnginePage.WebAction.SelectAll)
782 764
783 def __closePage(self): 765 def __closePage(self):
784 """ 766 """
785 Private method called by the context menu to close the current page. 767 Private method called by the context menu to close the current page.
786 """ 768 """
787 self.__helpViewerWidget.closeCurrentPage() 769 self.__helpViewerWidget.closeCurrentPage()
788 770
789 def __closeOtherPages(self): 771 def __closeOtherPages(self):
790 """ 772 """
791 Private method called by the context menu to close all other pages. 773 Private method called by the context menu to close all other pages.
792 """ 774 """
793 self.__helpViewerWidget.closeOtherPages() 775 self.__helpViewerWidget.closeOtherPages()

eric ide

mercurial