--- a/src/eric7/PdfViewer/PdfViewerWindow.py Sat Jan 14 18:25:26 2023 +0100 +++ b/src/eric7/PdfViewer/PdfViewerWindow.py Sun Jan 15 17:41:35 2023 +0100 @@ -8,12 +8,11 @@ """ import contextlib -import math import os import pathlib from PyQt6.QtCore import Qt, pyqtSignal, QSize, pyqtSlot, QPointF -from PyQt6.QtGui import QAction, QKeySequence +from PyQt6.QtGui import QAction, QKeySequence, QGuiApplication, QActionGroup from PyQt6.QtPdf import QPdfDocument from PyQt6.QtPdfWidgets import QPdfView from PyQt6.QtWidgets import ( @@ -33,9 +32,6 @@ from .PdfZoomSelector import PdfZoomSelector -# TODO: make this an eric widget - - class PdfViewerWindow(EricMainWindow): """ Class implementing the PDF viewer main window. @@ -49,8 +45,6 @@ maxMenuFilePathLen = 75 - ZoomMultiplier = math.sqrt(2.0) - def __init__(self, fileName="", parent=None, fromEric=False, project=None): """ Constructor @@ -71,6 +65,10 @@ self.__fromEric = fromEric self.setWindowIcon(EricPixmapCache.getIcon("ericPdf")) + self.__screenResolution = ( + QGuiApplication.primaryScreen().logicalDotsPerInch() / 72.0 + ) + if not self.__fromEric: self.setStyle(Preferences.getUI("Style"), Preferences.getUI("StyleSheet")) @@ -81,7 +79,6 @@ self.__cw.addWidget(self.__info) self.__view = QPdfView(self) self.__view.setDocument(self.__pdfDocument) - self.__view.setPageMode(QPdfView.PageMode.MultiPage) self.__cw.addWidget(self.__view) self.setCentralWidget(self.__cw) @@ -95,10 +92,6 @@ self.__pageSelector.gotoPage.connect(self.__gotoPage) self.__zoomSelector = PdfZoomSelector(self) - self.__zoomSelector.zoomModeChanged.connect(self.__view.setZoomMode) - ##self.__zoomSelector.zoomModeChanged.connect(self.__setFocusToView) - self.__zoomSelector.zoomFactorChanged.connect(self.__view.setZoomFactor) - ##self.__zoomSelector.zoomFactorChanged.connect(self.__setFocusToView) self.__zoomSelector.reset() g = Preferences.getGeometry("PdfViewerGeometry") @@ -114,13 +107,20 @@ self.__initToolbars() self.__createStatusBar() + self.__setDisplayMode() # needs to be done after actions have been created + self.__view.pageNavigator().backAvailableChanged.connect( self.backwardAct.setEnabled ) self.__view.pageNavigator().forwardAvailableChanged.connect( self.forwardAct.setEnabled ) + + self.__zoomSelector.zoomModeChanged.connect(self.__view.setZoomMode) + self.__zoomSelector.zoomModeChanged.connect(self.__zoomModeChanged) + self.__zoomSelector.zoomFactorChanged.connect(self.__view.setZoomFactor) self.__view.zoomFactorChanged.connect(self.__zoomSelector.setZoomFactor) + self.__view.zoomModeChanged.connect(self.__zoomSelector.setZoomMode) PdfViewerWindow.windows.append(self) @@ -390,8 +390,6 @@ """ Private method to define the view related user interface actions. """ - # Page Width (checkable, exclusive) - # Whole Page (checkable, exclusive) self.zoomInAct = EricAction( self.tr("Zoom in"), EricPixmapCache.getIcon("zoomIn"), @@ -428,6 +426,47 @@ self.zoomResetAct.triggered.connect(self.__zoomReset) self.__actions.append(self.zoomResetAct) + self.zoomPageWidthAct = EricAction( + self.tr("Page Width"), + EricPixmapCache.getIcon("zoomFitWidth"), + self.tr("Page &Width"), + 0, + 0, + self, + "pdfviewer_view_zoompagewidth", + ) + self.zoomPageWidthAct.triggered.connect(self.__zoomPageWidth) + self.zoomPageWidthAct.setCheckable(True) + self.__actions.append(self.zoomPageWidthAct) + + self.zoomWholePageAct = EricAction( + self.tr("Whole Page"), + EricPixmapCache.getIcon("zoomFitPage"), + self.tr("Whole &Page"), + 0, + 0, + self, + "pdfviewer_view_zoomwholePage", + ) + self.zoomWholePageAct.triggered.connect(self.__zoomWholePage) + self.zoomWholePageAct.setCheckable(True) + self.__actions.append(self.zoomWholePageAct) + + ##self.__displayModeActGrp = QActionGroup(self) +## + ##self.displayModeSingleAct = EricAction( + ##self.tr("Whole Page"), + ##EricPixmapCache.getIcon("zoomFitPage"), + ##self.tr("Whole &Page"), + ##0, + ##0, + ##self, + ##"pdfviewer_view_zoomwholePage", + ##) + ##self.displayModeSingleAct.triggered.connect(self.__zoomWholePage) + ##self.displayModeSingleAct.setCheckable(True) + ##self.__actions.append(self.displayModeSingleAct) + def __initHelpActions(self): """ Private method to create the Help actions. @@ -515,6 +554,8 @@ self.zoomInAct.setEnabled(ready) self.zoomOutAct.setEnabled(ready) self.zoomResetAct.setEnabled(ready) + self.zoomPageWidthAct.setEnabled(ready) + self.zoomWholePageAct.setEnabled(ready) self.__zoomSelector.setEnabled(ready) # TODO: not yet implemented @@ -562,7 +603,18 @@ menu.addAction(self.zoomInAct) menu.addAction(self.zoomOutAct) menu.addAction(self.zoomResetAct) - # TODO: not yet implemented + menu.addAction(self.zoomPageWidthAct) + menu.addAction(self.zoomWholePageAct) + menu.addSeparator() + modeMenu = menu.addMenu(self.tr("Display Mode")) + self.__singlePageAct = modeMenu.addAction(self.tr("Single Page")) + self.__singlePageAct.setCheckable(True) + self.__continuousPageAct = modeMenu.addAction(self.tr("Continuous")) + self.__continuousPageAct.setCheckable(True) + self.__displayModeActGrp = QActionGroup(self) + self.__displayModeActGrp.addAction(self.__singlePageAct) + self.__displayModeActGrp.addAction(self.__continuousPageAct) + modeMenu.triggered.connect(self.__displayModeSelected) menu = mb.addMenu(self.tr("&Go To")) menu.setTearOffEnabled(True) @@ -617,6 +669,8 @@ mainToolBar.addWidget(self.__zoomSelector) mainToolBar.addAction(self.zoomInAct) mainToolBar.addAction(self.zoomResetAct) + mainToolBar.addAction(self.zoomPageWidthAct) + mainToolBar.addAction(self.zoomWholePageAct) self.addToolBar(mainToolBar) self.addToolBarBreak() @@ -1033,29 +1087,51 @@ """ self.__view.pageNavigator().forward() - def __calculateZoomFactor(self): - if self.__view.ZoomMode == QPdfView.ZoomMode.FitToWidth: - pass + def __zoomInOut(self, zoomIn): + """ + Private method to zoom into or out of the view. + + @param zoomIn flag indicating to zoom into the view + @type bool + """ + zoomFactor = self.__zoomFactorForMode(self.__view.zoomMode()) + + factors = list(PdfZoomSelector.ZoomValues) + factors.append(self.__zoomFactorForMode(QPdfView.ZoomMode.FitInView)) + factors.append(self.__zoomFactorForMode(QPdfView.ZoomMode.FitToWidth)) + if zoomIn: + factors.sort() + if zoomFactor >= factors[-1]: + return + newIndex = next(x for x, val in enumerate(factors) if val > zoomFactor) else: - return self.__view.zoomFactor() - + factors.sort(reverse=True) + if zoomFactor <= factors[-1]: + return + newIndex = next(x for x, val in enumerate(factors) if val < zoomFactor) + newFactor = factors[newIndex] + if newFactor == self.__zoomFactorForMode(QPdfView.ZoomMode.FitInView): + self.__zoomWholePage(True) + elif newFactor == self.__zoomFactorForMode(QPdfView.ZoomMode.FitToWidth): + self.__zoomPageWidth(True) + else: + self.__view.setZoomFactor(newFactor) + self.__zoomSelector.setZoomFactor(newFactor) + self.__zoomModeChanged(QPdfView.ZoomMode.Custom) + @pyqtSlot() def __zoomIn(self): """ Private slot to zoom into the view. """ - self.__view.setZoomFactor( - self.__view.zoomFactor() * PdfViewerWindow.ZoomMultiplier - ) + self.__zoomInOut(True) @pyqtSlot() def __zoomOut(self): """ Private slot to zoom out of the view. """ - self.__view.setZoomFactor( - self.__view.zoomFactor() / PdfViewerWindow.ZoomMultiplier - ) + self.__zoomInOut(False) @pyqtSlot() def __zoomReset(self): @@ -1063,6 +1139,82 @@ Private slot to reset the zoom factor of the view. """ self.__view.setZoomFactor(1.0) + self.__zoomSelector.setZoomFactor(1.0) + self.__zoomModeChanged(QPdfView.ZoomMode.Custom) + + @pyqtSlot(bool) + def __zoomPageWidth(self, checked): + """ + Private slot to fit the page width. + + @param checked flag indicating the check state + @type bool + """ + if checked: + self.__view.setZoomMode(QPdfView.ZoomMode.FitToWidth) + self.zoomWholePageAct.setChecked(False) + + @pyqtSlot(bool) + def __zoomWholePage(self, checked): + """ + Private slot to fit the page width. + + @param checked flag indicating the check state + @type bool + """ + if checked: + self.__view.setZoomMode(QPdfView.ZoomMode.FitInView) + self.zoomPageWidthAct.setChecked(False) + + @pyqtSlot(QPdfView.ZoomMode) + def __zoomModeChanged(self, zoomMode): + """ + Private slot to handle a change of the zoom mode. + + @param zoomMode new zoom mode + @type QPdfView.ZoomMode + """ + self.zoomWholePageAct.setChecked(zoomMode == QPdfView.ZoomMode.FitInView) + self.zoomPageWidthAct.setChecked(zoomMode == QPdfView.ZoomMode.FitToWidth) + + def __zoomFactorForMode(self, zoomMode): + """ + Private method to calculate the zoom factor iaw. the current zoom mode. + + @param zoomMode zoom mode to get the zoom factor for + @type QPdfView.ZoomMode + @return zoom factor + @rtype float + """ + if zoomMode == QPdfView.ZoomMode.Custom: + return self.__view.zoomFactor() + else: + viewport = self.__view.viewport() + curPage = self.__view.pageNavigator().currentPage() + margins = self.__view.documentMargins() + if zoomMode == QPdfView.ZoomMode.FitToWidth: + pageSize = ( + self.__pdfDocument.pagePointSize(curPage) * self.__screenResolution + ).toSize() + factor = ( + viewport.width() - margins.left() - margins.right() + ) / pageSize.width() + pageSize *= factor + else: + # QPdfView.ZoomMode.FitInView + viewportSize = viewport.size() + QSize( + -margins.left() - margins.right(), -self.__view.pageSpacing() + ) + pageSize = ( + self.__pdfDocument.pagePointSize(curPage) * self.__screenResolution + ).toSize() + pageSize = pageSize.scaled( + viewportSize, Qt.AspectRatioMode.KeepAspectRatio + ) + zoomFactor = pageSize.width() / ( + self.__pdfDocument.pagePointSize(curPage) * self.__screenResolution + ).width() + return zoomFactor @pyqtSlot() def __setFocusToView(self): @@ -1070,3 +1222,29 @@ Private slot to set the focus to the PDF document view. """ self.__view.setFocus(Qt.FocusReason.OtherFocusReason) + + @pyqtSlot(QAction) + def __displayModeSelected(self, act): + """ + Private slot to handle the selection of a display mode. + + @param act reference to the triggering action + @type QAction + """ + if act is self.__singlePageAct: + Preferences.setPdfViewer("PdfViewerDisplayMode", "single") + else: + Preferences.setPdfViewer("PdfViewerDisplayMode", "continuous") + self.__setDisplayMode() + + def __setDisplayMode(self): + """ + Private method to set the display mode iaw. configuration. + """ + if Preferences.getPdfViewer("PdfViewerDisplayMode") == "single": + self.__view.setPageMode(QPdfView.PageMode.SinglePage) + self.__singlePageAct.setChecked(True) + else: + self.__view.setPageMode(QPdfView.PageMode.MultiPage) + self.__continuousPageAct.setChecked(True) + return