Die Drag&Drop-Funktionalität für XML-Dateien

This commit is contained in:
2025-08-31 17:04:22 +02:00
parent 7ab22dacc3
commit c82f9dccbd
6 changed files with 756 additions and 16 deletions
+256 -2
View File
@@ -4,8 +4,8 @@ import time
import polars as pl
import shutil
from PySide6.QtCore import Qt, QSize
from PySide6.QtGui import QCursor, QPixmap, QPainter, QAction, QIcon
from PySide6.QtCore import Qt, QSize, QUrl
from PySide6.QtGui import QCursor, QPixmap, QPainter, QAction, QIcon, QDragEnterEvent, QDropEvent
from PySide6.QtWidgets import QLabel, QMainWindow, QApplication, QStyleFactory, QMenu, QTreeWidgetItem, QMessageBox, QFileDialog
from PySide6.QtPdf import QPdfDocument
@@ -14,6 +14,7 @@ from ui.AppSettings import AppSettingsDlg
from ui.PdfProject import PdfProjectDlg
from ui.TreeNodeEditDialog import TreeNodeEditDialog
from ui.XslFileEditDialog import XslFileEditDialog
from ui.XmlToXslAssignDialog import XmlToXslAssignDialog
from conf import app_settings, Project, ProjectData, TreeNode, XslFile, XmlFile
from pathlib import Path
@@ -87,6 +88,9 @@ class MainWindow(QMainWindow):
# TreeWidget Styling für größeren vertikalen Abstand
self._setup_tree_widget_styling()
# Drag&Drop für TreeWidget aktivieren
self._setup_drag_drop()
def _setup_theme_menu(self):
"""Initialisiert das Theme-Menü mit verfügbaren Themes."""
@@ -1604,6 +1608,256 @@ class MainWindow(QMainWindow):
print(f"Fehler beim Speichern der Projekt-Einstellungen: {e}")
raise
def _setup_drag_drop(self):
"""Aktiviert Drag&Drop für das TreeWidget."""
try:
# Aktiviere Drag&Drop für das TreeWidget
self.ui.treeWidget.setAcceptDrops(True)
self.ui.treeWidget.setDragDropMode(self.ui.treeWidget.DragDropMode.DropOnly)
# Überschreibe die Drag&Drop-Events
self.ui.treeWidget.dragEnterEvent = self.tree_drag_enter_event
self.ui.treeWidget.dragMoveEvent = self.tree_drag_move_event
self.ui.treeWidget.dropEvent = self.tree_drop_event
print("Drag&Drop für TreeWidget aktiviert")
except Exception as e:
print(f"Fehler beim Aktivieren von Drag&Drop: {e}")
def tree_drag_enter_event(self, event: QDragEnterEvent):
"""
Wird ausgeführt, wenn ein Drag-Vorgang über das TreeWidget beginnt.
Args:
event: Das Drag-Enter-Event
"""
try:
# Prüfe ob URLs (Dateien) gedraggt werden
if event.mimeData().hasUrls():
urls = event.mimeData().urls()
# Prüfe ob mindestens eine XML-Datei dabei ist
xml_files = [url.toLocalFile() for url in urls
if url.toLocalFile().lower().endswith('.xml')]
if xml_files:
event.acceptProposedAction()
print(f"Drag-Enter akzeptiert: {len(xml_files)} XML-Dateien")
else:
event.ignore()
print("Drag-Enter ignoriert: Keine XML-Dateien")
else:
event.ignore()
print("Drag-Enter ignoriert: Keine URLs")
except Exception as e:
print(f"Fehler in tree_drag_enter_event: {e}")
event.ignore()
def tree_drag_move_event(self, event):
"""
Wird ausgeführt, wenn ein Drag-Vorgang über das TreeWidget bewegt wird.
Args:
event: Das Drag-Move-Event
"""
try:
# Prüfe ob URLs (Dateien) gedraggt werden
if event.mimeData().hasUrls():
urls = event.mimeData().urls()
# Prüfe ob mindestens eine XML-Datei dabei ist
xml_files = [url.toLocalFile() for url in urls
if url.toLocalFile().lower().endswith('.xml')]
if xml_files:
event.acceptProposedAction()
else:
event.ignore()
else:
event.ignore()
except Exception as e:
print(f"Fehler in tree_drag_move_event: {e}")
event.ignore()
def tree_drop_event(self, event: QDropEvent):
"""
Wird ausgeführt, wenn Dateien auf das TreeWidget gedroppt werden.
Args:
event: Das Drop-Event
"""
try:
# Prüfe ob ein Projekt geladen ist
if not hasattr(self, 'project') or not self.project:
QMessageBox.warning(self, "Warnung", "Kein Projekt geladen. Bitte öffnen Sie zuerst ein Projekt.")
event.ignore()
return
if not hasattr(self, 'pdf_project') or not self.pdf_project:
QMessageBox.warning(self, "Warnung", "Keine Projekt-Einstellungen geladen.")
event.ignore()
return
# Hole die URLs aus dem Drop-Event
if not event.mimeData().hasUrls():
event.ignore()
return
urls = event.mimeData().urls()
xml_files = []
# Sammle alle XML-Dateien
for url in urls:
file_path = url.toLocalFile()
if file_path.lower().endswith('.xml'):
xml_files.append(Path(file_path))
if not xml_files:
QMessageBox.information(self, "Information", "Keine XML-Dateien zum Hinzufügen gefunden.")
event.ignore()
return
print(f"Drop-Event: {len(xml_files)} XML-Dateien erkannt")
# Verarbeite jede XML-Datei einzeln
for xml_file_path in xml_files:
self._handle_xml_file_drop(xml_file_path)
event.acceptProposedAction()
except Exception as e:
error_msg = f"Fehler beim Verarbeiten des Drop-Events: {str(e)}"
print(error_msg)
QMessageBox.critical(self, "Fehler", error_msg)
event.ignore()
def _handle_xml_file_drop(self, xml_file_path: Path):
"""
Verarbeitet eine einzelne XML-Datei, die per Drag&Drop hinzugefügt wurde.
Args:
xml_file_path: Pfad zur XML-Datei
"""
try:
print(f"Verarbeite XML-Datei: {xml_file_path}")
# Prüfe ob die Datei existiert
if not xml_file_path.exists():
QMessageBox.critical(self, "Fehler", f"Die XML-Datei existiert nicht:\n{xml_file_path}")
return
# Öffne den Dialog zur Zuordnung zu XSL-Knoten
dialog = XmlToXslAssignDialog(
parent=self,
xml_file_path=xml_file_path,
project_nodes=self.pdf_project.nodes
)
if dialog.exec() == XmlToXslAssignDialog.DialogCode.Accepted:
# Hole die ausgewählten XSL-Knoten
selected_xsl_nodes = dialog.get_selected_xsl_nodes()
if selected_xsl_nodes:
# Verarbeite die Zuordnung
self._assign_xml_to_xsl_nodes(xml_file_path, selected_xsl_nodes)
else:
print("Keine XSL-Knoten ausgewählt")
else:
print("Dialog abgebrochen")
except Exception as e:
error_msg = f"Fehler beim Verarbeiten der XML-Datei '{xml_file_path}': {str(e)}"
print(error_msg)
QMessageBox.critical(self, "Fehler", error_msg)
def _assign_xml_to_xsl_nodes(self, xml_file_path: Path, selected_xsl_nodes: list):
"""
Ordnet eine XML-Datei den ausgewählten XSL-Knoten zu.
Args:
xml_file_path: Pfad zur XML-Datei
selected_xsl_nodes: Liste der ausgewählten XSL-Knoten
"""
try:
print(f"Ordne XML-Datei '{xml_file_path.name}' zu {len(selected_xsl_nodes)} XSL-Knoten zu")
# Erstelle xml-Ordner im Projekt-Verzeichnis falls er nicht existiert
xml_dir = Path(self.project.project_dir) / "xml"
xml_dir.mkdir(parents=True, exist_ok=True)
# Bestimme den Ziel-Pfad in xml-Ordner
target_xml_path = xml_dir / xml_file_path.name
# Prüfe ob eine Datei mit gleichem Namen bereits existiert
copy_file = True
if target_xml_path.exists():
reply = QMessageBox.question(
self,
"Datei existiert bereits",
f"Eine XML-Datei mit dem Namen '{xml_file_path.name}' existiert bereits im xml-Ordner.\n\n"
"Möchten Sie sie überschreiben?",
QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No,
QMessageBox.StandardButton.No
)
if reply != QMessageBox.StandardButton.Yes:
copy_file = False
# Kopiere die XML-Datei in den xml-Ordner (falls gewünscht)
if copy_file:
shutil.copy2(xml_file_path, target_xml_path)
print(f"XML-Datei kopiert: {xml_file_path} -> {target_xml_path}")
# Erstelle relatives Path zur XML-Datei (relativ zum xml-Ordner)
relative_xml_path = Path("xml") / xml_file_path.name
# Füge die XML-Datei zu allen ausgewählten XSL-Knoten hinzu
added_count = 0
for xsl_node in selected_xsl_nodes:
# Prüfe ob diese XML-Datei bereits in der XslFile-Node vorhanden ist
existing_xml = None
for xml_file in xsl_node.xmls:
if xml_file.xml == relative_xml_path:
existing_xml = xml_file
break
if not existing_xml:
# Erstelle neues XmlFile-Objekt und füge es zur XslFile-Node hinzu
new_xml_file = XmlFile(xml=relative_xml_path)
xsl_node.xmls.append(new_xml_file)
added_count += 1
print(f"XML-Datei '{xml_file_path.name}' zu XslFile-Node '{xsl_node.bez}' hinzugefügt")
else:
print(f"XML-Datei '{xml_file_path.name}' bereits in XslFile-Node '{xsl_node.bez}' vorhanden")
if added_count > 0:
# Speichere die aktualisierten Projekt-Einstellungen
self._save_project_settings()
# Aktualisiere das TreeWidget
self._load_nodes_to_tree()
# Zeige Erfolgsmeldung
QMessageBox.information(
self,
"Erfolg",
f"XML-Datei '{xml_file_path.name}' wurde erfolgreich zu {added_count} XSL-Knoten hinzugefügt."
)
else:
QMessageBox.information(
self,
"Information",
f"XML-Datei '{xml_file_path.name}' war bereits in allen ausgewählten XSL-Knoten vorhanden."
)
except Exception as e:
error_msg = f"Fehler beim Zuordnen der XML-Datei: {str(e)}"
print(error_msg)
QMessageBox.critical(self, "Fehler", error_msg)
def closeEvent(self, event):
"""Wird beim Schließen der Anwendung aufgerufen."""
# PDF-Dokumente schließen ist bei QtPdf automatisch durch Garbage Collection