PDF-Vergleich in integrierten Viewer umgeleitet und Alpha-Blending verbessert

Das Diff-PDF-Icon lädt nun alle drei PDFs (diff, ref, new) direkt in den eingebauten Vergleichs-Viewer, statt ein externes Programm zu öffnen. Zusätzlich wurde die Alpha-Blending-Logik für sanftere Übergänge zwischen den Ansichten korrigiert.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
2025-12-14 13:45:20 +01:00
parent 629485f5e4
commit dd20067d42
+143 -40
View File
@@ -675,13 +675,12 @@ class MainWindow(QMainWindow):
if alpha_value <= 0: if alpha_value <= 0:
# Alpha von -100 bis 0: Übergang von ref zu diff # Alpha von -100 bis 0: Übergang von ref zu diff
ref_opacity = 1.0 # - (alpha_value + 100) / 100.0 ref_opacity = abs(alpha_value) / 100
diff_opacity = (alpha_value + 100) / 100.0 diff_opacity = 1.0 - abs(alpha_value) / 100.0
new_opacity = 0.0 new_opacity = 0.0
else: else:
# Alpha von 0 bis 100: Übergang von diff zu new
ref_opacity = 0.0 ref_opacity = 0.0
diff_opacity = 1.0 # - alpha_value / 100.0 diff_opacity = 1.0 - alpha_value / 100.0
new_opacity = alpha_value / 100.0 new_opacity = alpha_value / 100.0
# Zeichne die Ebenen mit entsprechender Transparenz # Zeichne die Ebenen mit entsprechender Transparenz
@@ -1304,12 +1303,13 @@ class MainWindow(QMainWindow):
return container, progress_bar return container, progress_bar
def _create_centered_diff_icon(self, xml_file_path: Path) -> QWidget: def _create_centered_diff_icon(self, xml_file_path: Path, xsl_id_str: str) -> QWidget:
""" """
Erstellt ein zentriertes, klickbares Icon für Diff-PDF. Erstellt ein zentriertes, klickbares Icon für Diff-PDF.
Args: Args:
xml_file_path: Pfad zur XML-Datei (für Event-Handler) xml_file_path: Pfad zur XML-Datei (relativ)
xsl_id_str: XSL-ID als String (z.B. "2002_1_128")
Returns: Returns:
QWidget: Container mit klickbarem Icon QWidget: Container mit klickbarem Icon
@@ -1324,57 +1324,160 @@ class MainWindow(QMainWindow):
icon_label = QLabel() icon_label = QLabel()
icon_label.setPixmap(QIcon.fromTheme("document-preview").pixmap(16, 16)) icon_label.setPixmap(QIcon.fromTheme("document-preview").pixmap(16, 16))
icon_label.setCursor(QCursor(Qt.CursorShape.PointingHandCursor)) icon_label.setCursor(QCursor(Qt.CursorShape.PointingHandCursor))
icon_label.setToolTip("Diff-PDF öffnen (Doppelklick)") icon_label.setToolTip("Diff-PDF in Viewer laden (Doppelklick)")
# Klick-Event für Icon (Doppelklick öffnet PDF) # Klick-Event für Icon (Doppelklick lädt PDF in Viewer)
icon_label.mouseDoubleClickEvent = lambda event: self._open_diff_pdf(xml_file_path) icon_label.mouseDoubleClickEvent = lambda event: self._load_pdf_for_comparison(xml_file_path, xsl_id_str)
layout.addWidget(icon_label) layout.addWidget(icon_label)
return container return container
def _open_diff_pdf(self, xml_file_path: Path): def _load_pdf_for_comparison(self, xml_file_path: Path, xsl_id_str: str):
""" """
Öffnet die Diff-PDF für eine XML-Datei mit dem Standard-PDF-Viewer. Lädt die PDFs (diff, ref, new) einer Transformation in den Vergleichs-Viewer.
Args: Args:
xml_file_path: Pfad zur XML-Datei (relativ) xml_file_path: Pfad zur XML-Datei (relativ)
xsl_id_str: XSL-ID als String (z.B. "2002_1_128")
""" """
import subprocess
import sys
try: try:
# Ermittle Diff-PDF-Pfad basierend auf XML-Datei if not self.project:
# WICHTIG: Berücksichtige XSL-ID im Dateinamen! QMessageBox.warning(self, "Fehler", "Kein Projekt geöffnet")
# Vereinfachung: Suche nach allen PDFs die mit xml_stem beginnen
xml_stem = xml_file_path.stem
diff_dir = self.project.project_dir / "diff"
# Finde passende Diff-PDF (könnte mehrere geben bei verschiedenen XSL-IDs)
matching_pdfs = list(diff_dir.glob(f"{xml_stem}*.pdf"))
if not matching_pdfs:
QMessageBox.information(self, "Keine Diff-PDF", f"Keine Diff-PDF für {xml_file_path.name} gefunden")
return return
# Bei mehreren: Nehme neueste # Ermittle PDF-Dateinamen basierend auf XML und XSL-ID
diff_pdf = max(matching_pdfs, key=lambda p: p.stat().st_mtime) xml_stem = xml_file_path.stem
pdf_basename = f"{xml_stem}_xsl_{xsl_id_str}.pdf"
logger.info(f"Öffne Diff-PDF: {diff_pdf}") # Pfade zu den drei PDFs
diff_dir = self.project.project_dir / "diff"
ref_dir = self.project.project_dir / "ref"
new_dir = self.project.project_dir / "new"
# Öffne PDF mit Plattform-spezifischem Befehl diff_pdf_path = diff_dir / pdf_basename
if sys.platform == "win32": ref_pdf_path = ref_dir / pdf_basename
subprocess.Popen(["start", str(diff_pdf)], shell=True) new_pdf_path = new_dir / pdf_basename
elif sys.platform == "darwin":
subprocess.Popen(["open", str(diff_pdf)])
else:
subprocess.Popen(["xdg-open", str(diff_pdf)])
logger.info(f"Diff-PDF geöffnet: {diff_pdf}") # Prüfe ob PDFs existieren
if not diff_pdf_path.exists():
QMessageBox.information(self, "Keine Diff-PDF", f"Diff-PDF nicht gefunden:\n{pdf_basename}")
return
if not ref_pdf_path.exists() or not new_pdf_path.exists():
QMessageBox.warning(
self,
"Fehlende PDFs",
f"Ref-PDF oder New-PDF nicht gefunden:\n{pdf_basename}\n\nNur Diff-PDF vorhanden.",
)
return
logger.info(f"Lade PDFs für Vergleich: {pdf_basename}")
# Entferne bestehende Widgets aus den Layouts
self._clear_layout(self.ui.verticalLayout_2)
self._clear_layout(self.ui.verticalLayout_3)
# Dicts zurücksetzen
self.thumbnail_to_page = {}
self.pdf_documents = {}
self.current_rendered_pixmaps = None
# Alle drei PDF-Dateien öffnen mit QtPdf
diff_doc = QPdfDocument()
ref_doc = QPdfDocument()
new_doc = QPdfDocument()
# PDF-Dateien laden
diff_doc.load(str(diff_pdf_path))
ref_doc.load(str(ref_pdf_path))
new_doc.load(str(new_pdf_path))
# Warten bis PDFs geladen sind
if (
diff_doc.status() != QPdfDocument.Status.Ready
or ref_doc.status() != QPdfDocument.Status.Ready
or new_doc.status() != QPdfDocument.Status.Ready
):
QMessageBox.critical(self, "Fehler", f"Fehler beim Laden der PDFs:\n{pdf_basename}")
return
# PDF-Dokumente speichern
self.pdf_documents[pdf_basename] = {"diff": diff_doc, "ref": ref_doc, "new": new_doc}
logger.info(f"PDFs geladen: {pdf_basename}")
logger.info(f" diff: {diff_doc.pageCount()} Seiten")
logger.info(f" ref: {ref_doc.pageCount()} Seiten")
logger.info(f" new: {new_doc.pageCount()} Seiten")
# Nehme die Seitenzahl der diff-PDF als Basis
max_pages = diff_doc.pageCount()
# Erstelle Thumbnails für alle Seiten
for page_num in range(max_pages):
# Nur diff-Seite für Thumbnail rendern
page_size = diff_doc.pagePointSize(page_num)
# Skalierung für Thumbnail
scale_factor = 200.0 / page_size.width() # 200 Pixel Breite
# Seite rendern
page_image = diff_doc.render(
page_num,
QSize(int(page_size.width() * scale_factor), int(page_size.height() * scale_factor)),
)
diff_pixmap = QPixmap.fromImage(page_image)
# Thumbnail erstellen und zur linken Spalte hinzufügen
thumbnail = QLabel()
thumbnail.setObjectName(f"thumbnail_{pdf_basename}_page_{page_num + 1}")
thumbnail.setPixmap(diff_pixmap.scaledToWidth(200, Qt.TransformationMode.SmoothTransformation))
thumbnail.setCursor(QCursor(Qt.CursorShape.PointingHandCursor))
thumbnail.setMouseTracking(True)
self.ui.verticalLayout_2.addWidget(thumbnail)
# Seitennummer für Thumbnail anzeigen
thumbnail_info = QLabel(f"Seite {page_num + 1}")
thumbnail_info.setAlignment(Qt.AlignmentFlag.AlignCenter)
self.ui.verticalLayout_2.addWidget(thumbnail_info)
# Beziehung zwischen Thumbnail und Seitennummer speichern
self.thumbnail_to_page[thumbnail] = {"pdf_filename": pdf_basename, "page_num": page_num}
# Click-Event für das Thumbnail einrichten
thumbnail.mousePressEvent = lambda event, t=thumbnail: self.on_thumbnail_clicked(event, t)
# Erstelle das Vollbild-Label für die rechte Spalte (falls noch nicht vorhanden)
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)
# Drag-to-Scroll Events für das große Bild einrichten
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
)
# Setze die aktuelle PDF
self.current_pdf = pdf_basename
# Zeige die erste Seite initial an
self.render_and_display_page(pdf_basename, 0)
logger.info(f"PDF-Vergleich geladen: {pdf_basename}")
except Exception as e: except Exception as e:
logger.error(f"Fehler beim Öffnen der Diff-PDF: {e}") logger.error(f"Fehler beim Laden der PDFs für Vergleich: {e}")
QMessageBox.critical(self, "Fehler", f"Konnte Diff-PDF nicht öffnen: {str(e)}") QMessageBox.critical(self, "Fehler", f"Konnte PDFs nicht laden:\n{str(e)}")
def _update_diff_icons_for_existing_pdfs(self): def _update_diff_icons_for_existing_pdfs(self):
""" """
@@ -1410,7 +1513,7 @@ class MainWindow(QMainWindow):
if expected_pdf.exists(): if expected_pdf.exists():
# Icon setzen # Icon setzen
icon_widget = self._create_centered_diff_icon(xml_path) icon_widget = self._create_centered_diff_icon(xml_path, xsl_id_str)
self.ui.treeWidget.setItemWidget(tree_item, 2, icon_widget) self.ui.treeWidget.setItemWidget(tree_item, 2, icon_widget)
icon_count += 1 icon_count += 1
logger.debug(f"Diff-Icon für existierende PDF gesetzt: {map_key}") logger.debug(f"Diff-Icon für existierende PDF gesetzt: {map_key}")
@@ -3138,7 +3241,7 @@ class MainWindow(QMainWindow):
# Wenn Diff-PDF existiert, zeige Icon # Wenn Diff-PDF existiert, zeige Icon
if diff_pdf_str and Path(diff_pdf_str).exists(): if diff_pdf_str and Path(diff_pdf_str).exists():
xml_file_path = Path(xml_file_str) xml_file_path = Path(xml_file_str)
icon_widget = self._create_centered_diff_icon(xml_file_path) icon_widget = self._create_centered_diff_icon(xml_file_path, xsl_id_str)
self.ui.treeWidget.setItemWidget(tree_item, 2, icon_widget) self.ui.treeWidget.setItemWidget(tree_item, 2, icon_widget)
logger.debug(f"Diff-Icon für {xml_file_str} gesetzt") logger.debug(f"Diff-Icon für {xml_file_str} gesetzt")
else: else: