src/eric7/HelpViewer/HelpViewerImplQTB.py

branch
eric7
changeset 9221
bf71ee032bb4
parent 9209
b99e7fd55fd3
child 9413
80c06d472826
equal deleted inserted replaced
9220:e9e7eca7efee 9221:bf71ee032bb4
9 9
10 import contextlib 10 import contextlib
11 import functools 11 import functools
12 12
13 from PyQt6.QtCore import ( 13 from PyQt6.QtCore import (
14 pyqtSlot, Qt, QByteArray, QUrl, QEvent, QCoreApplication, QPoint 14 pyqtSlot,
15 Qt,
16 QByteArray,
17 QUrl,
18 QEvent,
19 QCoreApplication,
20 QPoint,
15 ) 21 )
16 from PyQt6.QtGui import QDesktopServices, QImage, QGuiApplication, QClipboard 22 from PyQt6.QtGui import QDesktopServices, QImage, QGuiApplication, QClipboard
17 from PyQt6.QtWidgets import QTextBrowser, QMenu 23 from PyQt6.QtWidgets import QTextBrowser, QMenu
18 24
19 from .HelpViewerImpl import HelpViewerImpl 25 from .HelpViewerImpl import HelpViewerImpl
21 import UI.PixmapCache 27 import UI.PixmapCache
22 28
23 29
24 AboutBlank = QCoreApplication.translate( 30 AboutBlank = QCoreApplication.translate(
25 "HelpViewer", 31 "HelpViewer",
26 "<html>" 32 "<html>" "<head><title>about:blank</title></head>" "<body></body>" "</html>",
27 "<head><title>about:blank</title></head>" 33 )
28 "<body></body>"
29 "</html>")
30 34
31 PageNotFound = QCoreApplication.translate( 35 PageNotFound = QCoreApplication.translate(
32 "HelpViewer", 36 "HelpViewer",
33 """<html>""" 37 """<html>"""
34 """<head><title>Error 404...</title></head>""" 38 """<head><title>Error 404...</title></head>"""
35 """<body><div align="center"><br><br>""" 39 """<body><div align="center"><br><br>"""
36 """<h1>The page could not be found</h1><br>""" 40 """<h1>The page could not be found</h1><br>"""
37 """<h3>'{0}'</h3></div></body>""" 41 """<h3>'{0}'</h3></div></body>"""
38 """</html>""") 42 """</html>""",
43 )
39 44
40 45
41 class HelpViewerImplQTB(HelpViewerImpl, QTextBrowser): 46 class HelpViewerImplQTB(HelpViewerImpl, QTextBrowser):
42 """ 47 """
43 Class implementing the QTextBrowser based help viewer class. 48 Class implementing the QTextBrowser based help viewer class.
44 """ 49 """
50
45 def __init__(self, engine, parent=None): 51 def __init__(self, engine, parent=None):
46 """ 52 """
47 Constructor 53 Constructor
48 54
49 @param engine reference to the help engine 55 @param engine reference to the help engine
50 @type QHelpEngine 56 @type QHelpEngine
51 @param parent reference to the parent widget 57 @param parent reference to the parent widget
52 @type QWidget 58 @type QWidget
53 """ 59 """
54 QTextBrowser.__init__(self, parent=parent) 60 QTextBrowser.__init__(self, parent=parent)
55 HelpViewerImpl.__init__(self, engine) 61 HelpViewerImpl.__init__(self, engine)
56 62
57 self.__helpViewerWidget = parent 63 self.__helpViewerWidget = parent
58 64
59 self.__zoomCount = 0 65 self.__zoomCount = 0
60 66
61 self.__menu = QMenu(self) 67 self.__menu = QMenu(self)
62 self.setContextMenuPolicy(Qt.ContextMenuPolicy.CustomContextMenu) 68 self.setContextMenuPolicy(Qt.ContextMenuPolicy.CustomContextMenu)
63 self.customContextMenuRequested.connect(self.__showContextMenu) 69 self.customContextMenuRequested.connect(self.__showContextMenu)
64 70
65 self.sourceChanged.connect(self.titleChanged) 71 self.sourceChanged.connect(self.titleChanged)
66 72
67 self.grabGesture(Qt.GestureType.PinchGesture) 73 self.grabGesture(Qt.GestureType.PinchGesture)
68 74
69 def setLink(self, url): 75 def setLink(self, url):
70 """ 76 """
71 Public method to set the URL of the document to be shown. 77 Public method to set the URL of the document to be shown.
72 78
73 @param url source of the document 79 @param url source of the document
74 @type QUrl 80 @type QUrl
75 """ 81 """
76 if url.toString() == "about:blank": 82 if url.toString() == "about:blank":
77 self.setHtml(self.__helpViewerWidget.emptyDocument()) 83 self.setHtml(self.__helpViewerWidget.emptyDocument())
78 else: 84 else:
79 self.setSource(url) 85 self.setSource(url)
80 86
81 def link(self): 87 def link(self):
82 """ 88 """
83 Public method to get the URL of the shown document. 89 Public method to get the URL of the shown document.
84 90
85 @return URL of the document 91 @return URL of the document
86 @rtype QUrl 92 @rtype QUrl
87 """ 93 """
88 return self.source() 94 return self.source()
89 95
90 def doSetSource(self, url, type_): 96 def doSetSource(self, url, type_):
91 """ 97 """
92 Public method to load the data and show it. 98 Public method to load the data and show it.
93 99
94 @param url URL of resource to load 100 @param url URL of resource to load
95 @type QUrl 101 @type QUrl
96 @param type_ type of the resource to load 102 @param type_ type of the resource to load
97 @type QTextDocument.ResourceType 103 @type QTextDocument.ResourceType
98 """ 104 """
99 if not self.__canLoadResource(url): 105 if not self.__canLoadResource(url):
100 QDesktopServices.openUrl(url) 106 QDesktopServices.openUrl(url)
101 return 107 return
102 108
103 super().doSetSource(url, type_) 109 super().doSetSource(url, type_)
104 110
105 self.sourceChanged.emit(url) 111 self.sourceChanged.emit(url)
106 self.loadFinished.emit(True) 112 self.loadFinished.emit(True)
107 113
108 def loadResource(self, type_, name): 114 def loadResource(self, type_, name):
109 """ 115 """
110 Public method to load data of the specified type from the resource with 116 Public method to load data of the specified type from the resource with
111 the given name. 117 the given name.
112 118
113 @param type_ resource type 119 @param type_ resource type
114 @type int 120 @type int
115 @param name resource name 121 @param name resource name
116 @type QUrl 122 @type QUrl
117 @return byte array containing the loaded data 123 @return byte array containing the loaded data
118 @rtype QByteArray 124 @rtype QByteArray
119 """ 125 """
120 ba = QByteArray() 126 ba = QByteArray()
121 scheme = name.scheme() 127 scheme = name.scheme()
122 128
123 if type_ < 4: # QTextDocument.ResourceType.MarkdownResource 129 if type_ < 4: # QTextDocument.ResourceType.MarkdownResource
124 if scheme == "about": 130 if scheme == "about":
125 if name.toString() == "about:blank": 131 if name.toString() == "about:blank":
126 return QByteArray(AboutBlank.encode("utf-8")) 132 return QByteArray(AboutBlank.encode("utf-8"))
127 elif scheme in ("file", ""): 133 elif scheme in ("file", ""):
128 filePath = name.toLocalFile() 134 filePath = name.toLocalFile()
130 ba = QByteArray(f.read()) 136 ba = QByteArray(f.read())
131 elif scheme == "qthelp": 137 elif scheme == "qthelp":
132 url = self._engine.findFile(name) 138 url = self._engine.findFile(name)
133 if url.isValid(): 139 if url.isValid():
134 ba = self._engine.fileData(url) 140 ba = self._engine.fileData(url)
135 141
136 if name.toString().lower().endswith(".svg"): 142 if name.toString().lower().endswith(".svg"):
137 image = QImage() 143 image = QImage()
138 image.loadFromData(ba, "svg") 144 image.loadFromData(ba, "svg")
139 if not image.isNull(): 145 if not image.isNull():
140 return image 146 return image
141 147
142 if ba.isEmpty(): 148 if ba.isEmpty():
143 ba = QByteArray( 149 ba = QByteArray(PageNotFound.format(name.toString()).encode("utf-8"))
144 PageNotFound.format(name.toString()).encode("utf-8") 150
145 )
146
147 return ba 151 return ba
148 152
149 def __canLoadResource(self, url): 153 def __canLoadResource(self, url):
150 """ 154 """
151 Private method to check, if the given resource can be loaded. 155 Private method to check, if the given resource can be loaded.
152 156
153 @param url URL of resource to be loaded 157 @param url URL of resource to be loaded
154 @type QUrl 158 @type QUrl
155 @return flag indicating, that the given URL can be handled 159 @return flag indicating, that the given URL can be handled
156 @rtype bool 160 @rtype bool
157 """ 161 """
158 scheme = url.scheme() 162 scheme = url.scheme()
159 return scheme in ("about", "qthelp", "file", "") 163 return scheme in ("about", "qthelp", "file", "")
160 164
161 def pageTitle(self): 165 def pageTitle(self):
162 """ 166 """
163 Public method get the page title. 167 Public method get the page title.
164 168
165 @return page title 169 @return page title
166 @rtype str 170 @rtype str
167 """ 171 """
168 titleStr = self.documentTitle() 172 titleStr = self.documentTitle()
169 if not titleStr: 173 if not titleStr:
170 url = self.link() 174 url = self.link()
171 175
172 titleStr = url.host() 176 titleStr = url.host()
173 if not titleStr: 177 if not titleStr:
174 titleStr = url.toString( 178 titleStr = url.toString(QUrl.UrlFormattingOption.RemoveFragment)
175 QUrl.UrlFormattingOption.RemoveFragment) 179
176
177 if not titleStr or titleStr == "about:blank": 180 if not titleStr or titleStr == "about:blank":
178 titleStr = self.tr("Empty Page") 181 titleStr = self.tr("Empty Page")
179 182
180 return titleStr 183 return titleStr
181 184
182 def isEmptyPage(self): 185 def isEmptyPage(self):
183 """ 186 """
184 Public method to check, if the current page is the empty page. 187 Public method to check, if the current page is the empty page.
185 188
186 @return flag indicating an empty page is loaded 189 @return flag indicating an empty page is loaded
187 @rtype bool 190 @rtype bool
188 """ 191 """
189 return self.pageTitle() == self.tr("Empty Page") 192 return self.pageTitle() == self.tr("Empty Page")
190 193
191 def mousePressEvent(self, evt): 194 def mousePressEvent(self, evt):
192 """ 195 """
193 Protected method called by a mouse press event. 196 Protected method called by a mouse press event.
194 197
195 @param evt reference to the mouse event 198 @param evt reference to the mouse event
196 @type QMouseEvent 199 @type QMouseEvent
197 """ 200 """
198 if evt.button() == Qt.MouseButton.XButton1: 201 if evt.button() == Qt.MouseButton.XButton1:
199 self.backward() 202 self.backward()
201 elif evt.button() == Qt.MouseButton.XButton2: 204 elif evt.button() == Qt.MouseButton.XButton2:
202 self.forward() 205 self.forward()
203 evt.accept() 206 evt.accept()
204 else: 207 else:
205 super().mousePressEvent(evt) 208 super().mousePressEvent(evt)
206 209
207 def mouseReleaseEvent(self, evt): 210 def mouseReleaseEvent(self, evt):
208 """ 211 """
209 Protected method called by a mouse release event. 212 Protected method called by a mouse release event.
210 213
211 @param evt reference to the mouse event 214 @param evt reference to the mouse event
212 @type QMouseEvent 215 @type QMouseEvent
213 """ 216 """
214 hasModifier = evt.modifiers() != Qt.KeyboardModifier.NoModifier 217 hasModifier = evt.modifiers() != Qt.KeyboardModifier.NoModifier
215 if evt.button() == Qt.MouseButton.LeftButton and hasModifier: 218 if evt.button() == Qt.MouseButton.LeftButton and hasModifier:
216 219
217 anchor = self.anchorAt(evt.pos()) 220 anchor = self.anchorAt(evt.pos())
218 if anchor: 221 if anchor:
219 url = self.link().resolved(QUrl(anchor)) 222 url = self.link().resolved(QUrl(anchor))
220 if evt.modifiers() & Qt.KeyboardModifier.ControlModifier: 223 if evt.modifiers() & Qt.KeyboardModifier.ControlModifier:
221 self.__helpViewerWidget.openUrlNewBackgroundPage(url) 224 self.__helpViewerWidget.openUrlNewBackgroundPage(url)
222 else: 225 else:
223 self.__helpViewerWidget.openUrlNewPage(url) 226 self.__helpViewerWidget.openUrlNewPage(url)
224 evt.accept() 227 evt.accept()
225 else: 228 else:
226 super().mousePressEvent(evt) 229 super().mousePressEvent(evt)
227 230
228 def gotoHistory(self, index): 231 def gotoHistory(self, index):
229 """ 232 """
230 Public method to step through the history. 233 Public method to step through the history.
231 234
232 @param index history index (<0 backward, >0 forward) 235 @param index history index (<0 backward, >0 forward)
233 @type int 236 @type int
234 """ 237 """
235 if index < 0: 238 if index < 0:
236 # backward 239 # backward
238 self.backward() 241 self.backward()
239 else: 242 else:
240 # forward 243 # forward
241 for _ind in range(index): 244 for _ind in range(index):
242 self.forward() 245 self.forward()
243 246
244 def isBackwardAvailable(self): 247 def isBackwardAvailable(self):
245 """ 248 """
246 Public method to check, if stepping backward through the history is 249 Public method to check, if stepping backward through the history is
247 available. 250 available.
248 251
249 @return flag indicating backward stepping is available 252 @return flag indicating backward stepping is available
250 @rtype bool 253 @rtype bool
251 """ 254 """
252 return QTextBrowser.isBackwardAvailable(self) 255 return QTextBrowser.isBackwardAvailable(self)
253 256
254 def isForwardAvailable(self): 257 def isForwardAvailable(self):
255 """ 258 """
256 Public method to check, if stepping forward through the history is 259 Public method to check, if stepping forward through the history is
257 available. 260 available.
258 261
259 @return flag indicating forward stepping is available 262 @return flag indicating forward stepping is available
260 @rtype bool 263 @rtype bool
261 """ 264 """
262 return QTextBrowser.isForwardAvailable(self) 265 return QTextBrowser.isForwardAvailable(self)
263 266
264 def scaleUp(self): 267 def scaleUp(self):
265 """ 268 """
266 Public method to zoom in. 269 Public method to zoom in.
267 """ 270 """
268 if self.__zoomCount < 10: 271 if self.__zoomCount < 10:
269 self.__zoomCount += 1 272 self.__zoomCount += 1
270 self.zoomIn() 273 self.zoomIn()
271 self.zoomChanged.emit() 274 self.zoomChanged.emit()
272 275
273 def scaleDown(self): 276 def scaleDown(self):
274 """ 277 """
275 Public method to zoom out. 278 Public method to zoom out.
276 """ 279 """
277 if self.__zoomCount > -5: 280 if self.__zoomCount > -5:
278 self.__zoomCount -= 1 281 self.__zoomCount -= 1
279 self.zoomOut() 282 self.zoomOut()
280 self.zoomChanged.emit() 283 self.zoomChanged.emit()
281 284
282 def setScale(self, scale): 285 def setScale(self, scale):
283 """ 286 """
284 Public method to set the zoom level. 287 Public method to set the zoom level.
285 288
286 @param scale zoom level to set 289 @param scale zoom level to set
287 @type int 290 @type int
288 """ 291 """
289 if -5 <= scale <= 10: 292 if -5 <= scale <= 10:
290 self.zoomOut(scale) 293 self.zoomOut(scale)
291 self.__zoomCount = scale 294 self.__zoomCount = scale
292 self.zoomChanged.emit() 295 self.zoomChanged.emit()
293 296
294 def resetScale(self): 297 def resetScale(self):
295 """ 298 """
296 Public method to reset the zoom level. 299 Public method to reset the zoom level.
297 """ 300 """
298 if self.__zoomCount != 0: 301 if self.__zoomCount != 0:
299 self.zoomOut(self.__zoomCount) 302 self.zoomOut(self.__zoomCount)
300 self.zoomChanged.emit() 303 self.zoomChanged.emit()
301 self.__zoomCount = 0 304 self.__zoomCount = 0
302 305
303 def scale(self): 306 def scale(self):
304 """ 307 """
305 Public method to get the zoom level. 308 Public method to get the zoom level.
306 309
307 @return current zoom level 310 @return current zoom level
308 @rtype int 311 @rtype int
309 """ 312 """
310 return self.__zoomCount 313 return self.__zoomCount
311 314
312 def isScaleUpAvailable(self): 315 def isScaleUpAvailable(self):
313 """ 316 """
314 Public method to check, if the max. zoom level is reached. 317 Public method to check, if the max. zoom level is reached.
315 318
316 @return flag indicating scale up is available 319 @return flag indicating scale up is available
317 @rtype bool 320 @rtype bool
318 """ 321 """
319 return self.__zoomCount < 10 322 return self.__zoomCount < 10
320 323
321 def isScaleDownAvailable(self): 324 def isScaleDownAvailable(self):
322 """ 325 """
323 Public method to check, if the min. zoom level is reached. 326 Public method to check, if the min. zoom level is reached.
324 327
325 @return flag indicating scale down is available 328 @return flag indicating scale down is available
326 @rtype bool 329 @rtype bool
327 """ 330 """
328 return self.__zoomCount > -5 331 return self.__zoomCount > -5
329 332
330 def wheelEvent(self, evt): 333 def wheelEvent(self, evt):
331 """ 334 """
332 Protected method to handle wheel event to zoom. 335 Protected method to handle wheel event to zoom.
333 336
334 @param evt reference to the event object 337 @param evt reference to the event object
335 @type QWheelEvent 338 @type QWheelEvent
336 """ 339 """
337 delta = evt.angleDelta().y() 340 delta = evt.angleDelta().y()
338 if evt.modifiers() == Qt.KeyboardModifier.ControlModifier: 341 if evt.modifiers() == Qt.KeyboardModifier.ControlModifier:
339 if delta > 0: 342 if delta > 0:
340 self.scaleUp() 343 self.scaleUp()
341 else: 344 else:
342 self.scaleDown() 345 self.scaleDown()
343 evt.accept() 346 evt.accept()
344 347
345 elif evt.modifiers() & Qt.KeyboardModifier.ShiftModifier: 348 elif evt.modifiers() & Qt.KeyboardModifier.ShiftModifier:
346 if delta < 0: 349 if delta < 0:
347 self.backward() 350 self.backward()
348 elif delta > 0: 351 elif delta > 0:
349 self.forward() 352 self.forward()
350 evt.accept() 353 evt.accept()
351 354
352 else: 355 else:
353 QTextBrowser.wheelEvent(self, evt) 356 QTextBrowser.wheelEvent(self, evt)
354 357
355 def keyPressEvent(self, evt): 358 def keyPressEvent(self, evt):
356 """ 359 """
357 Protected method to handle key press events. 360 Protected method to handle key press events.
358 361
359 @param evt reference to the key event 362 @param evt reference to the key event
360 @type QKeyEvent 363 @type QKeyEvent
361 """ 364 """
362 key = evt.key() 365 key = evt.key()
363 isControlModifier = ( 366 isControlModifier = evt.modifiers() == Qt.KeyboardModifier.ControlModifier
364 evt.modifiers() == Qt.KeyboardModifier.ControlModifier 367
365 ) 368 if key == Qt.Key.Key_ZoomIn or (key == Qt.Key.Key_Plus and isControlModifier):
366
367 if (
368 key == Qt.Key.Key_ZoomIn or
369 (key == Qt.Key.Key_Plus and isControlModifier)
370 ):
371 self.scaleUp() 369 self.scaleUp()
372 evt.accept() 370 evt.accept()
373 elif ( 371 elif key == Qt.Key.Key_ZoomOut or (
374 key == Qt.Key.Key_ZoomOut or 372 key == Qt.Key.Key_Minus and isControlModifier
375 (key == Qt.Key.Key_Minus and isControlModifier)
376 ): 373 ):
377 self.scaleDown() 374 self.scaleDown()
378 evt.accept() 375 evt.accept()
379 elif key == Qt.Key.Key_0 and isControlModifier: 376 elif key == Qt.Key.Key_0 and isControlModifier:
380 self.resetScale() 377 self.resetScale()
381 evt.accept() 378 evt.accept()
382 elif ( 379 elif key == Qt.Key.Key_Backspace or (
383 key == Qt.Key.Key_Backspace or 380 key == Qt.Key.Key_Left and isControlModifier
384 (key == Qt.Key.Key_Left and isControlModifier)
385 ): 381 ):
386 self.backward() 382 self.backward()
387 evt.accept() 383 evt.accept()
388 elif key == Qt.Key.Key_Right and isControlModifier: 384 elif key == Qt.Key.Key_Right and isControlModifier:
389 self.forward() 385 self.forward()
390 evt.accept() 386 evt.accept()
391 elif key == Qt.Key.Key_F and isControlModifier: 387 elif key == Qt.Key.Key_F and isControlModifier:
392 self.__helpViewerWidget.showHideSearch(True) 388 self.__helpViewerWidget.showHideSearch(True)
393 evt.accept() 389 evt.accept()
390 elif key == Qt.Key.Key_F3 and evt.modifiers() == Qt.KeyboardModifier.NoModifier:
391 self.__helpViewerWidget.searchNext()
392 evt.accept()
394 elif ( 393 elif (
395 key == Qt.Key.Key_F3 and 394 key == Qt.Key.Key_F3
396 evt.modifiers() == Qt.KeyboardModifier.NoModifier 395 and evt.modifiers() == Qt.KeyboardModifier.ShiftModifier
397 ):
398 self.__helpViewerWidget.searchNext()
399 evt.accept()
400 elif (
401 key == Qt.Key.Key_F3 and
402 evt.modifiers() == Qt.KeyboardModifier.ShiftModifier
403 ): 396 ):
404 self.__helpViewerWidget.searchPrev() 397 self.__helpViewerWidget.searchPrev()
405 evt.accept() 398 evt.accept()
406 else: 399 else:
407 super().keyPressEvent(evt) 400 super().keyPressEvent(evt)
408 401
409 def event(self, evt): 402 def event(self, evt):
410 """ 403 """
411 Public method handling events. 404 Public method handling events.
412 405
413 @param evt reference to the event 406 @param evt reference to the event
414 @type QEvent 407 @type QEvent
415 @return flag indicating the event was handled 408 @return flag indicating the event was handled
416 @rtype bool 409 @rtype bool
417 """ 410 """
418 if evt.type() == QEvent.Type.Gesture: 411 if evt.type() == QEvent.Type.Gesture:
419 self.gestureEvent(evt) 412 self.gestureEvent(evt)
420 return True 413 return True
421 414
422 return super().event(evt) 415 return super().event(evt)
423 416
424 def gestureEvent(self, evt): 417 def gestureEvent(self, evt):
425 """ 418 """
426 Protected method handling gesture events. 419 Protected method handling gesture events.
427 420
428 @param evt reference to the gesture event 421 @param evt reference to the gesture event
429 @type QGestureEvent 422 @type QGestureEvent
430 """ 423 """
431 pinch = evt.gesture(Qt.GestureType.PinchGesture) 424 pinch = evt.gesture(Qt.GestureType.PinchGesture)
432 if pinch: 425 if pinch:
441 elif zoom >= 10: 434 elif zoom >= 10:
442 zoom = 10 435 zoom = 10
443 pinch.setTotalScaleFactor(1.6) 436 pinch.setTotalScaleFactor(1.6)
444 self.setScale(zoom) 437 self.setScale(zoom)
445 evt.accept() 438 evt.accept()
446 439
447 ####################################################################### 440 #######################################################################
448 ## Context menu related methods below 441 ## Context menu related methods below
449 ####################################################################### 442 #######################################################################
450 443
451 @pyqtSlot(QPoint) 444 @pyqtSlot(QPoint)
452 def __showContextMenu(self, pos): 445 def __showContextMenu(self, pos):
453 """ 446 """
454 Private slot to show the context menu. 447 Private slot to show the context menu.
455 448
456 @param pos position to show the context menu at 449 @param pos position to show the context menu at
457 @type QPoint 450 @type QPoint
458 """ 451 """
459 self.__menu.clear() 452 self.__menu.clear()
460 anchor = self.anchorAt(pos) 453 anchor = self.anchorAt(pos)
461 linkUrl = self.link().resolved(QUrl(anchor)) if anchor else QUrl() 454 linkUrl = self.link().resolved(QUrl(anchor)) if anchor else QUrl()
462 selectedText = self.textCursor().selectedText() 455 selectedText = self.textCursor().selectedText()
463 456
464 act = self.__menu.addAction( 457 act = self.__menu.addAction(
465 UI.PixmapCache.getIcon("back"), 458 UI.PixmapCache.getIcon("back"), self.tr("Backward"), self.backward
466 self.tr("Backward"), 459 )
467 self.backward)
468 act.setEnabled(self.isBackwardAvailable()) 460 act.setEnabled(self.isBackwardAvailable())
469 461
470 act = self.__menu.addAction( 462 act = self.__menu.addAction(
471 UI.PixmapCache.getIcon("forward"), 463 UI.PixmapCache.getIcon("forward"), self.tr("Forward"), self.forward
472 self.tr("Forward"), 464 )
473 self.forward)
474 act.setEnabled(self.isForwardAvailable()) 465 act.setEnabled(self.isForwardAvailable())
475 466
476 act = self.__menu.addAction( 467 act = self.__menu.addAction(
477 UI.PixmapCache.getIcon("reload"), 468 UI.PixmapCache.getIcon("reload"), self.tr("Reload"), self.reload
478 self.tr("Reload"), 469 )
479 self.reload) 470
480
481 if not linkUrl.isEmpty() and linkUrl.scheme() != "javascript": 471 if not linkUrl.isEmpty() and linkUrl.scheme() != "javascript":
482 self.__createLinkContextMenu(self.__menu, linkUrl) 472 self.__createLinkContextMenu(self.__menu, linkUrl)
483 473
484 self.__menu.addSeparator() 474 self.__menu.addSeparator()
485 475
486 act = self.__menu.addAction( 476 act = self.__menu.addAction(
487 UI.PixmapCache.getIcon("editCopy"), 477 UI.PixmapCache.getIcon("editCopy"), self.tr("Copy Page URL to Clipboard")
488 self.tr("Copy Page URL to Clipboard")) 478 )
489 act.setData(self.link()) 479 act.setData(self.link())
490 act.triggered.connect( 480 act.triggered.connect(functools.partial(self.__copyLink, act))
491 functools.partial(self.__copyLink, act)) 481
492 482 act = self.__menu.addAction(
493 act = self.__menu.addAction( 483 UI.PixmapCache.getIcon("bookmark22"), self.tr("Bookmark Page")
494 UI.PixmapCache.getIcon("bookmark22"), 484 )
495 self.tr("Bookmark Page")) 485 act.setData({"title": self.pageTitle(), "url": self.link()})
496 act.setData({ 486 act.triggered.connect(functools.partial(self.__bookmarkPage, act))
497 "title": self.pageTitle(), 487
498 "url": self.link()
499 })
500 act.triggered.connect(
501 functools.partial(self.__bookmarkPage, act))
502
503 self.__menu.addSeparator() 488 self.__menu.addSeparator()
504 489
505 act = self.__menu.addAction( 490 act = self.__menu.addAction(
506 UI.PixmapCache.getIcon("zoomIn"), 491 UI.PixmapCache.getIcon("zoomIn"), self.tr("Zoom in"), self.scaleUp
507 self.tr("Zoom in"), 492 )
508 self.scaleUp)
509 act.setEnabled(self.isScaleUpAvailable()) 493 act.setEnabled(self.isScaleUpAvailable())
510 494
511 act = self.__menu.addAction( 495 act = self.__menu.addAction(
512 UI.PixmapCache.getIcon("zoomOut"), 496 UI.PixmapCache.getIcon("zoomOut"), self.tr("Zoom out"), self.scaleDown
513 self.tr("Zoom out"), 497 )
514 self.scaleDown)
515 act.setEnabled(self.isScaleDownAvailable()) 498 act.setEnabled(self.isScaleDownAvailable())
516 499
517 self.__menu.addAction( 500 self.__menu.addAction(
518 UI.PixmapCache.getIcon("zoomReset"), 501 UI.PixmapCache.getIcon("zoomReset"), self.tr("Zoom reset"), self.resetScale
519 self.tr("Zoom reset"), 502 )
520 self.resetScale) 503
521
522 self.__menu.addSeparator() 504 self.__menu.addSeparator()
523 505
524 act = self.__menu.addAction( 506 act = self.__menu.addAction(
525 UI.PixmapCache.getIcon("editCopy"), 507 UI.PixmapCache.getIcon("editCopy"), self.tr("Copy"), self.copy
526 self.tr("Copy"), 508 )
527 self.copy)
528 act.setEnabled(bool(selectedText)) 509 act.setEnabled(bool(selectedText))
529 510
530 self.__menu.addAction( 511 self.__menu.addAction(
531 UI.PixmapCache.getIcon("editSelectAll"), 512 UI.PixmapCache.getIcon("editSelectAll"),
532 self.tr("Select All"), 513 self.tr("Select All"),
533 self.selectAll) 514 self.selectAll,
534 515 )
516
535 self.__menu.addSeparator() 517 self.__menu.addSeparator()
536 518
537 self.__menu.addAction( 519 self.__menu.addAction(
538 UI.PixmapCache.getIcon("tabClose"), 520 UI.PixmapCache.getIcon("tabClose"), self.tr("Close"), self.__closePage
539 self.tr('Close'), 521 )
540 self.__closePage) 522
541
542 act = self.__menu.addAction( 523 act = self.__menu.addAction(
543 UI.PixmapCache.getIcon("tabCloseOther"), 524 UI.PixmapCache.getIcon("tabCloseOther"),
544 self.tr("Close Others"), 525 self.tr("Close Others"),
545 self.__closeOtherPages) 526 self.__closeOtherPages,
527 )
546 act.setEnabled(self.__helpViewerWidget.openPagesCount() > 1) 528 act.setEnabled(self.__helpViewerWidget.openPagesCount() > 1)
547 529
548 self.__menu.popup(self.mapToGlobal(pos)) 530 self.__menu.popup(self.mapToGlobal(pos))
549 531
550 def __createLinkContextMenu(self, menu, linkUrl): 532 def __createLinkContextMenu(self, menu, linkUrl):
551 """ 533 """
552 Private method to populate the context menu for URLs. 534 Private method to populate the context menu for URLs.
553 535
554 @param menu reference to the menu to be populated 536 @param menu reference to the menu to be populated
555 @type QMenu 537 @type QMenu
556 @param linkUrl URL to create the menu part for 538 @param linkUrl URL to create the menu part for
557 @type QUrl 539 @type QUrl
558 """ 540 """
559 if not menu.isEmpty(): 541 if not menu.isEmpty():
560 menu.addSeparator() 542 menu.addSeparator()
561 543
562 act = menu.addAction( 544 act = menu.addAction(
563 UI.PixmapCache.getIcon("openNewTab"), 545 UI.PixmapCache.getIcon("openNewTab"), self.tr("Open Link in New Page")
564 self.tr("Open Link in New Page")) 546 )
565 act.setData(linkUrl) 547 act.setData(linkUrl)
566 act.triggered.connect( 548 act.triggered.connect(functools.partial(self.__openLinkInNewPage, act))
567 functools.partial(self.__openLinkInNewPage, act)) 549
568
569 act = menu.addAction( 550 act = menu.addAction(
570 UI.PixmapCache.getIcon("newWindow"), 551 UI.PixmapCache.getIcon("newWindow"), self.tr("Open Link in Background Page")
571 self.tr("Open Link in Background Page")) 552 )
572 act.setData(linkUrl) 553 act.setData(linkUrl)
573 act.triggered.connect( 554 act.triggered.connect(functools.partial(self.__openLinkInBackgroundPage, act))
574 functools.partial(self.__openLinkInBackgroundPage, act)) 555
575
576 menu.addSeparator() 556 menu.addSeparator()
577 557
578 act = menu.addAction( 558 act = menu.addAction(
579 UI.PixmapCache.getIcon("editCopy"), 559 UI.PixmapCache.getIcon("editCopy"), self.tr("Copy URL to Clipboard")
580 self.tr("Copy URL to Clipboard")) 560 )
581 act.setData(linkUrl) 561 act.setData(linkUrl)
582 act.triggered.connect( 562 act.triggered.connect(functools.partial(self.__copyLink, act))
583 functools.partial(self.__copyLink, act)) 563
584
585 def __openLinkInNewPage(self, act): 564 def __openLinkInNewPage(self, act):
586 """ 565 """
587 Private method called by the context menu to open a link in a new page. 566 Private method called by the context menu to open a link in a new page.
588 567
589 @param act reference to the action that triggered 568 @param act reference to the action that triggered
590 @type QAction 569 @type QAction
591 """ 570 """
592 url = act.data() 571 url = act.data()
593 if url.isEmpty(): 572 if url.isEmpty():
594 return 573 return
595 574
596 self.__helpViewerWidget.openUrlNewPage(url) 575 self.__helpViewerWidget.openUrlNewPage(url)
597 576
598 def __openLinkInBackgroundPage(self, act): 577 def __openLinkInBackgroundPage(self, act):
599 """ 578 """
600 Private method called by the context menu to open a link in a 579 Private method called by the context menu to open a link in a
601 background page. 580 background page.
602 581
603 @param act reference to the action that triggered 582 @param act reference to the action that triggered
604 @type QAction 583 @type QAction
605 """ 584 """
606 url = act.data() 585 url = act.data()
607 if url.isEmpty(): 586 if url.isEmpty():
608 return 587 return
609 588
610 self.__helpViewerWidget.openUrlNewBackgroundPage(url) 589 self.__helpViewerWidget.openUrlNewBackgroundPage(url)
611 590
612 def __bookmarkPage(self, act): 591 def __bookmarkPage(self, act):
613 """ 592 """
614 Private method called by the context menu to bookmark the page. 593 Private method called by the context menu to bookmark the page.
615 594
616 @param act reference to the action that triggered 595 @param act reference to the action that triggered
617 @type QAction 596 @type QAction
618 """ 597 """
619 data = act.data() 598 data = act.data()
620 if data: 599 if data:
621 with contextlib.suppress(KeyError): 600 with contextlib.suppress(KeyError):
622 url = data["url"] 601 url = data["url"]
623 title = data["title"] 602 title = data["title"]
624 603
625 self.__helpViewerWidget.bookmarkPage(title, url) 604 self.__helpViewerWidget.bookmarkPage(title, url)
626 605
627 def __copyLink(self, act): 606 def __copyLink(self, act):
628 """ 607 """
629 Private method called by the context menu to copy a link to the 608 Private method called by the context menu to copy a link to the
630 clipboard. 609 clipboard.
631 610
632 @param act reference to the action that triggered 611 @param act reference to the action that triggered
633 @type QAction 612 @type QAction
634 """ 613 """
635 data = act.data() 614 data = act.data()
636 if isinstance(data, QUrl) and data.isEmpty(): 615 if isinstance(data, QUrl) and data.isEmpty():
637 return 616 return
638 617
639 if isinstance(data, QUrl): 618 if isinstance(data, QUrl):
640 data = data.toString() 619 data = data.toString()
641 620
642 # copy the URL to both clipboard areas 621 # copy the URL to both clipboard areas
643 QGuiApplication.clipboard().setText(data, QClipboard.Mode.Clipboard) 622 QGuiApplication.clipboard().setText(data, QClipboard.Mode.Clipboard)
644 QGuiApplication.clipboard().setText(data, QClipboard.Mode.Selection) 623 QGuiApplication.clipboard().setText(data, QClipboard.Mode.Selection)
645 624
646 def __closePage(self): 625 def __closePage(self):
647 """ 626 """
648 Private method called by the context menu to close the current page. 627 Private method called by the context menu to close the current page.
649 """ 628 """
650 self.__helpViewerWidget.closeCurrentPage() 629 self.__helpViewerWidget.closeCurrentPage()
651 630
652 def __closeOtherPages(self): 631 def __closeOtherPages(self):
653 """ 632 """
654 Private method called by the context menu to close all other pages. 633 Private method called by the context menu to close all other pages.
655 """ 634 """
656 self.__helpViewerWidget.closeOtherPages() 635 self.__helpViewerWidget.closeOtherPages()

eric ide

mercurial