src/eric7/PdfViewer/PdfViewerWindow.py

branch
pdf_viewer
changeset 9700
b74a13a382a8
parent 9699
92dcd34d54e4
child 9702
7c973954919d
--- 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 

eric ide

mercurial