--- a/eric7/HelpViewer/HelpViewerWidget.py Sat Oct 16 20:37:32 2021 +0200 +++ b/eric7/HelpViewer/HelpViewerWidget.py Sat Oct 16 20:38:23 2021 +0200 @@ -9,7 +9,7 @@ import os -from PyQt6.QtCore import pyqtSlot, Qt, QUrl, QTimer +from PyQt6.QtCore import pyqtSlot, Qt, QUrl, QTimer, QByteArray from PyQt6.QtGui import QAction, QFont, QFontMetrics from PyQt6.QtHelp import QHelpEngine from PyQt6.QtWidgets import ( @@ -17,6 +17,11 @@ QToolButton, QButtonGroup, QAbstractButton, QMenu, QFrame, QLabel, QProgressBar ) +try: + from PyQt6.QtWebEngineCore import QWebEngineProfile, QWebEngineSettings + WEBENGINE_AVAILABLE = True +except ImportError: + WEBENGINE_AVAILABLE = True from EricWidgets import EricFileDialog, EricMessageBox @@ -35,6 +40,8 @@ """ Class implementing an embedded viewer for QtHelp and local HTML files. """ + MaxHistoryItems = 20 # max. number of history items to be shown + def __init__(self, parent=None): """ Constructor @@ -62,8 +69,7 @@ QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Preferred) self.__selectorLayout.addWidget(self.__helpSelector) self.__populateHelpSelector() - self.__helpSelector.currentIndexChanged.connect( - self.__helpTopicSelected) + self.__helpSelector.activated.connect(self.__helpTopicSelected) self.__openButton = QToolButton(self) self.__openButton.setIcon(UI.PixmapCache.getIcon("open")) @@ -137,6 +143,14 @@ self.__zoomResetButton.clicked.connect(self.__zoomReset) self.__navButtonsLayout.addWidget(self.__zoomResetButton) + self.__buttonLine2 = QFrame(self) + self.__buttonLine2.setFrameShape(QFrame.Shape.VLine) + self.__buttonLine2.setFrameShadow(QFrame.Shadow.Sunken) + self.__navButtonsLayout.addWidget(self.__buttonLine2) + + # TODO: add plus button to open a new page (about:blank) + # TODO: add minus button to close the current page + self.__navButtonsLayout.addStretch() self.__layout.addLayout(self.__navButtonsLayout) @@ -161,6 +175,10 @@ ################################################################### + # TODO: addd a search widget (EricTextEditSearchWidget) + + ################################################################### + self.__helpNavigationStack = QStackedWidget(self) self.__helpNavigationStack.setSizePolicy( QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Preferred) @@ -210,6 +228,10 @@ self.__initActionsMenu() + if WEBENGINE_AVAILABLE: + self.__initQWebEngine() + self.__ui.preferencesChanged.connect(self.__initQWebEngineSettings) + self.addPage() self.__checkActionButtons() @@ -241,7 +263,7 @@ """ # Open Pages self.__openPagesList = OpenPagesWidget(self.__helpStack, self) - self.__openPagesList.currentChanged.connect(self.__checkActionButtons) + self.__openPagesList.currentChanged.connect(self.__currentPageChanged) self.__helpNavigationStack.addWidget(self.__openPagesList) # QtHelp TOC widget @@ -335,7 +357,7 @@ urlStr = self.__helpSelector.currentData() if urlStr: url = QUrl(urlStr) - self.currentViewer().setUrl(url) + self.openUrl(url) def activate(self, searchWord=None): """ @@ -394,11 +416,13 @@ self.__helpStack.insertWidget(index, viewer) self.__openPagesList.insertPage( index, viewer, background=background) + cv.setFocus(Qt.FocusReason.OtherFocusReason) return self.__helpStack.addWidget(viewer) self.__openPagesList.addPage(viewer, background=background) - + viewer.setFocus(Qt.FocusReason.OtherFocusReason) + @pyqtSlot(QUrl) def openUrl(self, url): """ @@ -410,6 +434,7 @@ cv = self.currentViewer() if cv: cv.setUrl(url) + cv.setFocus(Qt.FocusReason.OtherFocusReason) @pyqtSlot(QUrl) def openUrlNewPage(self, url): @@ -447,10 +472,10 @@ @return help viewer @rtype HelpViewerImpl """ - try: + if WEBENGINE_AVAILABLE: from .HelpViewerImpl_qwe import HelpViewerImpl_qwe viewer = HelpViewerImpl_qwe(self.__helpEngine, self) - except ImportError: + else: from .HelpViewerImpl_qtb import HelpViewerImpl_qtb viewer = HelpViewerImpl_qtb(self.__helpEngine, self) @@ -624,23 +649,6 @@ if cv: cv.reload() - @pyqtSlot() - def __checkActionButtons(self): - """ - Private slot to set the enabled state of the action buttons. - """ - cv = self.currentViewer() - if cv: - self.__backwardButton.setEnabled(cv.isBackwardAvailable()) - self.__forwardButton.setEnabled(cv.isForwardAvailable()) - self.__zoomInButton.setEnabled(cv.isScaleUpAvailable()) - self.__zoomOutButton.setEnabled(cv.isScaleDownAvailable()) - else: - self.__backwardButton.setEnabled(False) - self.__forwardButton.setEnabled(False) - self.__zoomInButton.setEnabled(False) - self.__zoomOutButton.setEnabled(False) - def __showBackMenu(self): """ Private slot showing the backward navigation menu. @@ -648,8 +656,8 @@ cv = self.currentViewer() if cv: self.__backMenu.clear() - backwardHistoryCount = min(cv.backwardHistoryCount(), 20) - # show max. 20 items + backwardHistoryCount = min(cv.backwardHistoryCount(), + HelpViewerWidget.MaxHistoryItems) for index in range(1, backwardHistoryCount + 1): act = QAction(self) @@ -668,8 +676,8 @@ cv = self.currentViewer() if cv: self.__forwardMenu.clear() - forwardHistoryCount = min(cv.forwardHistoryCount(), 20) - # show max. 20 items + forwardHistoryCount = min(cv.forwardHistoryCount(), + HelpViewerWidget.MaxHistoryItems) for index in range(1, forwardHistoryCount + 1): act = QAction(self) @@ -704,6 +712,37 @@ self.__checkActionButtons() ####################################################################### + ## Page navigation related methods below + ####################################################################### + + @pyqtSlot() + def __checkActionButtons(self): + """ + Private slot to set the enabled state of the action buttons. + """ + cv = self.currentViewer() + if cv: + self.__backwardButton.setEnabled(cv.isBackwardAvailable()) + self.__forwardButton.setEnabled(cv.isForwardAvailable()) + self.__zoomInButton.setEnabled(cv.isScaleUpAvailable()) + self.__zoomOutButton.setEnabled(cv.isScaleDownAvailable()) + else: + self.__backwardButton.setEnabled(False) + self.__forwardButton.setEnabled(False) + self.__zoomInButton.setEnabled(False) + self.__zoomOutButton.setEnabled(False) + + @pyqtSlot() + def __currentPageChanged(self): + """ + Private slot handling the selection of another page. + """ + self.__checkActionButtons() + cv = self.currentViewer() + if cv: + cv.setFocus(Qt.FocusReason.OtherFocusReason) + + ####################################################################### ## Zoom related methods below ####################################################################### @@ -878,3 +917,184 @@ if index < 0: index = 0 self.__helpFilterCombo.setCurrentIndex(index) + + ####################################################################### + ## QWebEngine related code below + ####################################################################### + + def __initQWebEngine(self): + """ + Private method to initialize global QWebEngine related objects. + """ + self.__webProfile = QWebEngineProfile.defaultProfile() + self.__webProfile.setHttpCacheType( + QWebEngineProfile.HttpCacheType.MemoryHttpCache) + self.__webProfile.setHttpCacheMaximumSize(0) + + self.__initQWebEngineSettings() + + from WebBrowser.Network.QtHelpSchemeHandler import QtHelpSchemeHandler + self.__qtHelpSchemeHandler = QtHelpSchemeHandler(self.__helpEngine) + self.__webProfile.installUrlSchemeHandler( + QByteArray(b"qthelp"), self.__qtHelpSchemeHandler) + + def webProfile(self): + """ + Public method to get a reference to the global web profile object. + + @return reference to the global web profile object + @rtype QWebEngineProfile + """ + return self.__webProfile + + def webSettings(self): + """ + Public method to get the web settings of the current profile. + + @return web settings of the current profile + @rtype QWebEngineSettings + """ + return self.webProfile().settings() + + def __initQWebEngineSettings(self): + """ + Private method to set the global web settings. + """ + settings = self.webSettings() + + settings.setFontFamily( + QWebEngineSettings.FontFamily.StandardFont, + Preferences.getWebBrowser("StandardFontFamily")) + settings.setFontFamily( + QWebEngineSettings.FontFamily.FixedFont, + Preferences.getWebBrowser("FixedFontFamily")) + settings.setFontFamily( + QWebEngineSettings.FontFamily.SerifFont, + Preferences.getWebBrowser("SerifFontFamily")) + settings.setFontFamily( + QWebEngineSettings.FontFamily.SansSerifFont, + Preferences.getWebBrowser("SansSerifFontFamily")) + settings.setFontFamily( + QWebEngineSettings.FontFamily.CursiveFont, + Preferences.getWebBrowser("CursiveFontFamily")) + settings.setFontFamily( + QWebEngineSettings.FontFamily.FantasyFont, + Preferences.getWebBrowser("FantasyFontFamily")) + + settings.setFontSize( + QWebEngineSettings.FontSize.DefaultFontSize, + Preferences.getWebBrowser("DefaultFontSize")) + settings.setFontSize( + QWebEngineSettings.FontSize.DefaultFixedFontSize, + Preferences.getWebBrowser("DefaultFixedFontSize")) + settings.setFontSize( + QWebEngineSettings.FontSize.MinimumFontSize, + Preferences.getWebBrowser("MinimumFontSize")) + settings.setFontSize( + QWebEngineSettings.FontSize.MinimumLogicalFontSize, + Preferences.getWebBrowser("MinimumLogicalFontSize")) + + settings.setAttribute( + QWebEngineSettings.WebAttribute.AutoLoadImages, + Preferences.getWebBrowser("AutoLoadImages")) + settings.setAttribute( + QWebEngineSettings.WebAttribute.JavascriptEnabled, + True) + # JavaScript is needed for the web browser functionality + settings.setAttribute( + QWebEngineSettings.WebAttribute.JavascriptCanOpenWindows, + Preferences.getWebBrowser("JavaScriptCanOpenWindows")) + settings.setAttribute( + QWebEngineSettings.WebAttribute.JavascriptCanAccessClipboard, + Preferences.getWebBrowser("JavaScriptCanAccessClipboard")) + settings.setAttribute( + QWebEngineSettings.WebAttribute.PluginsEnabled, + False) + + settings.setAttribute( + QWebEngineSettings.WebAttribute.LocalStorageEnabled, + False) + settings.setDefaultTextEncoding( + Preferences.getWebBrowser("DefaultTextEncoding")) + + settings.setAttribute( + QWebEngineSettings.WebAttribute.SpatialNavigationEnabled, + Preferences.getWebBrowser("SpatialNavigationEnabled")) + settings.setAttribute( + QWebEngineSettings.WebAttribute.LinksIncludedInFocusChain, + Preferences.getWebBrowser("LinksIncludedInFocusChain")) + settings.setAttribute( + QWebEngineSettings.WebAttribute.LocalContentCanAccessRemoteUrls, + Preferences.getWebBrowser("LocalContentCanAccessRemoteUrls")) + settings.setAttribute( + QWebEngineSettings.WebAttribute.LocalContentCanAccessFileUrls, + Preferences.getWebBrowser("LocalContentCanAccessFileUrls")) + settings.setAttribute( + QWebEngineSettings.WebAttribute.XSSAuditingEnabled, + Preferences.getWebBrowser("XSSAuditingEnabled")) + settings.setAttribute( + QWebEngineSettings.WebAttribute.ScrollAnimatorEnabled, + Preferences.getWebBrowser("ScrollAnimatorEnabled")) + settings.setAttribute( + QWebEngineSettings.WebAttribute.ErrorPageEnabled, + Preferences.getWebBrowser("ErrorPageEnabled")) + settings.setAttribute( + QWebEngineSettings.WebAttribute.FullScreenSupportEnabled, + False) + settings.setAttribute( + QWebEngineSettings.WebAttribute.ScreenCaptureEnabled, + Preferences.getWebBrowser("ScreenCaptureEnabled")) + settings.setAttribute( + QWebEngineSettings.WebAttribute.WebGLEnabled, + Preferences.getWebBrowser("WebGLEnabled")) + settings.setAttribute( + QWebEngineSettings.WebAttribute.FocusOnNavigationEnabled, + Preferences.getWebBrowser("FocusOnNavigationEnabled")) + settings.setAttribute( + QWebEngineSettings.WebAttribute.PrintElementBackgrounds, + Preferences.getWebBrowser("PrintElementBackgrounds")) + settings.setAttribute( + QWebEngineSettings.WebAttribute.AllowRunningInsecureContent, + Preferences.getWebBrowser("AllowRunningInsecureContent")) + settings.setAttribute( + QWebEngineSettings.WebAttribute.AllowGeolocationOnInsecureOrigins, + Preferences.getWebBrowser("AllowGeolocationOnInsecureOrigins")) + settings.setAttribute( + QWebEngineSettings.WebAttribute + .AllowWindowActivationFromJavaScript, + Preferences.getWebBrowser( + "AllowWindowActivationFromJavaScript")) + settings.setAttribute( + QWebEngineSettings.WebAttribute.ShowScrollBars, + Preferences.getWebBrowser("ShowScrollBars")) + settings.setAttribute( + QWebEngineSettings.WebAttribute.PlaybackRequiresUserGesture, + Preferences.getWebBrowser( + "PlaybackRequiresUserGesture")) + settings.setAttribute( + QWebEngineSettings.WebAttribute.JavascriptCanPaste, + Preferences.getWebBrowser( + "JavaScriptCanPaste")) + settings.setAttribute( + QWebEngineSettings.WebAttribute.WebRTCPublicInterfacesOnly, + False) + settings.setAttribute( + QWebEngineSettings.WebAttribute.DnsPrefetchEnabled, + False) + settings.setAttribute( + QWebEngineSettings.WebAttribute.PdfViewerEnabled, + Preferences.getWebBrowser( + "PdfViewerEnabled")) + + ####################################################################### + ## Utility methods below + ####################################################################### + + def openPagesCount(self): + """ + Public method to get the count of open pages. + + @return count of open pages + @rtype int + """ + return self.__helpStack.count()