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