eric7/HelpViewer/HelpViewerWidget.py

branch
eric7
changeset 8693
d51660d6f1b9
parent 8686
af2ee3a303ac
child 8696
7e88f292b1b1
equal deleted inserted replaced
8692:9c72f9bc9d72 8693:d51660d6f1b9
7 Module implementing an embedded viewer for QtHelp and local HTML files. 7 Module implementing an embedded viewer for QtHelp and local HTML files.
8 """ 8 """
9 9
10 import os 10 import os
11 11
12 from PyQt6.QtCore import pyqtSlot, Qt, QUrl, QTimer 12 from PyQt6.QtCore import pyqtSlot, Qt, QUrl, QTimer, QByteArray
13 from PyQt6.QtGui import QAction, QFont, QFontMetrics 13 from PyQt6.QtGui import QAction, QFont, QFontMetrics
14 from PyQt6.QtHelp import QHelpEngine 14 from PyQt6.QtHelp import QHelpEngine
15 from PyQt6.QtWidgets import ( 15 from PyQt6.QtWidgets import (
16 QWidget, QHBoxLayout, QVBoxLayout, QComboBox, QSizePolicy, QStackedWidget, 16 QWidget, QHBoxLayout, QVBoxLayout, QComboBox, QSizePolicy, QStackedWidget,
17 QToolButton, QButtonGroup, QAbstractButton, QMenu, QFrame, QLabel, 17 QToolButton, QButtonGroup, QAbstractButton, QMenu, QFrame, QLabel,
18 QProgressBar 18 QProgressBar
19 ) 19 )
20 try:
21 from PyQt6.QtWebEngineCore import QWebEngineProfile, QWebEngineSettings
22 WEBENGINE_AVAILABLE = True
23 except ImportError:
24 WEBENGINE_AVAILABLE = True
20 25
21 from EricWidgets import EricFileDialog, EricMessageBox 26 from EricWidgets import EricFileDialog, EricMessageBox
22 27
23 import UI.PixmapCache 28 import UI.PixmapCache
24 import Utilities 29 import Utilities
33 38
34 class HelpViewerWidget(QWidget): 39 class HelpViewerWidget(QWidget):
35 """ 40 """
36 Class implementing an embedded viewer for QtHelp and local HTML files. 41 Class implementing an embedded viewer for QtHelp and local HTML files.
37 """ 42 """
43 MaxHistoryItems = 20 # max. number of history items to be shown
44
38 def __init__(self, parent=None): 45 def __init__(self, parent=None):
39 """ 46 """
40 Constructor 47 Constructor
41 48
42 @param parent reference to the parent widget (defaults to None) 49 @param parent reference to the parent widget (defaults to None)
60 self.__helpSelector = QComboBox(self) 67 self.__helpSelector = QComboBox(self)
61 self.__helpSelector.setSizePolicy( 68 self.__helpSelector.setSizePolicy(
62 QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Preferred) 69 QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Preferred)
63 self.__selectorLayout.addWidget(self.__helpSelector) 70 self.__selectorLayout.addWidget(self.__helpSelector)
64 self.__populateHelpSelector() 71 self.__populateHelpSelector()
65 self.__helpSelector.currentIndexChanged.connect( 72 self.__helpSelector.activated.connect(self.__helpTopicSelected)
66 self.__helpTopicSelected)
67 73
68 self.__openButton = QToolButton(self) 74 self.__openButton = QToolButton(self)
69 self.__openButton.setIcon(UI.PixmapCache.getIcon("open")) 75 self.__openButton.setIcon(UI.PixmapCache.getIcon("open"))
70 self.__openButton.setToolTip(self.tr("Open a local file")) 76 self.__openButton.setToolTip(self.tr("Open a local file"))
71 self.__openButton.clicked.connect(self.__openFile) 77 self.__openButton.clicked.connect(self.__openFile)
135 self.__zoomResetButton.setToolTip( 141 self.__zoomResetButton.setToolTip(
136 self.tr("Reset the zoom level of the current page")) 142 self.tr("Reset the zoom level of the current page"))
137 self.__zoomResetButton.clicked.connect(self.__zoomReset) 143 self.__zoomResetButton.clicked.connect(self.__zoomReset)
138 self.__navButtonsLayout.addWidget(self.__zoomResetButton) 144 self.__navButtonsLayout.addWidget(self.__zoomResetButton)
139 145
146 self.__buttonLine2 = QFrame(self)
147 self.__buttonLine2.setFrameShape(QFrame.Shape.VLine)
148 self.__buttonLine2.setFrameShadow(QFrame.Shadow.Sunken)
149 self.__navButtonsLayout.addWidget(self.__buttonLine2)
150
151 # TODO: add plus button to open a new page (about:blank)
152 # TODO: add minus button to close the current page
153
140 self.__navButtonsLayout.addStretch() 154 self.__navButtonsLayout.addStretch()
141 155
142 self.__layout.addLayout(self.__navButtonsLayout) 156 self.__layout.addLayout(self.__navButtonsLayout)
143 157
144 self.__backMenu = QMenu(self) 158 self.__backMenu = QMenu(self)
156 170
157 self.__helpStack = QStackedWidget(self) 171 self.__helpStack = QStackedWidget(self)
158 self.__helpStack.setSizePolicy( 172 self.__helpStack.setSizePolicy(
159 QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Expanding) 173 QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Expanding)
160 self.__layout.addWidget(self.__helpStack) 174 self.__layout.addWidget(self.__helpStack)
175
176 ###################################################################
177
178 # TODO: addd a search widget (EricTextEditSearchWidget)
161 179
162 ################################################################### 180 ###################################################################
163 181
164 self.__helpNavigationStack = QStackedWidget(self) 182 self.__helpNavigationStack = QStackedWidget(self)
165 self.__helpNavigationStack.setSizePolicy( 183 self.__helpNavigationStack.setSizePolicy(
208 226
209 self.__ui.preferencesChanged.connect(self.__populateHelpSelector) 227 self.__ui.preferencesChanged.connect(self.__populateHelpSelector)
210 228
211 self.__initActionsMenu() 229 self.__initActionsMenu()
212 230
231 if WEBENGINE_AVAILABLE:
232 self.__initQWebEngine()
233 self.__ui.preferencesChanged.connect(self.__initQWebEngineSettings)
234
213 self.addPage() 235 self.addPage()
214 self.__checkActionButtons() 236 self.__checkActionButtons()
215 237
216 QTimer.singleShot(50, self.__lookForNewDocumentation) 238 QTimer.singleShot(50, self.__lookForNewDocumentation)
217 239
239 """ 261 """
240 Private method to populate the stack of navigation widgets. 262 Private method to populate the stack of navigation widgets.
241 """ 263 """
242 # Open Pages 264 # Open Pages
243 self.__openPagesList = OpenPagesWidget(self.__helpStack, self) 265 self.__openPagesList = OpenPagesWidget(self.__helpStack, self)
244 self.__openPagesList.currentChanged.connect(self.__checkActionButtons) 266 self.__openPagesList.currentChanged.connect(self.__currentPageChanged)
245 self.__helpNavigationStack.addWidget(self.__openPagesList) 267 self.__helpNavigationStack.addWidget(self.__openPagesList)
246 268
247 # QtHelp TOC widget 269 # QtHelp TOC widget
248 self.__helpTocWidget = HelpTocWidget( 270 self.__helpTocWidget = HelpTocWidget(
249 self.__helpEngine, internal=True) 271 self.__helpEngine, internal=True)
333 Private slot handling the selection of a new help topic. 355 Private slot handling the selection of a new help topic.
334 """ 356 """
335 urlStr = self.__helpSelector.currentData() 357 urlStr = self.__helpSelector.currentData()
336 if urlStr: 358 if urlStr:
337 url = QUrl(urlStr) 359 url = QUrl(urlStr)
338 self.currentViewer().setUrl(url) 360 self.openUrl(url)
339 361
340 def activate(self, searchWord=None): 362 def activate(self, searchWord=None):
341 """ 363 """
342 Public method to activate the widget and search for a given word. 364 Public method to activate the widget and search for a given word.
343 365
392 if cv: 414 if cv:
393 index = self.__helpStack.indexOf(cv) + 1 415 index = self.__helpStack.indexOf(cv) + 1
394 self.__helpStack.insertWidget(index, viewer) 416 self.__helpStack.insertWidget(index, viewer)
395 self.__openPagesList.insertPage( 417 self.__openPagesList.insertPage(
396 index, viewer, background=background) 418 index, viewer, background=background)
419 cv.setFocus(Qt.FocusReason.OtherFocusReason)
397 return 420 return
398 421
399 self.__helpStack.addWidget(viewer) 422 self.__helpStack.addWidget(viewer)
400 self.__openPagesList.addPage(viewer, background=background) 423 self.__openPagesList.addPage(viewer, background=background)
401 424 viewer.setFocus(Qt.FocusReason.OtherFocusReason)
425
402 @pyqtSlot(QUrl) 426 @pyqtSlot(QUrl)
403 def openUrl(self, url): 427 def openUrl(self, url):
404 """ 428 """
405 Public slot to load a URL in the current page. 429 Public slot to load a URL in the current page.
406 430
408 @type QUrl 432 @type QUrl
409 """ 433 """
410 cv = self.currentViewer() 434 cv = self.currentViewer()
411 if cv: 435 if cv:
412 cv.setUrl(url) 436 cv.setUrl(url)
437 cv.setFocus(Qt.FocusReason.OtherFocusReason)
413 438
414 @pyqtSlot(QUrl) 439 @pyqtSlot(QUrl)
415 def openUrlNewPage(self, url): 440 def openUrlNewPage(self, url):
416 """ 441 """
417 Public slot to load a URL in a new page. 442 Public slot to load a URL in a new page.
445 Private method to create a new help viewer. 470 Private method to create a new help viewer.
446 471
447 @return help viewer 472 @return help viewer
448 @rtype HelpViewerImpl 473 @rtype HelpViewerImpl
449 """ 474 """
450 try: 475 if WEBENGINE_AVAILABLE:
451 from .HelpViewerImpl_qwe import HelpViewerImpl_qwe 476 from .HelpViewerImpl_qwe import HelpViewerImpl_qwe
452 viewer = HelpViewerImpl_qwe(self.__helpEngine, self) 477 viewer = HelpViewerImpl_qwe(self.__helpEngine, self)
453 except ImportError: 478 else:
454 from .HelpViewerImpl_qtb import HelpViewerImpl_qtb 479 from .HelpViewerImpl_qtb import HelpViewerImpl_qtb
455 viewer = HelpViewerImpl_qtb(self.__helpEngine, self) 480 viewer = HelpViewerImpl_qtb(self.__helpEngine, self)
456 481
457 viewer.zoomChanged.connect(self.__checkActionButtons) 482 viewer.zoomChanged.connect(self.__checkActionButtons)
458 483
622 """ 647 """
623 cv = self.currentViewer() 648 cv = self.currentViewer()
624 if cv: 649 if cv:
625 cv.reload() 650 cv.reload()
626 651
627 @pyqtSlot()
628 def __checkActionButtons(self):
629 """
630 Private slot to set the enabled state of the action buttons.
631 """
632 cv = self.currentViewer()
633 if cv:
634 self.__backwardButton.setEnabled(cv.isBackwardAvailable())
635 self.__forwardButton.setEnabled(cv.isForwardAvailable())
636 self.__zoomInButton.setEnabled(cv.isScaleUpAvailable())
637 self.__zoomOutButton.setEnabled(cv.isScaleDownAvailable())
638 else:
639 self.__backwardButton.setEnabled(False)
640 self.__forwardButton.setEnabled(False)
641 self.__zoomInButton.setEnabled(False)
642 self.__zoomOutButton.setEnabled(False)
643
644 def __showBackMenu(self): 652 def __showBackMenu(self):
645 """ 653 """
646 Private slot showing the backward navigation menu. 654 Private slot showing the backward navigation menu.
647 """ 655 """
648 cv = self.currentViewer() 656 cv = self.currentViewer()
649 if cv: 657 if cv:
650 self.__backMenu.clear() 658 self.__backMenu.clear()
651 backwardHistoryCount = min(cv.backwardHistoryCount(), 20) 659 backwardHistoryCount = min(cv.backwardHistoryCount(),
652 # show max. 20 items 660 HelpViewerWidget.MaxHistoryItems)
653 661
654 for index in range(1, backwardHistoryCount + 1): 662 for index in range(1, backwardHistoryCount + 1):
655 act = QAction(self) 663 act = QAction(self)
656 act.setData(-index) 664 act.setData(-index)
657 act.setText(cv.historyTitle(-index)) 665 act.setText(cv.historyTitle(-index))
666 Private slot showing the forward navigation menu. 674 Private slot showing the forward navigation menu.
667 """ 675 """
668 cv = self.currentViewer() 676 cv = self.currentViewer()
669 if cv: 677 if cv:
670 self.__forwardMenu.clear() 678 self.__forwardMenu.clear()
671 forwardHistoryCount = min(cv.forwardHistoryCount(), 20) 679 forwardHistoryCount = min(cv.forwardHistoryCount(),
672 # show max. 20 items 680 HelpViewerWidget.MaxHistoryItems)
673 681
674 for index in range(1, forwardHistoryCount + 1): 682 for index in range(1, forwardHistoryCount + 1):
675 act = QAction(self) 683 act = QAction(self)
676 act.setData(index) 684 act.setData(index)
677 act.setText(cv.historyTitle(index)) 685 act.setText(cv.historyTitle(index))
700 """ 708 """
701 cv = self.currentViewer() 709 cv = self.currentViewer()
702 if cv: 710 if cv:
703 cv.clearHistory() 711 cv.clearHistory()
704 self.__checkActionButtons() 712 self.__checkActionButtons()
713
714 #######################################################################
715 ## Page navigation related methods below
716 #######################################################################
717
718 @pyqtSlot()
719 def __checkActionButtons(self):
720 """
721 Private slot to set the enabled state of the action buttons.
722 """
723 cv = self.currentViewer()
724 if cv:
725 self.__backwardButton.setEnabled(cv.isBackwardAvailable())
726 self.__forwardButton.setEnabled(cv.isForwardAvailable())
727 self.__zoomInButton.setEnabled(cv.isScaleUpAvailable())
728 self.__zoomOutButton.setEnabled(cv.isScaleDownAvailable())
729 else:
730 self.__backwardButton.setEnabled(False)
731 self.__forwardButton.setEnabled(False)
732 self.__zoomInButton.setEnabled(False)
733 self.__zoomOutButton.setEnabled(False)
734
735 @pyqtSlot()
736 def __currentPageChanged(self):
737 """
738 Private slot handling the selection of another page.
739 """
740 self.__checkActionButtons()
741 cv = self.currentViewer()
742 if cv:
743 cv.setFocus(Qt.FocusReason.OtherFocusReason)
705 744
706 ####################################################################### 745 #######################################################################
707 ## Zoom related methods below 746 ## Zoom related methods below
708 ####################################################################### 747 #######################################################################
709 748
876 """ 915 """
877 index = self.__helpFilterCombo.findData(filter) 916 index = self.__helpFilterCombo.findData(filter)
878 if index < 0: 917 if index < 0:
879 index = 0 918 index = 0
880 self.__helpFilterCombo.setCurrentIndex(index) 919 self.__helpFilterCombo.setCurrentIndex(index)
920
921 #######################################################################
922 ## QWebEngine related code below
923 #######################################################################
924
925 def __initQWebEngine(self):
926 """
927 Private method to initialize global QWebEngine related objects.
928 """
929 self.__webProfile = QWebEngineProfile.defaultProfile()
930 self.__webProfile.setHttpCacheType(
931 QWebEngineProfile.HttpCacheType.MemoryHttpCache)
932 self.__webProfile.setHttpCacheMaximumSize(0)
933
934 self.__initQWebEngineSettings()
935
936 from WebBrowser.Network.QtHelpSchemeHandler import QtHelpSchemeHandler
937 self.__qtHelpSchemeHandler = QtHelpSchemeHandler(self.__helpEngine)
938 self.__webProfile.installUrlSchemeHandler(
939 QByteArray(b"qthelp"), self.__qtHelpSchemeHandler)
940
941 def webProfile(self):
942 """
943 Public method to get a reference to the global web profile object.
944
945 @return reference to the global web profile object
946 @rtype QWebEngineProfile
947 """
948 return self.__webProfile
949
950 def webSettings(self):
951 """
952 Public method to get the web settings of the current profile.
953
954 @return web settings of the current profile
955 @rtype QWebEngineSettings
956 """
957 return self.webProfile().settings()
958
959 def __initQWebEngineSettings(self):
960 """
961 Private method to set the global web settings.
962 """
963 settings = self.webSettings()
964
965 settings.setFontFamily(
966 QWebEngineSettings.FontFamily.StandardFont,
967 Preferences.getWebBrowser("StandardFontFamily"))
968 settings.setFontFamily(
969 QWebEngineSettings.FontFamily.FixedFont,
970 Preferences.getWebBrowser("FixedFontFamily"))
971 settings.setFontFamily(
972 QWebEngineSettings.FontFamily.SerifFont,
973 Preferences.getWebBrowser("SerifFontFamily"))
974 settings.setFontFamily(
975 QWebEngineSettings.FontFamily.SansSerifFont,
976 Preferences.getWebBrowser("SansSerifFontFamily"))
977 settings.setFontFamily(
978 QWebEngineSettings.FontFamily.CursiveFont,
979 Preferences.getWebBrowser("CursiveFontFamily"))
980 settings.setFontFamily(
981 QWebEngineSettings.FontFamily.FantasyFont,
982 Preferences.getWebBrowser("FantasyFontFamily"))
983
984 settings.setFontSize(
985 QWebEngineSettings.FontSize.DefaultFontSize,
986 Preferences.getWebBrowser("DefaultFontSize"))
987 settings.setFontSize(
988 QWebEngineSettings.FontSize.DefaultFixedFontSize,
989 Preferences.getWebBrowser("DefaultFixedFontSize"))
990 settings.setFontSize(
991 QWebEngineSettings.FontSize.MinimumFontSize,
992 Preferences.getWebBrowser("MinimumFontSize"))
993 settings.setFontSize(
994 QWebEngineSettings.FontSize.MinimumLogicalFontSize,
995 Preferences.getWebBrowser("MinimumLogicalFontSize"))
996
997 settings.setAttribute(
998 QWebEngineSettings.WebAttribute.AutoLoadImages,
999 Preferences.getWebBrowser("AutoLoadImages"))
1000 settings.setAttribute(
1001 QWebEngineSettings.WebAttribute.JavascriptEnabled,
1002 True)
1003 # JavaScript is needed for the web browser functionality
1004 settings.setAttribute(
1005 QWebEngineSettings.WebAttribute.JavascriptCanOpenWindows,
1006 Preferences.getWebBrowser("JavaScriptCanOpenWindows"))
1007 settings.setAttribute(
1008 QWebEngineSettings.WebAttribute.JavascriptCanAccessClipboard,
1009 Preferences.getWebBrowser("JavaScriptCanAccessClipboard"))
1010 settings.setAttribute(
1011 QWebEngineSettings.WebAttribute.PluginsEnabled,
1012 False)
1013
1014 settings.setAttribute(
1015 QWebEngineSettings.WebAttribute.LocalStorageEnabled,
1016 False)
1017 settings.setDefaultTextEncoding(
1018 Preferences.getWebBrowser("DefaultTextEncoding"))
1019
1020 settings.setAttribute(
1021 QWebEngineSettings.WebAttribute.SpatialNavigationEnabled,
1022 Preferences.getWebBrowser("SpatialNavigationEnabled"))
1023 settings.setAttribute(
1024 QWebEngineSettings.WebAttribute.LinksIncludedInFocusChain,
1025 Preferences.getWebBrowser("LinksIncludedInFocusChain"))
1026 settings.setAttribute(
1027 QWebEngineSettings.WebAttribute.LocalContentCanAccessRemoteUrls,
1028 Preferences.getWebBrowser("LocalContentCanAccessRemoteUrls"))
1029 settings.setAttribute(
1030 QWebEngineSettings.WebAttribute.LocalContentCanAccessFileUrls,
1031 Preferences.getWebBrowser("LocalContentCanAccessFileUrls"))
1032 settings.setAttribute(
1033 QWebEngineSettings.WebAttribute.XSSAuditingEnabled,
1034 Preferences.getWebBrowser("XSSAuditingEnabled"))
1035 settings.setAttribute(
1036 QWebEngineSettings.WebAttribute.ScrollAnimatorEnabled,
1037 Preferences.getWebBrowser("ScrollAnimatorEnabled"))
1038 settings.setAttribute(
1039 QWebEngineSettings.WebAttribute.ErrorPageEnabled,
1040 Preferences.getWebBrowser("ErrorPageEnabled"))
1041 settings.setAttribute(
1042 QWebEngineSettings.WebAttribute.FullScreenSupportEnabled,
1043 False)
1044 settings.setAttribute(
1045 QWebEngineSettings.WebAttribute.ScreenCaptureEnabled,
1046 Preferences.getWebBrowser("ScreenCaptureEnabled"))
1047 settings.setAttribute(
1048 QWebEngineSettings.WebAttribute.WebGLEnabled,
1049 Preferences.getWebBrowser("WebGLEnabled"))
1050 settings.setAttribute(
1051 QWebEngineSettings.WebAttribute.FocusOnNavigationEnabled,
1052 Preferences.getWebBrowser("FocusOnNavigationEnabled"))
1053 settings.setAttribute(
1054 QWebEngineSettings.WebAttribute.PrintElementBackgrounds,
1055 Preferences.getWebBrowser("PrintElementBackgrounds"))
1056 settings.setAttribute(
1057 QWebEngineSettings.WebAttribute.AllowRunningInsecureContent,
1058 Preferences.getWebBrowser("AllowRunningInsecureContent"))
1059 settings.setAttribute(
1060 QWebEngineSettings.WebAttribute.AllowGeolocationOnInsecureOrigins,
1061 Preferences.getWebBrowser("AllowGeolocationOnInsecureOrigins"))
1062 settings.setAttribute(
1063 QWebEngineSettings.WebAttribute
1064 .AllowWindowActivationFromJavaScript,
1065 Preferences.getWebBrowser(
1066 "AllowWindowActivationFromJavaScript"))
1067 settings.setAttribute(
1068 QWebEngineSettings.WebAttribute.ShowScrollBars,
1069 Preferences.getWebBrowser("ShowScrollBars"))
1070 settings.setAttribute(
1071 QWebEngineSettings.WebAttribute.PlaybackRequiresUserGesture,
1072 Preferences.getWebBrowser(
1073 "PlaybackRequiresUserGesture"))
1074 settings.setAttribute(
1075 QWebEngineSettings.WebAttribute.JavascriptCanPaste,
1076 Preferences.getWebBrowser(
1077 "JavaScriptCanPaste"))
1078 settings.setAttribute(
1079 QWebEngineSettings.WebAttribute.WebRTCPublicInterfacesOnly,
1080 False)
1081 settings.setAttribute(
1082 QWebEngineSettings.WebAttribute.DnsPrefetchEnabled,
1083 False)
1084 settings.setAttribute(
1085 QWebEngineSettings.WebAttribute.PdfViewerEnabled,
1086 Preferences.getWebBrowser(
1087 "PdfViewerEnabled"))
1088
1089 #######################################################################
1090 ## Utility methods below
1091 #######################################################################
1092
1093 def openPagesCount(self):
1094 """
1095 Public method to get the count of open pages.
1096
1097 @return count of open pages
1098 @rtype int
1099 """
1100 return self.__helpStack.count()

eric ide

mercurial