eric7/HelpViewer/HelpViewerWidget.py

branch
eric7
changeset 8685
b0669ce1066d
parent 8683
e8a907801549
child 8686
af2ee3a303ac
equal deleted inserted replaced
8683:e8a907801549 8685:b0669ce1066d
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
24 import Preferences 25 import Preferences
25 26
26 from .OpenPagesWidget import OpenPagesWidget 27 from .OpenPagesWidget import OpenPagesWidget
27 28
28 from WebBrowser.QtHelp.HelpTocWidget import HelpTocWidget 29 from WebBrowser.QtHelp.HelpTocWidget import HelpTocWidget
30 from WebBrowser.QtHelp.HelpIndexWidget import HelpIndexWidget
31 from WebBrowser.QtHelp.HelpSearchWidget import HelpSearchWidget
29 32
30 33
31 class HelpViewerWidget(QWidget): 34 class HelpViewerWidget(QWidget):
32 """ 35 """
33 Class implementing an embedded viewer for QtHelp and local HTML files. 36 Class implementing an embedded viewer for QtHelp and local HTML files.
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
200 212
201 self.__initActionsMenu() 213 self.__initActionsMenu()
202 214
203 self.addPage() 215 self.addPage()
204 self.__checkActionButtons() 216 self.__checkActionButtons()
217
218 QTimer.singleShot(50, self.__lookForNewDocumentation)
205 219
206 def __addNavigationButton(self, iconName, toolTip): 220 def __addNavigationButton(self, iconName, toolTip):
207 """ 221 """
208 Private method to create and add a navigation button. 222 Private method to create and add a navigation button.
209 223
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 """
288 urlStr = self.__helpSelector.currentData() 337 urlStr = self.__helpSelector.currentData()
289 if urlStr: 338 if urlStr:
290 url = QUrl(urlStr) 339 url = QUrl(urlStr)
291 self.currentViewer().setUrl(url) 340 self.currentViewer().setUrl(url)
292 341
293 def searchQtHelp(self, searchExpression):
294 """
295 Public method to search for a given search expression.
296
297 @param searchExpression expression to search for
298 @type str
299 """
300 # TODO: not yet implemented
301
302 def activate(self, searchWord=None): 342 def activate(self, searchWord=None):
303 """ 343 """
304 Public method to activate the widget and search for a given word. 344 Public method to activate the widget and search for a given word.
305 345
306 @param searchWord word to search for (defaults to None) 346 @param searchWord word to search for (defaults to None)
310 if cv: 350 if cv:
311 cv.setFocus(Qt.FocusReason.OtherFocusReason) 351 cv.setFocus(Qt.FocusReason.OtherFocusReason)
312 352
313 if searchWord: 353 if searchWord:
314 self.searchQtHelp(searchWord) 354 self.searchQtHelp(searchWord)
355
356 def shutdown(self):
357 """
358 Public method to perform shut down actions.
359 """
360 self.__helpSearchEngine.cancelIndexing()
361 self.__helpSearchEngine.cancelSearching()
362
363 self.__helpInstaller.stop()
315 364
316 @pyqtSlot() 365 @pyqtSlot()
317 def __openFile(self): 366 def __openFile(self):
318 """ 367 """
319 Private slot to open a local help file (*.html). 368 Private slot to open a local help file (*.html).
430 """ 479 """
431 self.__helpEngine = QHelpEngine( 480 self.__helpEngine = QHelpEngine(
432 self.__getQtHelpCollectionFileName(), 481 self.__getQtHelpCollectionFileName(),
433 self) 482 self)
434 self.__helpEngine.setReadOnly(False) 483 self.__helpEngine.setReadOnly(False)
484 self.__helpEngine.setUsesFilterEngine(True)
435 self.__helpEngine.setupData() 485 self.__helpEngine.setupData()
436 self.__helpEngine.setUsesFilterEngine(True)
437 self.__removeOldDocumentation() 486 self.__removeOldDocumentation()
438 self.__helpEngine.warning.connect(self.__warning) 487 self.__helpEngine.warning.connect(self.__warning)
439 488
440 def __getQtHelpCollectionFileName(cls): 489 def __getQtHelpCollectionFileName(cls):
441 """ 490 """
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)

eric ide

mercurial