PDF Viewer pdf_viewer

Fri, 20 Jan 2023 15:05:59 +0100

author
Detlev Offenbach <detlev@die-offenbachs.de>
date
Fri, 20 Jan 2023 15:05:59 +0100
branch
pdf_viewer
changeset 9707
717f95e35ca8
parent 9706
c0ff0b4d5657
child 9708
8956a005f478

PDF Viewer
- added highlighting of the search results in the document
- added selection of text with mouse
- added copy of selected text

src/eric7/PdfViewer/PdfSearchWidget.py file | annotate | diff | comparison | revisions
src/eric7/PdfViewer/PdfView.py file | annotate | diff | comparison | revisions
src/eric7/PdfViewer/PdfViewerWindow.py file | annotate | diff | comparison | revisions
src/eric7/Preferences/__init__.py file | annotate | diff | comparison | revisions
--- a/src/eric7/PdfViewer/PdfSearchWidget.py	Wed Jan 18 16:38:29 2023 +0100
+++ b/src/eric7/PdfViewer/PdfSearchWidget.py	Fri Jan 20 15:05:59 2023 +0100
@@ -28,11 +28,16 @@
         search results after the current one
     @signal searchPrevAvailable(bool) emitted to indicate the availability of
         search results before the current one
+    @signal searchResult(QPdfLink) emitted to send the link of a search result
+    @signal searchCleared() emitted to indicate that the search results have been
+        cleared
     """
 
     rowCountChanged = pyqtSignal()
     searchNextAvailable = pyqtSignal(bool)
     searchPrevAvailable = pyqtSignal(bool)
+    searchResult = pyqtSignal(QPdfLink)
+    searchCleared = pyqtSignal()
 
     def __init__(self, parent=None):
         """
@@ -99,6 +104,7 @@
         """
         self.clear()
 
+        self.searchCleared.emit()
         self.rowCountChanged.emit()
         self.searchNextAvailable.emit(False)
         self.searchPrevAvailable.emit(False)
@@ -150,6 +156,9 @@
             )
             self.setItemWidget(itm, 1, resultLabel)
 
+            if Preferences.getPdfViewer("PdfSearchHighlightAll"):
+                self.searchResult.emit(self.__searchModel.resultAtIndex(row))
+
         for column in range(self.columnCount()):
             self.resizeColumnToContents(column)
 
@@ -238,11 +247,16 @@
         search results after the current one
     @signal searchPrevAvailable(bool) emitted to indicate the availability of
         search results before the current one
+    @signal searchResult(QPdfLink) emitted to send the link of a search result
+    @signal searchCleared() emitted to indicate that the search results have been
+        cleared
     """
 
     searchResultActivated = pyqtSignal(QPdfLink)
     searchNextAvailable = pyqtSignal(bool)
     searchPrevAvailable = pyqtSignal(bool)
+    searchResult = pyqtSignal(QPdfLink)
+    searchCleared = pyqtSignal()
 
     def __init__(self, document, parent=None):
         """
@@ -314,6 +328,8 @@
         )
         self.__findNextButton.clicked.connect(self.nextResult)
         self.__findPrevButton.clicked.connect(self.previousResult)
+        self.__resultsWidget.searchCleared.connect(self.searchCleared)
+        self.__resultsWidget.searchResult.connect(self.searchResult)
 
     @pyqtSlot(QPdfDocument.Status)
     def __handleDocumentStatus(self, status):
--- a/src/eric7/PdfViewer/PdfView.py	Wed Jan 18 16:38:29 2023 +0100
+++ b/src/eric7/PdfViewer/PdfView.py	Fri Jan 20 15:05:59 2023 +0100
@@ -7,18 +7,65 @@
 Module implementing a specialized PDF view class.
 """
 
-from PyQt6.QtCore import QSize, Qt, pyqtSlot, QEvent
-from PyQt6.QtGui import QGuiApplication
+import collections
+import enum
+
+from dataclasses import dataclass
+
+from PyQt6.QtCore import (
+    QSize, Qt, pyqtSlot, QEvent, QSizeF, QRect, QPoint, QPointF, QRectF,
+    pyqtSignal
+)
+from PyQt6.QtGui import QGuiApplication, QPainter, QColor, QPen
+from PyQt6.QtPdf import QPdfDocument, QPdfLink
 from PyQt6.QtPdfWidgets import QPdfView
+from PyQt6.QtWidgets import QRubberBand
 
 from .PdfZoomSelector import PdfZoomSelector
 
 
+class PdfMarkerType(enum.Enum):
+    """
+    Class defining the various marker types.
+    """
+
+    SearchResult = 0
+    Selection = 1
+
+
+@dataclass
+class PdfMarker:
+    """
+    Class defining the data structure for markers.
+    """
+
+    rectangle: QRectF
+    markerType: PdfMarkerType
+
+
+@dataclass
+class PdfMarkerGeometry:
+    """
+    Class defining the data structure for marker geometries.
+    """
+
+    rectangle: QRect
+    markerType: PdfMarkerType
+
+
 class PdfView(QPdfView):
     """
     Class implementing a specialized PDF view.
     """
 
+    MarkerColors = {
+        # merker type: (pen color, brush color)
+        PdfMarkerType.SearchResult: (QColor(255, 200, 0, 255), QColor(255, 200, 0, 64)),
+        PdfMarkerType.Selection: (QColor(0, 0, 255, 255), QColor(0, 0, 255, 64)),
+    }
+
+    selectionAvailable = pyqtSignal(bool)
+
     def __init__(self, parent):
         """
         Constructor
@@ -32,8 +79,34 @@
             QGuiApplication.primaryScreen().logicalDotsPerInch() / 72.0
         )
 
+        self.__documentViewport = QRect()
+        self.__documentSize = QSize()
+        self.__pageGeometries = {}
+        self.__markers = collections.defaultdict(list)
+        self.__markerGeometries = collections.defaultdict(list)
+        self.__rubberBand = None
+
+        self.pageModeChanged.connect(self.__calculateDocumentLayout)
+        self.zoomModeChanged.connect(self.__calculateDocumentLayout)
+        self.zoomFactorChanged.connect(self.__calculateDocumentLayout)
+        self.pageSpacingChanged.connect(self.__calculateDocumentLayout)
+        self.documentMarginsChanged.connect(self.__calculateDocumentLayout)
+
+        self.pageNavigator().currentPageChanged.connect(self.__currentPageChanged)
+
         self.grabGesture(Qt.GestureType.PinchGesture)
 
+    def setDocument(self, document):
+        """
+        Public method to set the PDF document.
+
+        @param document reference to the PDF document object
+        @type QPdfDocument
+        """
+        super().setDocument(document)
+
+        document.statusChanged.connect(self.__calculateDocumentLayout)
+
     def __zoomInOut(self, zoomIn):
         """
         Private method to zoom into or out of the view.
@@ -78,10 +151,11 @@
         @return zoom factor
         @rtype float
         """
+        self.__calculateDocumentViewport()
+
         if zoomMode == QPdfView.ZoomMode.Custom:
             return self.zoomFactor()
         else:
-            viewport = self.viewport()
             curPage = self.pageNavigator().currentPage()
             margins = self.documentMargins()
             if zoomMode == QPdfView.ZoomMode.FitToWidth:
@@ -89,12 +163,12 @@
                     self.document().pagePointSize(curPage) * self.__screenResolution
                 ).toSize()
                 factor = (
-                    viewport.width() - margins.left() - margins.right()
+                    self.__documentViewport.width() - margins.left() - margins.right()
                 ) / pageSize.width()
                 pageSize *= factor
             else:
                 # QPdfView.ZoomMode.FitInView
-                viewportSize = viewport.size() + QSize(
+                viewportSize = self.__documentViewport.size() + QSize(
                     -margins.left() - margins.right(), -self.pageSpacing()
                 )
                 pageSize = (
@@ -159,6 +233,90 @@
 
         super().wheelEvent(evt)
 
+    def keyPressEvent(self, evt):
+        """
+        Protected method handling key press events.
+
+        @param evt reference to the key event
+        @type QKeyEvent
+        """
+        if evt.key() == Qt.Key.Key_Escape:
+            self.clearSelection()
+
+    def mousePressEvent(self, evt):
+        """
+        Protected method to handle mouse press events.
+
+        @param evt reference to the mouse event
+        @type QMouseEvent
+        """
+        if evt.button() == Qt.MouseButton.LeftButton:
+            self.clearMarkers(PdfMarkerType.Selection)
+            self.selectionAvailable.emit(False)
+
+            self.__rubberBandOrigin = evt.pos()
+            if self.__rubberBand is None:
+                self.__rubberBand = QRubberBand(
+                    QRubberBand.Shape.Rectangle, self.viewport()
+                )
+            self.__rubberBand.setGeometry(QRect(self.__rubberBandOrigin, QSize()))
+            self.__rubberBand.show()
+
+        super().mousePressEvent(evt)
+
+    def mouseMoveEvent(self, evt):
+        """
+        Protected method to handle mouse move events.
+
+        @param evt reference to the mouse event
+        @type QMouseEvent
+        """
+        if evt.buttons() & Qt.MouseButton.LeftButton:
+            self.__rubberBand.setGeometry(
+                QRect(self.__rubberBandOrigin, evt.pos()).normalized()
+            )
+
+        super().mousePressEvent(evt)
+
+    def mouseReleaseEvent(self, evt):
+        """
+        Protected method to handle mouse release events.
+
+        @param evt reference to the mouse event
+        @type QMouseEvent
+        """
+        if evt.button() == Qt.MouseButton.LeftButton:
+            self.__rubberBand.hide()
+            translatedRubber = self.__rubberBand.geometry().translated(
+                self.__documentViewport.topLeft()
+            )
+            for page in self.__pageGeometries:
+                if self.__pageGeometries[page].intersects(translatedRubber):
+                    translatedRubber = translatedRubber.translated(
+                        -self.__pageGeometries[page].topLeft()
+                    )
+                    factor = self.__zoomFactorForMode(self.zoomMode())
+                    selectionSize = (
+                        QSizeF(translatedRubber.size()) / factor
+                        / self.__screenResolution
+                    )
+                    selectionTopLeft = (
+                        QPointF(translatedRubber.topLeft()) / factor
+                        / self.__screenResolution
+                    )
+                    selectionRect = QRectF(selectionTopLeft, selectionSize)
+                    selection = self.document().getSelection(
+                        page, selectionRect.topLeft(), selectionRect.bottomRight()
+                    )
+                    if selection.isValid():
+                        for bound in selection.bounds():
+                            self.addMarker(
+                                page, bound.boundingRect(), PdfMarkerType.Selection
+                            )
+                            self.selectionAvailable.emit(True)
+
+        super().mousePressEvent(evt)
+
     def event(self, evt):
         """
         Public method handling events.
@@ -193,3 +351,310 @@
                 self.setZoomFactor(zoomFactor)
                 self.zoomFactorChanged.emit(zoomFactor)
             evt.accept()
+
+    def resizeEvent(self, evt):
+        """
+        Protected method to handle a widget resize.
+
+        @param evt reference to the resize event
+        @type QResizeEvent
+        """
+        super().resizeEvent(evt)
+
+        self.__calculateDocumentViewport()
+
+    def paintEvent(self, evt):
+        """
+        Protected method to paint the view.
+
+        This event handler calls the original paint event handler of the super class
+        and paints the markers on top of the result.
+
+        @param evt reference to the paint event
+        @type QPaintEvent
+        """
+        super().paintEvent(evt)
+
+        painter = QPainter(self.viewport())
+        painter.translate(-self.__documentViewport.x(), -self.__documentViewport.y())
+        for page in self.__markerGeometries:
+            for markerGeom in self.__markerGeometries[page]:
+                if markerGeom.rectangle.intersects(self.__documentViewport):
+                    painter.setPen(QPen(
+                        PdfView.MarkerColors[markerGeom.markerType][0], 2
+                    ))
+                    painter.setBrush(PdfView.MarkerColors[markerGeom.markerType][1])
+                    painter.drawRect(markerGeom.rectangle)
+        painter.end()
+
+    def __calculateDocumentViewport(self):
+        """
+        Private method to calculate the document viewport.
+
+        This is a PyQt implementation of the code found in the QPdfView class
+        because it is calculated in a private part and not accessible.
+        """
+        x = self.horizontalScrollBar().value()
+        y = self.verticalScrollBar().value()
+        width = self.viewport().width()
+        height = self.viewport().height()
+        
+        docViewport = QRect(x, y, width, height)
+        if self.__documentViewport == docViewport:
+            return
+
+        oldSize = self.__documentViewport.size()
+
+        self.__documentViewport = docViewport
+
+        if oldSize != self.__documentViewport.size():
+            self.__calculateDocumentLayout()
+
+    @pyqtSlot()
+    def __calculateDocumentLayout(self):
+        """
+        Private slot to calculate the document layout data.
+
+        This is a PyQt implementation of the code found in the QPdfView class
+        because it is calculated in a private part and not accessible.
+        """
+        self.__documentSize = QSize()
+        self.__pageGeometries.clear()
+        self.__markerGeometries.clear()
+
+        document = self.document()
+        margins = self.documentMargins()
+        
+        if document is None or document.status() != QPdfDocument.Status.Ready:
+            return
+
+        pageCount = document.pageCount()
+        
+        totalWidth = 0
+        
+        startPage = (
+            self.pageNavigator().currentPage()
+            if self.pageMode == QPdfView.PageMode.SinglePage
+            else 0
+        )
+        endPage = (
+            self.pageNavigator().currentPage() + 1
+            if self.pageMode == QPdfView.PageMode.SinglePage
+            else pageCount
+        )
+
+        # calculate pageSizes
+        for page in range(startPage, endPage):
+            if self.zoomMode() == QPdfView.ZoomMode.Custom:
+                pageSize = QSizeF(
+                    document.pagePointSize(page) * self.__screenResolution
+                    * self.zoomFactor()
+                ).toSize()
+            elif self.zoomMode() == QPdfView.ZoomMode.FitToWidth:
+                pageSize = QSizeF(
+                    document.pagePointSize(page) * self.__screenResolution
+                ).toSize()
+                factor = (
+                    self.__documentViewport.width() - margins.left() - margins.right()
+                ) / pageSize.width()
+                pageSize *= factor
+            elif self.zoomMode() == QPdfView.ZoomMode.FitInView:
+                viewportSize = (
+                    self.__documentViewport.size()
+                    + QSize(-margins.left() - margins.right(), -self.pageSpacing())
+                )
+                pageSize = QSizeF(
+                    document.pagePointSize(page) * self.__screenResolution
+                ).toSize()
+                pageSize = pageSize.scaled(
+                    viewportSize, Qt.AspectRatioMode.KeepAspectRatio
+                )
+
+            totalWidth = max(totalWidth, pageSize.width())
+
+            self.__pageGeometries[page] = QRect(QPoint(0, 0), pageSize)
+
+        totalWidth += margins.left() + margins.right()
+
+        pageY = margins.top()
+
+        # calculate page positions
+        for page in range(startPage, endPage):
+            pageSize = self.__pageGeometries[page].size()
+
+            # center horizontally inside the viewport
+            pageX = (
+                max(totalWidth, self.__documentViewport.width()) - pageSize.width()
+            ) // 2
+            self.__pageGeometries[page].moveTopLeft(QPoint(pageX, pageY))
+
+            self.__calculateMarkerGeometries(page, QPoint(pageX, pageY))
+
+            pageY += pageSize.height() + self.pageSpacing()
+
+        pageY += margins.bottom()
+
+        self.__documentSize = QSize(totalWidth, pageY)
+
+    @pyqtSlot()
+    def __currentPageChanged(self):
+        """
+        Private slot to handle a change of the current page.
+        """
+        if self.pageMode() == QPdfView.PageMode.SinglePage:
+            self.__calculateDocumentLayout()
+
+    def __calculateMarkerGeometries(self, page, offset):
+        """
+        Private method to calculate the marker geometries.
+
+        @param page page number
+        @type int
+        @param offset page offset
+        @type QPoint or QPointF
+        """
+        # calculate search marker sizes
+        if page in self.__markers:
+            factor = self.__zoomFactorForMode(self.zoomMode())
+            for marker in self.__markers[page]:
+                markerSize = (
+                    QSizeF(marker.rectangle.size()) * factor * self.__screenResolution
+                ).toSize()
+                markerTopLeft = (
+                    QPointF(marker.rectangle.topLeft()) * factor
+                    * self.__screenResolution
+                ).toPoint()
+
+                markerGeometry = QRect(markerTopLeft, markerSize)
+                self.__markerGeometries[page].append(
+                    PdfMarkerGeometry(
+                        rectangle=markerGeometry.translated(offset),
+                        markerType=marker.markerType
+                    )
+                )
+
+    def scrollContentsBy(self, dx, dy):
+        """
+        Public method called when the scrollbars are moved.
+
+        @param dx change of the horizontal scroll bar
+        @type int
+        @param dy change of the vertical scroll bar
+        @type int
+        """
+        super().scrollContentsBy(dx, dy)
+
+        self.__calculateDocumentViewport()
+
+    def __updateView(self):
+        """
+        Private method to update the view.
+        """
+        self.__calculateDocumentLayout()
+        self.update()
+
+    @pyqtSlot(int, QRectF, PdfMarkerType)
+    @pyqtSlot(int, QRect, PdfMarkerType)
+    def addMarker(self, page, rect, markerType):
+        """
+        Public slot to add a marker.
+
+        @param page page number for the marker
+        @type int
+        @param rect marker rectangle
+        @type QRect or QRectF
+        @param markerType type of the marker
+        @type PdfMarkerType
+        """
+        marker = PdfMarker(rectangle=QRectF(rect), markerType=markerType)
+        if marker not in self.__markers[page]:
+            self.__markers[page].append(marker)
+        self.__updateView()
+
+    @pyqtSlot(PdfMarkerType)
+    def clearMarkers(self, markerType):
+        """
+        Public slot to clear the markers of a specific type.
+
+        @param markerType type of the marker
+        @type PdfMarkerType
+        """
+        markers = collections.defaultdict(list)
+        for page in self.__markers:
+            markersList = [
+                m for m in self.__markers[page] if m.markerType != markerType
+            ]
+            if markersList:
+                markers[page] = markersList
+
+        self.__markers = markers
+        self.__updateView()
+
+    @pyqtSlot()
+    def clearAllMarkers(self):
+        """
+        Public slot to clear all markers.
+        """
+        self.__markers.clear()
+        self.__updateView()
+
+    @pyqtSlot(QPdfLink)
+    def addSearchMarker(self, link):
+        """
+        Public slot to add a search marker given a PDF link.
+
+        @param link reference to the PDF link object
+        @type QPdfLink
+        """
+        for rect in link.rectangles():
+            self.addMarker(link.page(), rect, PdfMarkerType.SearchResult)
+
+    @pyqtSlot()
+    def clearSearchMarkers(self):
+        """
+        Public slot to clear the search markers.
+        """
+        self.clearMarkers(PdfMarkerType.SearchResult)
+
+    def hasSelection(self):
+        """
+        Public method to check the presence of a selection.
+
+        @return flag indicating the presence of a selection
+        @rtype bool
+        """
+        return any(
+            m.markerType == PdfMarkerType.Selection
+            for p in self.__markers
+            for m in self.__markers[p]
+        )
+
+    def getSelection(self):
+        """
+        Public method to get a PDF selection object.
+
+        @return reference to the PDF selection object
+        @rtype QPdfSelection
+        """
+        for page in self.__markers:
+            markersList = [
+                m for m in self.__markers[page]
+                if m.markerType == PdfMarkerType.Selection
+            ]
+            if markersList:
+                selection = self.document().getSelection(
+                    page,
+                    markersList[0].rectangle.topLeft(),
+                    markersList[-1].rectangle.bottomRight(),
+                )
+                if selection.isValid():
+                    return selection
+
+        return None
+
+    @pyqtSlot()
+    def clearSelection(self):
+        """
+        Public slot to clear the current selection.
+        """
+        self.clearMarkers(PdfMarkerType.Selection)
--- a/src/eric7/PdfViewer/PdfViewerWindow.py	Wed Jan 18 16:38:29 2023 +0100
+++ b/src/eric7/PdfViewer/PdfViewerWindow.py	Fri Jan 20 15:05:59 2023 +0100
@@ -146,12 +146,15 @@
         self.__zoomSelector.zoomFactorChanged.connect(self.__view.setZoomFactor)
         self.__view.zoomFactorChanged.connect(self.__zoomSelector.setZoomFactor)
         self.__view.zoomModeChanged.connect(self.__zoomSelector.setZoomMode)
+        self.__view.selectionAvailable.connect(self.copyAct.setEnabled)
 
         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)
+        self.__searchWidget.searchCleared.connect(self.__view.clearSearchMarkers)
+        self.__searchWidget.searchResult.connect(self.__view.addSearchMarker)
 
         PdfViewerWindow.windows.append(self)
 
@@ -505,11 +508,22 @@
         """
         Private method to create the Edit actions.
         """
+        self.copyAct = EricAction(
+            self.tr("Copy"),
+            EricPixmapCache.getIcon("editCopy"),
+            self.tr("&Copy"),
+            QKeySequence(self.tr("Ctrl+C", "Edit|Copy")),
+            0,
+            self,
+            "pdfviewer_edit_copy",
+        )
+        self.copyAct.triggered.connect(self.__copyText)
+        self.__actions.append(self.copyAct)
+        
         self.copyAllAct = EricAction(
             self.tr("Copy All Text"),
-            EricPixmapCache.getIcon("editCopy"),
-            self.tr("&Copy All Text"),
-            QKeySequence(self.tr("Ctrl+C", "Edit|Copy All Text")),
+            self.tr("Copy &All Text"),
+            QKeySequence(self.tr("Alt+Ctrl+C", "Edit|Copy All Text")),
             0,
             self,
             "pdfviewer_edit_copyall",
@@ -519,7 +533,7 @@
 
         self.copyAllPageAct = EricAction(
             self.tr("Copy All Page Text"),
-            self.tr("Copy &All Page Text"),
+            self.tr("Copy All Page &Text"),
             QKeySequence(self.tr("Shift+Ctrl+C", "Edit|Copy All Page Text")),
             0,
             self,
@@ -564,6 +578,7 @@
         self.searchPrevAct.triggered.connect(self.__searchWidget.previousResult)
         self.__actions.append(self.searchPrevAct)
 
+        self.copyAct.setEnabled(False)
         self.searchNextAct.setEnabled(False)
         self.searchPrevAct.setEnabled(False)
 
@@ -741,8 +756,9 @@
 
         menu = mb.addMenu(self.tr("&Edit"))
         menu.setTearOffEnabled(True)
+        menu.addAction(self.copyAct)
+        menu.addSeparator()
         menu.addAction(self.copyAllAct)
-        menu.addSeparator()
         menu.addAction(self.copyAllPageAct)
         menu.addSeparator()
         menu.addAction(self.searchAct)
@@ -1078,6 +1094,7 @@
         @type QPdfLink
         """
         self.__view.pageNavigator().jump(link)
+        self.__view.addSearchMarker(link)
 
     @pyqtSlot()
     def __search(self):
@@ -1433,3 +1450,12 @@
         QGuiApplication.clipboard().setText(
             "\r\n".join(textPages), QClipboard.Mode.Clipboard
         )
+
+    @pyqtSlot()
+    def __copyText(self):
+        """
+        Private slot to copy the selected text to the system clipboard.
+        """
+        selection = self.__view.getSelection()
+        if selection is not None:
+            selection.copyToClipboard()
--- a/src/eric7/Preferences/__init__.py	Wed Jan 18 16:38:29 2023 +0100
+++ b/src/eric7/Preferences/__init__.py	Fri Jan 20 15:05:59 2023 +0100
@@ -1642,6 +1642,7 @@
         "PdfViewerZoomFactor": 1.0,
         "PdfViewerOpenRecentInNewWindow": False,
         "PdfSearchContextLength": 30,
+        "PdfSearchHighlightAll": True,
     }
 
 
@@ -3864,7 +3865,11 @@
         return int(
             Prefs.settings.value("PdfViewer/" + key, Prefs.pdfViewerDefaults[key])
         )
-    elif key in ("PdfViewerSidebarVisible", "PdfViewerOpenRecentInNewWindow"):
+    elif key in (
+        "PdfViewerSidebarVisible",
+        "PdfViewerOpenRecentInNewWindow",
+        "PdfSearchHighlightAll",
+    ):
         return toBool(
             Prefs.settings.value("PdfViewer/" + key, Prefs.pdfViewerDefaults[key])
         )
@@ -3874,9 +3879,7 @@
         )
     elif key == "PdfViewerZoomMode":
         return QPdfView.ZoomMode(
-            int(
-                Prefs.settings.value("PdfViewer/" + key, Prefs.pdfViewerDefaults[key])
-            )
+            int(Prefs.settings.value("PdfViewer/" + key, Prefs.pdfViewerDefaults[key]))
         )
     else:
         return Prefs.settings.value("PdfViewer/" + key, Prefs.pdfViewerDefaults[key])

eric ide

mercurial