Wed, 18 Jan 2023 16:38:29 +0100
PDF Viewer
- added the search actions and a 'Full Screen' action to the menus
src/eric7/PdfViewer/PdfSearchWidget.py | file | annotate | diff | comparison | revisions | |
src/eric7/PdfViewer/PdfViewerWindow.py | file | annotate | diff | comparison | revisions |
--- a/src/eric7/PdfViewer/PdfSearchWidget.py Wed Jan 18 16:37:08 2023 +0100 +++ b/src/eric7/PdfViewer/PdfSearchWidget.py Wed Jan 18 16:38:29 2023 +0100 @@ -24,9 +24,15 @@ @signal rowCountChanged() emitted to indicate a change of the number of items + @signal searchNextAvailable(bool) emitted to indicate the availability of + search results after the current one + @signal searchPrevAvailable(bool) emitted to indicate the availability of + search results before the current one """ rowCountChanged = pyqtSignal() + searchNextAvailable = pyqtSignal(bool) + searchPrevAvailable = pyqtSignal(bool) def __init__(self, parent=None): """ @@ -48,6 +54,8 @@ self.__searchModel.modelReset.connect(self.__clear) self.__searchModel.rowsInserted.connect(self.__rowsInserted) + self.currentItemChanged.connect(self.__handleCurrentItemChanged) + def setSearchString(self, searchString): """ Public method to set the search string. @@ -90,7 +98,10 @@ Private slot to clear the list of search results. """ self.clear() + self.rowCountChanged.emit() + self.searchNextAvailable.emit(False) + self.searchPrevAvailable.emit(False) @pyqtSlot(QModelIndex, int, int) def __rowsInserted(self, parent, first, last): @@ -143,6 +154,7 @@ self.resizeColumnToContents(column) self.rowCountChanged.emit() + self.searchNextAvailable.emit(True) def rowCount(self): """ @@ -203,13 +215,34 @@ row = self.indexOfTopLevelItem(item) return self.__searchModel.resultAtIndex(row) + @pyqtSlot() + def __handleCurrentItemChanged(self): + """ + Private slot to handle a change of the current item. + """ + hasSearchResults = bool(self.topLevelItemCount()) + currentRow = self.currentRow() + self.searchPrevAvailable.emit(hasSearchResults and currentRow > 0) + self.searchNextAvailable.emit( + hasSearchResults and currentRow < self.topLevelItemCount() - 1 + ) + class PdfSearchWidget(QWidget): """ Class implementing a Search widget. + + @signal searchResultAktivated(QPdfLink) emitted to send the activated search + result link + @signal searchNextAvailable(bool) emitted to indicate the availability of + search results after the current one + @signal searchPrevAvailable(bool) emitted to indicate the availability of + search results before the current one """ searchResultActivated = pyqtSignal(QPdfLink) + searchNextAvailable = pyqtSignal(bool) + searchPrevAvailable = pyqtSignal(bool) def __init__(self, document, parent=None): """ @@ -271,12 +304,16 @@ document.statusChanged.connect(self.__handleDocumentStatus) self.__searchEdit.returnPressed.connect(self.__search) self.__searchEdit.textChanged.connect(self.__searchTextChanged) - self.__resultsWidget.rowCountChanged.connect(self.__updateButtons) - self.__resultsWidget.currentItemChanged.connect( - self.__updateButtons + self.__resultsWidget.searchNextAvailable.connect(self.searchNextAvailable) + self.__resultsWidget.searchPrevAvailable.connect(self.searchPrevAvailable) + self.__resultsWidget.searchNextAvailable.connect( + self.__findNextButton.setEnabled ) - self.__findNextButton.clicked.connect(self.__nextResult) - self.__findPrevButton.clicked.connect(self.__previousResult) + self.__resultsWidget.searchPrevAvailable.connect( + self.__findPrevButton.setEnabled + ) + self.__findNextButton.clicked.connect(self.nextResult) + self.__findPrevButton.clicked.connect(self.previousResult) @pyqtSlot(QPdfDocument.Status) def __handleDocumentStatus(self, status): @@ -313,18 +350,6 @@ searchString = self.__searchEdit.text() self.__resultsWidget.setSearchString(searchString) - @pyqtSlot() - def __updateButtons(self): - """ - Private slot to update the state of the navigation buttons. - """ - hasSearchResults = bool(self.__resultsWidget.rowCount()) - currentRow = self.__resultsWidget.currentRow() - self.__findPrevButton.setEnabled(hasSearchResults and currentRow > 0) - self.__findNextButton.setEnabled( - hasSearchResults and currentRow < self.__resultsWidget.rowCount() - 2 - ) - @pyqtSlot(QTreeWidgetItem) def __entrySelected(self, item): """ @@ -337,23 +362,31 @@ self.searchResultActivated.emit(link) @pyqtSlot() - def __nextResult(self): + def nextResult(self): """ - Private slot to activate the next result. + Public slot to activate the next result. """ row = self.__resultsWidget.currentRow() - if row < self.__resultsWidget.rowCount() - 2: + if row < self.__resultsWidget.rowCount() - 1: nextItem = self.__resultsWidget.topLevelItem(row + 1) self.__resultsWidget.setCurrentItem(nextItem) self.__entrySelected(nextItem) @pyqtSlot() - def __previousResult(self): + def previousResult(self): """ - Private slot to activate the previous result. + Public slot to activate the previous result. """ row = self.__resultsWidget.currentRow() if row > 0: prevItem = self.__resultsWidget.topLevelItem(row - 1) self.__resultsWidget.setCurrentItem(prevItem) self.__entrySelected(prevItem) + + @pyqtSlot() + def activateSearch(self): + """ + Public slot to 'activate' a search. + """ + self.__searchEdit.setFocus(Qt.FocusReason.OtherFocusReason) + self.__searchEdit.selectAll()
--- a/src/eric7/PdfViewer/PdfViewerWindow.py Wed Jan 18 16:37:08 2023 +0100 +++ b/src/eric7/PdfViewer/PdfViewerWindow.py Wed Jan 18 16:38:29 2023 +0100 @@ -18,7 +18,8 @@ from PyQt6.QtPdf import QPdfDocument, QPdfLink from PyQt6.QtPdfWidgets import QPdfView from PyQt6.QtWidgets import ( - QWhatsThis, QMenu, QTabWidget, QSplitter, QToolBar, QDialog + QWhatsThis, QMenu, QTabWidget, QSplitter, QToolBar, QDialog, QInputDialog, + QLineEdit ) from eric7 import Preferences @@ -28,7 +29,7 @@ from eric7.EricWidgets.EricMainWindow import EricMainWindow from eric7.EricWidgets.EricStretchableSpacer import EricStretchableSpacer from eric7.Globals import recentNamePdfFiles -from eric7.SystemUtilities import FileSystemUtilities +from eric7.SystemUtilities import FileSystemUtilities, OSUtilities from .PdfPageSelector import PdfPageSelector from .PdfZoomSelector import PdfZoomSelector @@ -147,7 +148,10 @@ self.__view.zoomModeChanged.connect(self.__zoomSelector.setZoomMode) self.__tocWidget.topicActivated.connect(self.__tocActivated) + self.__searchWidget.searchResultActivated.connect(self.__handleSearchResult) + self.__searchWidget.searchNextAvailable.connect(self.searchNextAct.setEnabled) + self.__searchWidget.searchPrevAvailable.connect(self.searchPrevAct.setEnabled) PdfViewerWindow.windows.append(self) @@ -418,7 +422,23 @@ """ Private method to define the view related user interface actions. """ - # TODO: add Fullscreen action + self.fullScreenAct = EricAction( + self.tr("Full Screen"), + EricPixmapCache.getIcon("windowFullscreen"), + self.tr("&Full Screen"), + 0, + 0, + self, + "pdfviewer_view_full_screen", + ) + if OSUtilities.isMacPlatform(): + self.fullScreenAct.setShortcut(QKeySequence(self.tr("Meta+Ctrl+F"))) + else: + self.fullScreenAct.setShortcut(QKeySequence(self.tr("F11"))) + self.fullScreenAct.setCheckable(True) + self.fullScreenAct.triggered.connect(self.__toggleFullScreen) + self.__actions.append(self.fullScreenAct) + self.zoomInAct = EricAction( self.tr("Zoom in"), EricPixmapCache.getIcon("zoomIn"), @@ -508,6 +528,45 @@ self.copyAllPageAct.triggered.connect(self.__copyAllTextOfPage) self.__actions.append(self.copyAllPageAct) + self.searchAct = EricAction( + self.tr("Search"), + EricPixmapCache.getIcon("find"), + self.tr("&Search..."), + QKeySequence(self.tr("Ctrl+F", "Edit|Search")), + 0, + self, + "pdfviewer_edit_search", + ) + self.searchAct.triggered.connect(self.__search) + self.__actions.append(self.searchAct) + + self.searchNextAct = EricAction( + self.tr("Search Next"), + EricPixmapCache.getIcon("findNext"), + self.tr("Search &Next"), + QKeySequence(self.tr("F3", "Edit|Search Next")), + 0, + self, + "pdfviewer_edit_searchnext", + ) + self.searchNextAct.triggered.connect(self.__searchWidget.nextResult) + self.__actions.append(self.searchNextAct) + + self.searchPrevAct = EricAction( + self.tr("Search Previous"), + EricPixmapCache.getIcon("findPrev"), + self.tr("Search &Previous"), + QKeySequence(self.tr("Shift+F3", "Edit|Search Previous")), + 0, + self, + "pdfviewer_edit_searchprevious", + ) + self.searchPrevAct.triggered.connect(self.__searchWidget.previousResult) + self.__actions.append(self.searchPrevAct) + + self.searchNextAct.setEnabled(False) + self.searchPrevAct.setEnabled(False) + def __initSettingsActions(self): """ Private method to create the Settings actions. @@ -628,6 +687,10 @@ self.zoomWholePageAct.setEnabled(ready) self.__zoomSelector.setEnabled(ready) + self.copyAllAct.setEnabled(ready) + self.copyAllPageAct.setEnabled(ready) + self.searchAct.setEnabled(ready) + def __initMenus(self): """ Private method to create the menus. @@ -658,6 +721,8 @@ menu = mb.addMenu(self.tr("&View")) menu.setTearOffEnabled(True) + menu.addAction(self.fullScreenAct) + menu.addSeparator() menu.addAction(self.zoomInAct) menu.addAction(self.zoomOutAct) menu.addAction(self.zoomResetAct) @@ -679,6 +744,10 @@ menu.addAction(self.copyAllAct) menu.addSeparator() menu.addAction(self.copyAllPageAct) + menu.addSeparator() + menu.addAction(self.searchAct) + menu.addAction(self.searchNextAct) + menu.addAction(self.searchPrevAct) menu = mb.addMenu(self.tr("&Go To")) menu.setTearOffEnabled(True) @@ -774,6 +843,8 @@ self.__saveRecent() + self.__documentInfoWidget.setDocument(None) + evt.accept() self.viewerClosed.emit() @@ -855,9 +926,21 @@ @param fileName path of the PDF file to load @type str """ - # TODO: if error is QPdfDocument.Error.IncorrectPassword ask for PW and try - # again until cancelled - err = self.__pdfDocument.load(fileName) + canceled = False + err = QPdfDocument.Error.IncorrectPassword + while not canceled and err == QPdfDocument.Error.IncorrectPassword: + err = self.__pdfDocument.load(fileName) + if err == QPdfDocument.Error.IncorrectPassword: + password, ok = QInputDialog.getText( + self, + self.tr("Load PDF File"), + self.tr("Enter password to read the document:"), + QLineEdit.EchoMode.Password, + ) + if ok: + self.__pdfDocument.setPassword(password) + else: + canceled = True if err != QPdfDocument.Error.None_: EricMessageBox.critical( self, @@ -996,6 +1079,14 @@ """ self.__view.pageNavigator().jump(link) + @pyqtSlot() + def __search(self): + """ + Private slot to initiate a search. + """ + self.__info.setCurrentWidget(self.__searchWidget) + self.__searchWidget.activateSearch() + def __setCurrentFile(self, fileName): """ Private method to register the file name of the current file. @@ -1204,6 +1295,19 @@ """ self.__view.pageNavigator().forward() + @pyqtSlot(bool) + def __toggleFullScreen(self, on): + """ + Private slot to toggle the full screen mode. + + @param on flag indicating to activate full screen mode + @type bool + """ + if on: + self.showFullScreen() + else: + self.showNormal() + @pyqtSlot() def __zoomIn(self): """