import math from PySide6.QtCore import QFile, QModelIndex, QPoint, Signal, Slot from PySide6.QtPdf import QPdfBookmarkModel, QPdfDocument from PySide6.QtPdfWidgets import QPdfView from PySide6.QtWidgets import QComboBox, QDialog, QMenuBar, QSpinBox, QWidget from ui.pdfViewer import Ui_pdfViewer ZOOM_MULTIPLIER = math.sqrt(2.0) class ZoomSelector(QComboBox): zoom_mode_changed = Signal(QPdfView.ZoomMode) zoom_factor_changed = Signal(float) def __init__(self, parent: QWidget|None = None) -> None: super(ZoomSelector, self).__init__(parent) self.setEditable(True) for text in [ 'Fit Width', 'Fit Page', '12%', '25%', '33%', '50%', '66%', '75%', '100%', '125%', '150%', '200%', '400%']: self.addItem(text) self.currentTextChanged.connect(self.on_current_text_changed) lineEdit = self.lineEdit() assert lineEdit is not None lineEdit.editingFinished.connect(self._editing_finished) return @Slot(float) # type: ignore def set_zoom_factor(self, zoomFactor: float) -> None: percent = int(zoomFactor * 100) self.setCurrentText(f"{percent}%") return @Slot() def reset(self) -> None: self.setCurrentIndex(8) # 100% return @Slot(str) # type: ignore def on_current_text_changed(self, text: str) -> None: if text == "Fit Width": self.zoom_mode_changed.emit(QPdfView.ZoomMode.FitToWidth) elif text == "Fit Page": self.zoom_mode_changed.emit(QPdfView.ZoomMode.FitInView) elif text.endswith("%"): zoom_level = int(text[:-1]) factor = zoom_level / 100.0 self.zoom_mode_changed.emit(QPdfView.ZoomMode.Custom) self.zoom_factor_changed.emit(factor) return @Slot() def _editing_finished(self) -> None: lineEdit = self.lineEdit() assert lineEdit is not None self.on_current_text_changed(lineEdit.text()) return class PDFViewer(QDialog, Ui_pdfViewer): menubar: QMenuBar zoomSelector: ZoomSelector pageSelector: QSpinBox document: QPdfDocument def __init__(self, parent: QWidget | None) -> None: super(PDFViewer, self).__init__(parent) self.setupUi(self) self.zoomSelector = ZoomSelector(self) self.pageSelector = QSpinBox(self) self.document = QPdfDocument(self) self.zoomSelector.setMaximumWidth(150) self.mainToolBar.insertWidget(self.actionZoom_In, self.zoomSelector) self.mainToolBar.insertWidget(self.actionForward, self.pageSelector) self.pageSelector.valueChanged.connect(self.page_selected) nav = self.pdfView.pageNavigator() nav.currentPageChanged.connect(self.pageSelector.setValue) nav.backAvailableChanged.connect(self.actionBack.setEnabled) nav.forwardAvailableChanged.connect(self.actionForward.setEnabled) self.zoomSelector.zoom_mode_changed.connect(self.pdfView.setZoomMode) self.zoomSelector.zoom_factor_changed.connect(self.pdfView.setZoomFactor) self.zoomSelector.reset() bookmark_model = QPdfBookmarkModel(self) bookmark_model.setDocument(self.document) self.bookmarkView.setModel(bookmark_model) self.bookmarkView.activated.connect(self.bookmark_selected) self.tabWidget.setTabEnabled(1, False) # disable pages tabwidget self.pdfView.setDocument(self.document) self.pdfView.zoomFactorChanged.connect(self.zoomSelector.set_zoom_factor) return @Slot(QFile) # type: ignore def open(self, file: QFile) -> None: #assert file.exists() #if not file.isOpen(): #file.open(QFile.OpenModeFlag.ReadOnly) #self.document.load(file) self.document.load(file.fileName()) document_title = self.document.metaData(QPdfDocument.MetaDataField.Title) self.setWindowTitle(document_title if document_title else "PDF Viewer") self.page_selected(0) self.pageSelector.setMaximum(self.document.pageCount() -1 ) return @Slot(QModelIndex) # type: ignore def bookmark_selected(self, index: QModelIndex) -> None: if not index.isValid(): return page = index.data(int(QPdfBookmarkModel.Role.Page)) zoom_level = index.data(int(QPdfBookmarkModel.Role.Level)) nav = self.pdfView.pageNavigator() assert nav is not None nav.jump(page, QPoint(), zoom_level) return @Slot(int) # type: ignore def page_selected(self, page: int) -> None: nav = self.pdfView.pageNavigator() nav.jump(page, QPoint(), nav.currentZoom()) return @Slot() def on_actionOpen_triggered(self) -> None: print("What are you doing in actionOpen_triggered?") return @Slot() def on_actionQuit_triggered(self) -> None: self.close() return @Slot() def on_actionZoom_In_triggered(self) -> None: factor = self.pdfView.zoomFactor() * ZOOM_MULTIPLIER self.pdfView.setZoomFactor(factor) return @Slot() def on_actionZoom_Out_triggered(self) -> None: factor = self.pdfView.zoomFactor() / ZOOM_MULTIPLIER self.pdfView.setZoomFactor(factor) return @Slot() def on_actionPrevious_Page_triggered(self) -> None: nav = self.pdfView.pageNavigator() nav.jump(nav.currentPage() - 1, QPoint(), nav.currentZoom()) return @Slot() def on_actionNext_Page_triggered(self) -> None: nav = self.pdfView.pageNavigator() nav.jump(nav.currentPage() + 1, QPoint(), nav.currentZoom()) return @Slot() def on_actionContinuous_triggered(self) -> None: cont_checked = self.actionContinuous.isChecked() mode = QPdfView.PageMode.MultiPage if cont_checked else QPdfView.PageMode.SinglePage self.pdfView.setPageMode(mode) return @Slot() def on_actionBack_triggered(self) -> None: self.pdfView.pageNavigator().back() return @Slot() def on_actionForward_triggered(self) -> None: self.pdfView.pageNavigator().forward() return