From 4f2d136d17fdfcff137f25e26c8f116447fcad92 Mon Sep 17 00:00:00 2001 From: Vitali Graf Date: Sat, 14 Mar 2026 17:01:19 +0100 Subject: [PATCH] Feat: Ref-PDF automatisch im internen Viewer anzeigen wenn keine Diff-PDF vorhanden MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Beim Auswählen eines XML-Knotens im Baum wird jetzt die Ref-PDF direkt im internen Viewer geladen, sofern keine Diff-PDF existiert. Der Kontextmenü-Eintrag "Ref-PDF öffnen" und der zugehörige Handler wurden entfernt. Co-Authored-By: Claude Sonnet 4.6 --- src/ui/MainWindow.py | 64 +------------------ src/ui/mixins/pdf_viewer.py | 112 ++++++++++++++++++++++++++++++++++ src/ui/mixins/tree_manager.py | 37 +++-------- 3 files changed, 121 insertions(+), 92 deletions(-) diff --git a/src/ui/MainWindow.py b/src/ui/MainWindow.py index 5142715..7c4d34e 100644 --- a/src/ui/MainWindow.py +++ b/src/ui/MainWindow.py @@ -1,8 +1,8 @@ import logging import shutil -from PySide6.QtCore import Qt, QUrl, QEvent -from PySide6.QtGui import QAction, QDesktopServices +from PySide6.QtCore import Qt, QEvent +from PySide6.QtGui import QAction from PySide6.QtWidgets import ( QMainWindow, QApplication, @@ -870,66 +870,6 @@ class MainWindow( logger.error(f"Fehler beim Akzeptieren der Änderungen: {e}") QMessageBox.critical(self, "Fehler", f"Fehler beim Akzeptieren der Änderungen:\n{str(e)}") - def _open_ref_pdf_for_xml_file(self, item): - """ - Handler für Kontextmenü-Aktion "Ref-PDF öffnen" bei XML-Dateien. - Öffnet die Referenz-PDF für die ausgewählte XML-Datei im systemseitig installierten PDF-Viewer. - - Args: - item: Das TreeWidgetItem der XML-Datei - """ - try: - if not self.project: - QMessageBox.warning(self, "Fehler", "Kein Projekt geöffnet") - return - - # Hole XML-Datei-Objekt - xml_file_obj = item.data(0, Qt.ItemDataRole.UserRole) - if not xml_file_obj: - QMessageBox.warning(self, "Fehler", "XML-Datei-Objekt nicht gefunden") - return - - # Hole Parent-Item (XslFile) - parent_item = item.parent() - if not parent_item: - QMessageBox.warning(self, "Fehler", "Parent-Item nicht gefunden") - return - - # Hole XslFile-Objekt - xsl_file_obj = parent_item.data(0, Qt.ItemDataRole.UserRole) - if not xsl_file_obj: - QMessageBox.warning(self, "Fehler", "XSL-Datei-Objekt nicht gefunden") - return - - # Erstelle XSL-ID-String - xsl_id_str = "_".join(map(str, xsl_file_obj.id)) - - # Ermittle PDF-Dateinamen - xml_file_path = xml_file_obj.xml - xml_stem = xml_file_path.stem - pdf_basename = f"{xml_stem}_xsl_{xsl_id_str}.pdf" - - # Pfad zur Ref-PDF - ref_dir = self.project.project_dir / "ref" - ref_pdf_path = ref_dir / pdf_basename - - # Prüfe ob Ref-PDF existiert - if not ref_pdf_path.exists(): - QMessageBox.warning(self, "Fehler", f"Referenz-PDF nicht gefunden:\n{pdf_basename}") - logger.warning(f"Referenz-PDF nicht gefunden: {ref_pdf_path}") - return - - # Öffne Ref-PDF im System-Viewer - logger.info(f"Öffne Referenz-PDF im System-Viewer: {ref_pdf_path}") - url = QUrl.fromLocalFile(str(ref_pdf_path)) - if not QDesktopServices.openUrl(url): - QMessageBox.critical(self, "Fehler", f"Konnte Referenz-PDF nicht öffnen:\n{ref_pdf_path}") - logger.error(f"Fehler beim Öffnen der Referenz-PDF: {ref_pdf_path}") - - except Exception as e: - logger.error(f"Fehler beim Öffnen der Referenz-PDF: {e}") - QMessageBox.critical(self, "Fehler", f"Fehler beim Öffnen der Referenz-PDF:\n{str(e)}") - def eventFilter(self, obj, event): """ Event-Filter für Zoom per STRG+Mausrad im PDF-Viewer. diff --git a/src/ui/mixins/pdf_viewer.py b/src/ui/mixins/pdf_viewer.py index 0c7ba65..3782134 100644 --- a/src/ui/mixins/pdf_viewer.py +++ b/src/ui/mixins/pdf_viewer.py @@ -550,6 +550,118 @@ class PdfViewerMixin: QMessageBox.critical(self, "Fehler", f"Konnte Referenz-PDF nicht öffnen:\n{self.current_ref_pdf_path}") logger.error(f"Fehler beim Öffnen der Referenz-PDF: {self.current_ref_pdf_path}") + def _load_ref_pdf_for_display(self, xml_file_path: Path, xsl_id_str: str): + """ + Lädt nur die Ref-PDF in den Viewer (wenn keine Diff-PDF vorhanden ist). + + Args: + xml_file_path: Pfad zur XML-Datei (relativ) + xsl_id_str: XSL-ID als String + """ + try: + if not self.project: + return + + xml_stem = xml_file_path.stem + pdf_basename = f"{xml_stem}_xsl_{xsl_id_str}.pdf" + ref_pdf_path = self.project.project_dir / "ref" / pdf_basename + + if not ref_pdf_path.exists(): + if self.pdf_documents: + self._clear_pdf_viewer() + return + + logger.info(f"Lade Ref-PDF für Anzeige: {pdf_basename}") + + self._clear_layout(self.ui.verticalLayout_2) + self._clear_layout(self.ui.verticalLayout_3) + self.ui.verticalLayout_2.setSpacing(5) + self.ui.verticalLayout_2.setContentsMargins(0, 0, 0, 0) + + self.thumbnail_to_page = {} + self.pdf_documents = {} + self.current_rendered_pixmaps = None + self.fullsize_label = None + + ref_doc = QPdfDocument() + ref_doc.load(str(ref_pdf_path)) + + if ref_doc.status() != QPdfDocument.Status.Ready: + QMessageBox.critical(self, "Fehler", f"Fehler beim Laden der Ref-PDF:\n{pdf_basename}") + return + + # Ref-Doc in allen drei Slots speichern, damit render_and_display_page funktioniert + self.pdf_documents[pdf_basename] = {"diff": ref_doc, "ref": ref_doc, "new": ref_doc} + + self.current_ref_pdf_path = ref_pdf_path + self.current_new_pdf_path = None + self.ui.view_ref_pdf.setEnabled(True) + self.ui.view_new_pdf.setEnabled(False) + + # Alpha deaktivieren (Blending nicht sinnvoll ohne Diff), Zoom aktivieren + self.ui.alpha.setValue(0) + self.ui.alpha.setEnabled(False) + self.ui.zoom.setEnabled(True) + + self.ui.accept_changes.setEnabled(False) + + max_pages = ref_doc.pageCount() + logger.info(f"Ref-PDF geladen: {pdf_basename}, {max_pages} Seiten") + + thumbnail_labels = [] + for page_num in range(max_pages): + thumbnail = QLabel() + thumbnail.setObjectName(f"thumbnail_{pdf_basename}_page_{page_num + 1}") + thumbnail.setText(f"Seite {page_num + 1}\n…") + thumbnail.setCursor(QCursor(Qt.CursorShape.PointingHandCursor)) + thumbnail.setMouseTracking(True) + thumbnail.setAlignment(Qt.AlignmentFlag.AlignCenter) + thumbnail.setMinimumHeight(150) + self.ui.verticalLayout_2.addWidget(thumbnail) + + thumbnail_info = QLabel(f"Seite {page_num + 1}") + thumbnail_info.setAlignment(Qt.AlignmentFlag.AlignCenter) + thumbnail_info.setMaximumHeight(18) + thumbnail_info.setContentsMargins(0, 0, 0, 0) + self.ui.verticalLayout_2.addWidget(thumbnail_info) + + self.thumbnail_to_page[thumbnail] = {"pdf_filename": pdf_basename, "page_num": page_num} + thumbnail.mousePressEvent = lambda event, t=thumbnail: self.on_thumbnail_clicked(event, t) + thumbnail_labels.append(thumbnail) + + self._schedule_thumbnail_rendering(ref_doc, pdf_basename, thumbnail_labels, 0) + + spacer = QSpacerItem(20, 40, QSizePolicy.Policy.Minimum, QSizePolicy.Policy.Expanding) + self.ui.verticalLayout_2.addItem(spacer) + + if self.fullsize_label is None: + self.fullsize_label = QLabel() + self.fullsize_label.setObjectName("fullsize_current_page") + self.fullsize_label.setAlignment(Qt.AlignmentFlag.AlignHCenter) + self.fullsize_label.setCursor(QCursor(Qt.CursorShape.OpenHandCursor)) + self.ui.verticalLayout_3.addWidget(self.fullsize_label) + + self.fullsize_label.mousePressEvent = lambda event: self.on_fullsize_mouse_press( + event, self.fullsize_label + ) + self.fullsize_label.mouseMoveEvent = lambda event: self.on_fullsize_mouse_move( + event, self.fullsize_label + ) + self.fullsize_label.mouseReleaseEvent = lambda event: self.on_fullsize_mouse_release( + event, self.fullsize_label + ) + + self.current_pdf = pdf_basename + self.current_diff_xml_path = None + self.current_diff_xsl_id = None + + self.render_and_display_page(pdf_basename, 0) + logger.info(f"Ref-PDF-Anzeige geladen: {pdf_basename}") + + except Exception as e: + logger.error(f"Fehler beim Laden der Ref-PDF: {e}") + QMessageBox.critical(self, "Fehler", f"Konnte Ref-PDF nicht laden:\n{str(e)}") + def _on_view_new_pdf_clicked(self): """ Handler für view_new_pdf Button. diff --git a/src/ui/mixins/tree_manager.py b/src/ui/mixins/tree_manager.py index 758eacb..b5f4838 100644 --- a/src/ui/mixins/tree_manager.py +++ b/src/ui/mixins/tree_manager.py @@ -140,9 +140,13 @@ class TreeManagerMixin: logger.info(f"XML-Knoten mit Diff-PDF ausgewählt: {pdf_basename}, lade automatisch") self._load_pdf_for_comparison(xml_file_path, xsl_id_str) else: - # Kein Diff-PDF - Viewer leeren falls noch ein PDF geladen ist - if self.pdf_documents: - logger.debug("XML-Knoten ohne Diff-PDF ausgewählt, leere Viewer") + # Kein Diff-PDF - Ref-PDF laden falls vorhanden, sonst Viewer leeren + ref_pdf_path = self.project.project_dir / "ref" / pdf_basename + if ref_pdf_path.exists(): + logger.info(f"XML-Knoten ohne Diff-PDF, lade Ref-PDF: {pdf_basename}") + self._load_ref_pdf_for_display(xml_file_path, xsl_id_str) + elif self.pdf_documents: + logger.debug("XML-Knoten ohne Diff-PDF und ohne Ref-PDF, leere Viewer") self._clear_pdf_viewer() else: logger.debug("XML-File-Daten fehlen (xml_file_obj oder xsl_id_str ist None)") @@ -410,33 +414,6 @@ class TreeManagerMixin: menu.addSeparator() - # Ref-PDF öffnen Aktion (nur enabled wenn Ref-PDF existiert und keine Diff-PDF) - xml_file_obj = item.data(0, Qt.ItemDataRole.UserRole) - parent_item = item.parent() - ref_pdf_can_open = False - - if xml_file_obj and parent_item and self.project: - xsl_file_obj = parent_item.data(0, Qt.ItemDataRole.UserRole) - if xsl_file_obj: - # Erstelle Pfade zu Ref-PDF und Diff-PDF - xsl_id_str = "_".join(map(str, xsl_file_obj.id)) - xml_stem = xml_file_obj.xml.stem - pdf_basename = f"{xml_stem}_xsl_{xsl_id_str}.pdf" - - ref_pdf_path = self.project.project_dir / "ref" / pdf_basename - diff_pdf_path = self.project.project_dir / "diff" / pdf_basename - - # Ref-PDF kann geöffnet werden, wenn sie existiert und keine Diff-PDF vorhanden ist - ref_pdf_can_open = ref_pdf_path.exists() and not diff_pdf_path.exists() - - action_open_ref_pdf = QAction("Ref-PDF öffnen", self) - action_open_ref_pdf.setIcon(QIcon(QIcon.fromTheme("document-open"))) - action_open_ref_pdf.triggered.connect(lambda: self._open_ref_pdf_for_xml_file(item)) - action_open_ref_pdf.setEnabled(ref_pdf_can_open) - menu.addAction(action_open_ref_pdf) - - menu.addSeparator() - action_edit = QAction("Bearbeiten", self) action_edit.setIcon(QIcon(QIcon.fromTheme(QIcon.ThemeIcon.DocumentProperties))) action_edit.triggered.connect(lambda: self._edit_xml_file(item))