--- a/eric7/HelpViewer/HelpViewerWidget.py Wed Oct 13 18:15:30 2021 +0200 +++ b/eric7/HelpViewer/HelpViewerWidget.py Thu Oct 14 20:15:58 2021 +0200 @@ -9,12 +9,13 @@ import os -from PyQt6.QtCore import pyqtSlot, Qt, QUrl -from PyQt6.QtGui import QAction +from PyQt6.QtCore import pyqtSlot, Qt, QUrl, QTimer +from PyQt6.QtGui import QAction, QFont, QFontMetrics from PyQt6.QtHelp import QHelpEngine from PyQt6.QtWidgets import ( QWidget, QHBoxLayout, QVBoxLayout, QComboBox, QSizePolicy, QStackedWidget, - QToolButton, QButtonGroup, QAbstractButton, QMenu, QFrame + QToolButton, QButtonGroup, QAbstractButton, QMenu, QFrame, QLabel, + QProgressBar ) from EricWidgets import EricFileDialog, EricMessageBox @@ -26,6 +27,8 @@ from .OpenPagesWidget import OpenPagesWidget from WebBrowser.QtHelp.HelpTocWidget import HelpTocWidget +from WebBrowser.QtHelp.HelpIndexWidget import HelpIndexWidget +from WebBrowser.QtHelp.HelpSearchWidget import HelpSearchWidget class HelpViewerWidget(QWidget): @@ -179,15 +182,24 @@ self.__openPagesButton = self.__addNavigationButton( "fileMisc", self.tr("Show list of open pages")) self.__helpTocButton = self.__addNavigationButton( - "tableOfContents", self.tr("Show table of contents")) + "tableOfContents", self.tr("Show the table of contents")) + self.__helpIndexButton = self.__addNavigationButton( + "helpIndex", self.tr("Show the help document index")) + self.__helpSearchButton = self.__addNavigationButton( + "documentFind", self.tr("Show the help search window")) self.__openPagesButton.setChecked(True) - # TODO: add buttons for the QHelp related widgets - self.__buttonLayout.addStretch() + self.__helpFilterWidget = self.__initFilterWidget() + self.__buttonLayout.addWidget(self.__helpFilterWidget) + self.__layout.addLayout(self.__buttonLayout) + self.__indexingProgressWidget = self.__initIndexingProgress() + self.__layout.addWidget(self.__indexingProgressWidget) + self.__indexingProgressWidget.hide() + ################################################################### self.setLayout(self.__layout) @@ -202,6 +214,8 @@ self.addPage() self.__checkActionButtons() + + QTimer.singleShot(50, self.__lookForNewDocumentation) def __addNavigationButton(self, iconName, toolTip): """ @@ -232,16 +246,45 @@ self.__openPagesList.currentChanged.connect(self.__checkActionButtons) self.__helpNavigationStack.addWidget(self.__openPagesList) - # QtHelp TOC - self.__tocWidget = HelpTocWidget(self.__helpEngine, internal=True) - self.__tocWidget.escapePressed.connect(self.__activateCurrentPage) - self.__tocWidget.openUrl.connect(self.openUrl) - self.__tocWidget.newTab.connect(self.openUrlNewPage) - self.__tocWidget.newBackgroundTab.connect( + # QtHelp TOC widget + self.__helpTocWidget = HelpTocWidget( + self.__helpEngine, internal=True) + self.__helpTocWidget.escapePressed.connect(self.__activateCurrentPage) + self.__helpTocWidget.openUrl.connect(self.openUrl) + self.__helpTocWidget.newTab.connect(self.openUrlNewPage) + self.__helpTocWidget.newBackgroundTab.connect( + self.openUrlNewBackgroundPage) + self.__helpNavigationStack.addWidget(self.__helpTocWidget) + + # QtHelp Index widget + self.__helpIndexWidget = HelpIndexWidget( + self.__helpEngine, internal=True) + self.__helpIndexWidget.escapePressed.connect( + self.__activateCurrentPage) + self.__helpIndexWidget.openUrl.connect(self.openUrl) + self.__helpIndexWidget.newTab.connect(self.openUrlNewPage) + self.__helpIndexWidget.newBackgroundTab.connect( self.openUrlNewBackgroundPage) - self.__helpNavigationStack.addWidget(self.__tocWidget) + self.__helpNavigationStack.addWidget(self.__helpIndexWidget) - # TODO: not yet implemented + # QtHelp Search widget + self.__indexing = False + self.__indexingProgress = None + self.__helpSearchEngine = self.__helpEngine.searchEngine() + self.__helpSearchEngine.indexingStarted.connect( + self.__indexingStarted) + self.__helpSearchEngine.indexingFinished.connect( + self.__indexingFinished) + + self.__helpSearchWidget = HelpSearchWidget( + self.__helpSearchEngine, internal=True) + self.__helpSearchWidget.escapePressed.connect( + self.__activateCurrentPage) + self.__helpSearchWidget.openUrl.connect(self.openUrl) + self.__helpSearchWidget.newTab.connect(self.openUrlNewPage) + self.__helpSearchWidget.newBackgroundTab.connect( + self.openUrlNewBackgroundPage) + self.__helpNavigationStack.addWidget(self.__helpSearchWidget) @pyqtSlot(QAbstractButton) def __selectNavigationWidget(self, button): @@ -252,11 +295,17 @@ @type QAbstractButton """ if button == self.__openPagesButton: - self.__helpNavigationStack.setCurrentWidget(self.__openPagesList) + self.__helpNavigationStack.setCurrentWidget( + self.__openPagesList) elif button == self.__helpTocButton: - self.__helpNavigationStack.setCurrentWidget(self.__tocWidget) - - # TODO: not yet implemented + self.__helpNavigationStack.setCurrentWidget( + self.__helpTocWidget) + elif button == self.__helpIndexButton: + self.__helpNavigationStack.setCurrentWidget( + self.__helpIndexWidget) + elif button == self.__helpSearchButton: + self.__helpNavigationStack.setCurrentWidget( + self.__helpSearchWidget) def __populateHelpSelector(self): """ @@ -290,15 +339,6 @@ url = QUrl(urlStr) self.currentViewer().setUrl(url) - def searchQtHelp(self, searchExpression): - """ - Public method to search for a given search expression. - - @param searchExpression expression to search for - @type str - """ - # TODO: not yet implemented - def activate(self, searchWord=None): """ Public method to activate the widget and search for a given word. @@ -313,6 +353,15 @@ if searchWord: self.searchQtHelp(searchWord) + def shutdown(self): + """ + Public method to perform shut down actions. + """ + self.__helpSearchEngine.cancelIndexing() + self.__helpSearchEngine.cancelSearching() + + self.__helpInstaller.stop() + @pyqtSlot() def __openFile(self): """ @@ -432,8 +481,8 @@ self.__getQtHelpCollectionFileName(), self) self.__helpEngine.setReadOnly(False) + self.__helpEngine.setUsesFilterEngine(True) self.__helpEngine.setupData() - self.__helpEngine.setUsesFilterEngine(True) self.__removeOldDocumentation() self.__helpEngine.warning.connect(self.__warning) @@ -472,6 +521,47 @@ self.__helpEngine.unregisterDocumentation(namespace) @pyqtSlot() + def __lookForNewDocumentation(self): + """ + Private slot to look for new documentation to be loaded into the + help database. + """ + from WebBrowser.QtHelp.HelpDocsInstaller import HelpDocsInstaller + self.__helpInstaller = HelpDocsInstaller( + self.__helpEngine.collectionFile()) + self.__helpInstaller.errorMessage.connect( + self.__showInstallationError) + self.__helpInstaller.docsInstalled.connect(self.__docsInstalled) + + self.__ui.statusBar().showMessage( + self.tr("Looking for Documentation...")) + self.__helpInstaller.installDocs() + + @pyqtSlot(str) + def __showInstallationError(self, message): + """ + Private slot to show installation errors. + + @param message message to be shown + @type str + """ + EricMessageBox.warning( + self, + self.tr("eric Web Browser"), + message) + + @pyqtSlot(bool) + def __docsInstalled(self, installed): + """ + Private slot handling the end of documentation installation. + + @param installed flag indicating that documents were installed + @type bool + """ + self.__ui.statusBar().clearMessage() + self.__helpEngine.setupData() + + @pyqtSlot() def __manageQtHelpDocuments(self): """ Private slot to manage the QtHelp documentation database. @@ -504,7 +594,7 @@ self.__manageQtHelpDocuments) act = self.__actionsMenu.addAction(self.tr("Reindex Documentation"), self.__reindexDocumentation) -## act.triggered.connect(self.__searchEngine.reindexDocumentation) + act.triggered.connect(self.__helpSearchEngine.reindexDocumentation) self.__actionsButton.setMenu(self.__actionsMenu) @@ -648,3 +738,132 @@ cv = self.currentViewer() if cv: cv.resetScale() + + ####################################################################### + ## QtHelp Search related methods below + ####################################################################### + + def __initIndexingProgress(self): + """ + Private method to initialize the help documents indexing progress + widget. + + @return reference to the generated widget + @rtype QWidget + """ + progressWidget = QWidget(self) + layout = QHBoxLayout(progressWidget) + layout.setContentsMargins(0, 0, 0, 0) + + label = QLabel(self.tr("Updating search index")) + layout.addWidget(label) + + progressBar = QProgressBar() + progressBar.setRange(0, 0) + progressBar.setTextVisible(False) + progressBar.setFixedHeight(16) + layout.addWidget(progressBar) + + return progressWidget + + @pyqtSlot() + def __indexingStarted(self): + """ + Private slot handling the start of the indexing process. + """ + self.__indexing = True + self.__indexingProgressWidget.show() + + @pyqtSlot() + def __indexingFinished(self): + """ + Private slot handling the end of the indexing process. + """ + self.__indexingProgressWidget.hide() + self.__indexing = False + + @pyqtSlot(str) + def searchQtHelp(self, searchExpression): + """ + Public slot to search for a given search expression. + + @param searchExpression expression to search for + @type str + """ + if searchExpression: + if self.__indexing: + # Try again a second later + QTimer.singleShot( + 1000, + lambda: self.searchQtHelp(searchExpression) + ) + else: + self.__helpSearchButton.setChecked(True) + self.__helpSearchEngine.search(searchExpression) + + ####################################################################### + ## QtHelp filter related methods below + ####################################################################### + + def __initFilterWidget(self): + """ + Private method to initialize the filter selection widget. + + @return reference to the generated widget + @rtype QWidget + """ + filterWidget = QWidget() + layout = QHBoxLayout(filterWidget) + layout.setContentsMargins(0, 0, 0, 0) + + label = QLabel(self.tr("Filtered by: ")) + layout.addWidget(label) + + self.__helpFilterCombo = QComboBox() + comboWidth = QFontMetrics(QFont()).horizontalAdvance( + "ComboBoxWithEnoughWidth") + self.__helpFilterCombo.setMinimumWidth(comboWidth) + layout.addWidget(self.__helpFilterCombo) + + self.__helpEngine.setupFinished.connect(self.__setupFilterCombo) + self.__helpFilterCombo.currentIndexChanged.connect( + self.__filterQtHelpDocumentation) + + self.__setupFilterCombo() + + return filterWidget + + @pyqtSlot() + def __setupFilterCombo(self): + """ + Private slot to setup the filter combo box. + """ + activeFilter = self.__helpFilterCombo.currentText() + if not activeFilter: + activeFilter = self.__helpEngine.filterEngine().activeFilter() + if not activeFilter: + activeFilter = self.tr("Unfiltered") + allFilters = self.__helpEngine.filterEngine().filters() + + blocked = self.__helpFilterCombo.blockSignals(True) + self.__helpFilterCombo.clear() + self.__helpFilterCombo.addItem(self.tr("Unfiltered")) + if allFilters: + self.__helpFilterCombo.insertSeparator(1) + for helpFilter in sorted(allFilters): + self.__helpFilterCombo.addItem(helpFilter, helpFilter) + self.__helpFilterCombo.blockSignals(blocked) + + self.__helpFilterCombo.setCurrentText(activeFilter) + + @pyqtSlot(int) + def __filterQtHelpDocumentation(self, index): + """ + Private slot to filter the QtHelp documentation. + + @param index index of the selected QtHelp documentation filter + @type int + """ + if self.__helpEngine: + helpFilter = self.__helpFilterCombo.itemData(index) + self.__helpEngine.filterEngine().setActiveFilter(helpFilter)