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 |
12 from PyQt6.QtCore import pyqtSlot, Qt, QUrl, QTimer |
13 from PyQt6.QtGui import QAction |
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 |
17 QToolButton, QButtonGroup, QAbstractButton, QMenu, QFrame, QLabel, |
|
18 QProgressBar |
18 ) |
19 ) |
19 |
20 |
20 from EricWidgets import EricFileDialog, EricMessageBox |
21 from EricWidgets import EricFileDialog, EricMessageBox |
21 |
22 |
22 import UI.PixmapCache |
23 import UI.PixmapCache |
177 self.__buttonLayout.addStretch() |
180 self.__buttonLayout.addStretch() |
178 |
181 |
179 self.__openPagesButton = self.__addNavigationButton( |
182 self.__openPagesButton = self.__addNavigationButton( |
180 "fileMisc", self.tr("Show list of open pages")) |
183 "fileMisc", self.tr("Show list of open pages")) |
181 self.__helpTocButton = self.__addNavigationButton( |
184 self.__helpTocButton = self.__addNavigationButton( |
182 "tableOfContents", self.tr("Show table of contents")) |
185 "tableOfContents", self.tr("Show the table of contents")) |
|
186 self.__helpIndexButton = self.__addNavigationButton( |
|
187 "helpIndex", self.tr("Show the help document index")) |
|
188 self.__helpSearchButton = self.__addNavigationButton( |
|
189 "documentFind", self.tr("Show the help search window")) |
183 self.__openPagesButton.setChecked(True) |
190 self.__openPagesButton.setChecked(True) |
184 |
191 |
185 # TODO: add buttons for the QHelp related widgets |
|
186 |
|
187 self.__buttonLayout.addStretch() |
192 self.__buttonLayout.addStretch() |
188 |
193 |
|
194 self.__helpFilterWidget = self.__initFilterWidget() |
|
195 self.__buttonLayout.addWidget(self.__helpFilterWidget) |
|
196 |
189 self.__layout.addLayout(self.__buttonLayout) |
197 self.__layout.addLayout(self.__buttonLayout) |
|
198 |
|
199 self.__indexingProgressWidget = self.__initIndexingProgress() |
|
200 self.__layout.addWidget(self.__indexingProgressWidget) |
|
201 self.__indexingProgressWidget.hide() |
190 |
202 |
191 ################################################################### |
203 ################################################################### |
192 |
204 |
193 self.setLayout(self.__layout) |
205 self.setLayout(self.__layout) |
194 |
206 |
230 # Open Pages |
244 # Open Pages |
231 self.__openPagesList = OpenPagesWidget(self.__helpStack, self) |
245 self.__openPagesList = OpenPagesWidget(self.__helpStack, self) |
232 self.__openPagesList.currentChanged.connect(self.__checkActionButtons) |
246 self.__openPagesList.currentChanged.connect(self.__checkActionButtons) |
233 self.__helpNavigationStack.addWidget(self.__openPagesList) |
247 self.__helpNavigationStack.addWidget(self.__openPagesList) |
234 |
248 |
235 # QtHelp TOC |
249 # QtHelp TOC widget |
236 self.__tocWidget = HelpTocWidget(self.__helpEngine, internal=True) |
250 self.__helpTocWidget = HelpTocWidget( |
237 self.__tocWidget.escapePressed.connect(self.__activateCurrentPage) |
251 self.__helpEngine, internal=True) |
238 self.__tocWidget.openUrl.connect(self.openUrl) |
252 self.__helpTocWidget.escapePressed.connect(self.__activateCurrentPage) |
239 self.__tocWidget.newTab.connect(self.openUrlNewPage) |
253 self.__helpTocWidget.openUrl.connect(self.openUrl) |
240 self.__tocWidget.newBackgroundTab.connect( |
254 self.__helpTocWidget.newTab.connect(self.openUrlNewPage) |
|
255 self.__helpTocWidget.newBackgroundTab.connect( |
241 self.openUrlNewBackgroundPage) |
256 self.openUrlNewBackgroundPage) |
242 self.__helpNavigationStack.addWidget(self.__tocWidget) |
257 self.__helpNavigationStack.addWidget(self.__helpTocWidget) |
243 |
258 |
244 # TODO: not yet implemented |
259 # QtHelp Index widget |
|
260 self.__helpIndexWidget = HelpIndexWidget( |
|
261 self.__helpEngine, internal=True) |
|
262 self.__helpIndexWidget.escapePressed.connect( |
|
263 self.__activateCurrentPage) |
|
264 self.__helpIndexWidget.openUrl.connect(self.openUrl) |
|
265 self.__helpIndexWidget.newTab.connect(self.openUrlNewPage) |
|
266 self.__helpIndexWidget.newBackgroundTab.connect( |
|
267 self.openUrlNewBackgroundPage) |
|
268 self.__helpNavigationStack.addWidget(self.__helpIndexWidget) |
|
269 |
|
270 # QtHelp Search widget |
|
271 self.__indexing = False |
|
272 self.__indexingProgress = None |
|
273 self.__helpSearchEngine = self.__helpEngine.searchEngine() |
|
274 self.__helpSearchEngine.indexingStarted.connect( |
|
275 self.__indexingStarted) |
|
276 self.__helpSearchEngine.indexingFinished.connect( |
|
277 self.__indexingFinished) |
|
278 |
|
279 self.__helpSearchWidget = HelpSearchWidget( |
|
280 self.__helpSearchEngine, internal=True) |
|
281 self.__helpSearchWidget.escapePressed.connect( |
|
282 self.__activateCurrentPage) |
|
283 self.__helpSearchWidget.openUrl.connect(self.openUrl) |
|
284 self.__helpSearchWidget.newTab.connect(self.openUrlNewPage) |
|
285 self.__helpSearchWidget.newBackgroundTab.connect( |
|
286 self.openUrlNewBackgroundPage) |
|
287 self.__helpNavigationStack.addWidget(self.__helpSearchWidget) |
245 |
288 |
246 @pyqtSlot(QAbstractButton) |
289 @pyqtSlot(QAbstractButton) |
247 def __selectNavigationWidget(self, button): |
290 def __selectNavigationWidget(self, button): |
248 """ |
291 """ |
249 Private slot to select the navigation widget. |
292 Private slot to select the navigation widget. |
250 |
293 |
251 @param button reference to the clicked button |
294 @param button reference to the clicked button |
252 @type QAbstractButton |
295 @type QAbstractButton |
253 """ |
296 """ |
254 if button == self.__openPagesButton: |
297 if button == self.__openPagesButton: |
255 self.__helpNavigationStack.setCurrentWidget(self.__openPagesList) |
298 self.__helpNavigationStack.setCurrentWidget( |
|
299 self.__openPagesList) |
256 elif button == self.__helpTocButton: |
300 elif button == self.__helpTocButton: |
257 self.__helpNavigationStack.setCurrentWidget(self.__tocWidget) |
301 self.__helpNavigationStack.setCurrentWidget( |
258 |
302 self.__helpTocWidget) |
259 # TODO: not yet implemented |
303 elif button == self.__helpIndexButton: |
|
304 self.__helpNavigationStack.setCurrentWidget( |
|
305 self.__helpIndexWidget) |
|
306 elif button == self.__helpSearchButton: |
|
307 self.__helpNavigationStack.setCurrentWidget( |
|
308 self.__helpSearchWidget) |
260 |
309 |
261 def __populateHelpSelector(self): |
310 def __populateHelpSelector(self): |
262 """ |
311 """ |
263 Private method to populate the help selection combo box. |
312 Private method to populate the help selection combo box. |
264 """ |
313 """ |
468 """ |
517 """ |
469 for namespace in self.__helpEngine.registeredDocumentations(): |
518 for namespace in self.__helpEngine.registeredDocumentations(): |
470 docFile = self.__helpEngine.documentationFileName(namespace) |
519 docFile = self.__helpEngine.documentationFileName(namespace) |
471 if not os.path.exists(docFile): |
520 if not os.path.exists(docFile): |
472 self.__helpEngine.unregisterDocumentation(namespace) |
521 self.__helpEngine.unregisterDocumentation(namespace) |
|
522 |
|
523 @pyqtSlot() |
|
524 def __lookForNewDocumentation(self): |
|
525 """ |
|
526 Private slot to look for new documentation to be loaded into the |
|
527 help database. |
|
528 """ |
|
529 from WebBrowser.QtHelp.HelpDocsInstaller import HelpDocsInstaller |
|
530 self.__helpInstaller = HelpDocsInstaller( |
|
531 self.__helpEngine.collectionFile()) |
|
532 self.__helpInstaller.errorMessage.connect( |
|
533 self.__showInstallationError) |
|
534 self.__helpInstaller.docsInstalled.connect(self.__docsInstalled) |
|
535 |
|
536 self.__ui.statusBar().showMessage( |
|
537 self.tr("Looking for Documentation...")) |
|
538 self.__helpInstaller.installDocs() |
|
539 |
|
540 @pyqtSlot(str) |
|
541 def __showInstallationError(self, message): |
|
542 """ |
|
543 Private slot to show installation errors. |
|
544 |
|
545 @param message message to be shown |
|
546 @type str |
|
547 """ |
|
548 EricMessageBox.warning( |
|
549 self, |
|
550 self.tr("eric Web Browser"), |
|
551 message) |
|
552 |
|
553 @pyqtSlot(bool) |
|
554 def __docsInstalled(self, installed): |
|
555 """ |
|
556 Private slot handling the end of documentation installation. |
|
557 |
|
558 @param installed flag indicating that documents were installed |
|
559 @type bool |
|
560 """ |
|
561 self.__ui.statusBar().clearMessage() |
|
562 self.__helpEngine.setupData() |
473 |
563 |
474 @pyqtSlot() |
564 @pyqtSlot() |
475 def __manageQtHelpDocuments(self): |
565 def __manageQtHelpDocuments(self): |
476 """ |
566 """ |
477 Private slot to manage the QtHelp documentation database. |
567 Private slot to manage the QtHelp documentation database. |
502 |
592 |
503 self.__actionsMenu.addAction(self.tr("Manage QtHelp Documents"), |
593 self.__actionsMenu.addAction(self.tr("Manage QtHelp Documents"), |
504 self.__manageQtHelpDocuments) |
594 self.__manageQtHelpDocuments) |
505 act = self.__actionsMenu.addAction(self.tr("Reindex Documentation"), |
595 act = self.__actionsMenu.addAction(self.tr("Reindex Documentation"), |
506 self.__reindexDocumentation) |
596 self.__reindexDocumentation) |
507 ## act.triggered.connect(self.__searchEngine.reindexDocumentation) |
597 act.triggered.connect(self.__helpSearchEngine.reindexDocumentation) |
508 |
598 |
509 self.__actionsButton.setMenu(self.__actionsMenu) |
599 self.__actionsButton.setMenu(self.__actionsMenu) |
510 |
600 |
511 ####################################################################### |
601 ####################################################################### |
512 ## Navigation related methods below |
602 ## Navigation related methods below |
646 Private slot to reset the zoom level. |
736 Private slot to reset the zoom level. |
647 """ |
737 """ |
648 cv = self.currentViewer() |
738 cv = self.currentViewer() |
649 if cv: |
739 if cv: |
650 cv.resetScale() |
740 cv.resetScale() |
|
741 |
|
742 ####################################################################### |
|
743 ## QtHelp Search related methods below |
|
744 ####################################################################### |
|
745 |
|
746 def __initIndexingProgress(self): |
|
747 """ |
|
748 Private method to initialize the help documents indexing progress |
|
749 widget. |
|
750 |
|
751 @return reference to the generated widget |
|
752 @rtype QWidget |
|
753 """ |
|
754 progressWidget = QWidget(self) |
|
755 layout = QHBoxLayout(progressWidget) |
|
756 layout.setContentsMargins(0, 0, 0, 0) |
|
757 |
|
758 label = QLabel(self.tr("Updating search index")) |
|
759 layout.addWidget(label) |
|
760 |
|
761 progressBar = QProgressBar() |
|
762 progressBar.setRange(0, 0) |
|
763 progressBar.setTextVisible(False) |
|
764 progressBar.setFixedHeight(16) |
|
765 layout.addWidget(progressBar) |
|
766 |
|
767 return progressWidget |
|
768 |
|
769 @pyqtSlot() |
|
770 def __indexingStarted(self): |
|
771 """ |
|
772 Private slot handling the start of the indexing process. |
|
773 """ |
|
774 self.__indexing = True |
|
775 self.__indexingProgressWidget.show() |
|
776 |
|
777 @pyqtSlot() |
|
778 def __indexingFinished(self): |
|
779 """ |
|
780 Private slot handling the end of the indexing process. |
|
781 """ |
|
782 self.__indexingProgressWidget.hide() |
|
783 self.__indexing = False |
|
784 |
|
785 @pyqtSlot(str) |
|
786 def searchQtHelp(self, searchExpression): |
|
787 """ |
|
788 Public slot to search for a given search expression. |
|
789 |
|
790 @param searchExpression expression to search for |
|
791 @type str |
|
792 """ |
|
793 if searchExpression: |
|
794 if self.__indexing: |
|
795 # Try again a second later |
|
796 QTimer.singleShot( |
|
797 1000, |
|
798 lambda: self.searchQtHelp(searchExpression) |
|
799 ) |
|
800 else: |
|
801 self.__helpSearchButton.setChecked(True) |
|
802 self.__helpSearchEngine.search(searchExpression) |
|
803 |
|
804 ####################################################################### |
|
805 ## QtHelp filter related methods below |
|
806 ####################################################################### |
|
807 |
|
808 def __initFilterWidget(self): |
|
809 """ |
|
810 Private method to initialize the filter selection widget. |
|
811 |
|
812 @return reference to the generated widget |
|
813 @rtype QWidget |
|
814 """ |
|
815 filterWidget = QWidget() |
|
816 layout = QHBoxLayout(filterWidget) |
|
817 layout.setContentsMargins(0, 0, 0, 0) |
|
818 |
|
819 label = QLabel(self.tr("Filtered by: ")) |
|
820 layout.addWidget(label) |
|
821 |
|
822 self.__helpFilterCombo = QComboBox() |
|
823 comboWidth = QFontMetrics(QFont()).horizontalAdvance( |
|
824 "ComboBoxWithEnoughWidth") |
|
825 self.__helpFilterCombo.setMinimumWidth(comboWidth) |
|
826 layout.addWidget(self.__helpFilterCombo) |
|
827 |
|
828 self.__helpEngine.setupFinished.connect(self.__setupFilterCombo) |
|
829 self.__helpFilterCombo.currentIndexChanged.connect( |
|
830 self.__filterQtHelpDocumentation) |
|
831 |
|
832 self.__setupFilterCombo() |
|
833 |
|
834 return filterWidget |
|
835 |
|
836 @pyqtSlot() |
|
837 def __setupFilterCombo(self): |
|
838 """ |
|
839 Private slot to setup the filter combo box. |
|
840 """ |
|
841 activeFilter = self.__helpFilterCombo.currentText() |
|
842 if not activeFilter: |
|
843 activeFilter = self.__helpEngine.filterEngine().activeFilter() |
|
844 if not activeFilter: |
|
845 activeFilter = self.tr("Unfiltered") |
|
846 allFilters = self.__helpEngine.filterEngine().filters() |
|
847 |
|
848 blocked = self.__helpFilterCombo.blockSignals(True) |
|
849 self.__helpFilterCombo.clear() |
|
850 self.__helpFilterCombo.addItem(self.tr("Unfiltered")) |
|
851 if allFilters: |
|
852 self.__helpFilterCombo.insertSeparator(1) |
|
853 for helpFilter in sorted(allFilters): |
|
854 self.__helpFilterCombo.addItem(helpFilter, helpFilter) |
|
855 self.__helpFilterCombo.blockSignals(blocked) |
|
856 |
|
857 self.__helpFilterCombo.setCurrentText(activeFilter) |
|
858 |
|
859 @pyqtSlot(int) |
|
860 def __filterQtHelpDocumentation(self, index): |
|
861 """ |
|
862 Private slot to filter the QtHelp documentation. |
|
863 |
|
864 @param index index of the selected QtHelp documentation filter |
|
865 @type int |
|
866 """ |
|
867 if self.__helpEngine: |
|
868 helpFilter = self.__helpFilterCombo.itemData(index) |
|
869 self.__helpEngine.filterEngine().setActiveFilter(helpFilter) |