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() |
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() |