Die Drag&Drop-Funktionalität für XML-Dateien
This commit is contained in:
+12
-6
@@ -1,8 +1,14 @@
|
|||||||
# Projekt allgemeines
|
# agents.md
|
||||||
- In diesem Projekt wirt uv Packetmanager verwendet.
|
|
||||||
|
Entwicklung mit Python und PySide6
|
||||||
|
|
||||||
|
## Richtlinien
|
||||||
|
|
||||||
|
### Allgemeines zum Projekt
|
||||||
|
- In diesem Projekt wird der uv Packetmanager verwendet.
|
||||||
|
|
||||||
## PySide6-GUI
|
## PySide6-GUI
|
||||||
- Beim Erstellen neuer Dialoge sollte stets eine passende UI-Datei erstellt werden.
|
- Beim Erstellen neuer Dialoge sollte immer eine passende UI-Datei erstellt werden.
|
||||||
- Der Entwickler soll den neuen Dialog später über die UI-Datei gestalten können.
|
- Der Entwickler sollte später in der Lage sein, den neuen Dialog über die UI-Datei zu gestalten.
|
||||||
- Die UI-Datei wird in Visual Studio Code durch eine Erweiterung automatisch als .py-Datei generiert.
|
- Aus der UI-Datei wird in Visual Studio Code über eine Erweiterung automatisch eine .py-Datei erzeugt.
|
||||||
- Die automatisch generierte .py-Datei muss in den Code eingebunden und genutzt werden.
|
- Die automatisch generierte .py-Datei muss in den Code eingebunden und verwendet werden.
|
||||||
|
|||||||
@@ -1,14 +1,14 @@
|
|||||||
# agents.md
|
# agents.md
|
||||||
|
|
||||||
Entwickeln mit Python und PySide6
|
Entwicklung mit Python und PySide6
|
||||||
|
|
||||||
## Richtlinien
|
## Richtlinien
|
||||||
|
|
||||||
### Projekt allgemeines
|
### Allgemeines zum Projekt
|
||||||
- In diesem Projekt wirt uv Packetmanager verwendet.
|
- In diesem Projekt wird der uv Packetmanager verwendet.
|
||||||
|
|
||||||
### PySide6-GUI
|
## PySide6-GUI
|
||||||
- Beim Erstellen neuer Dialoge sollte stets eine passende UI-Datei erstellt werden.
|
- Beim Erstellen neuer Dialoge sollte immer eine passende UI-Datei erstellt werden.
|
||||||
- Der Entwickler soll den neuen Dialog später über die UI-Datei gestalten können.
|
- Der Entwickler sollte später in der Lage sein, den neuen Dialog über die UI-Datei zu gestalten.
|
||||||
- Die UI-Datei wird in Visual Studio Code durch eine Erweiterung automatisch als .py-Datei generiert.
|
- Aus der UI-Datei wird in Visual Studio Code über eine Erweiterung automatisch eine .py-Datei erzeugt.
|
||||||
- Die automatisch generierte .py-Datei muss in den Code eingebunden und genutzt werden.
|
- Die automatisch generierte .py-Datei muss in den Code eingebunden und verwendet werden.
|
||||||
+256
-2
@@ -4,8 +4,8 @@ import time
|
|||||||
import polars as pl
|
import polars as pl
|
||||||
import shutil
|
import shutil
|
||||||
|
|
||||||
from PySide6.QtCore import Qt, QSize
|
from PySide6.QtCore import Qt, QSize, QUrl
|
||||||
from PySide6.QtGui import QCursor, QPixmap, QPainter, QAction, QIcon
|
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.QtWidgets import QLabel, QMainWindow, QApplication, QStyleFactory, QMenu, QTreeWidgetItem, QMessageBox, QFileDialog
|
||||||
from PySide6.QtPdf import QPdfDocument
|
from PySide6.QtPdf import QPdfDocument
|
||||||
|
|
||||||
@@ -14,6 +14,7 @@ from ui.AppSettings import AppSettingsDlg
|
|||||||
from ui.PdfProject import PdfProjectDlg
|
from ui.PdfProject import PdfProjectDlg
|
||||||
from ui.TreeNodeEditDialog import TreeNodeEditDialog
|
from ui.TreeNodeEditDialog import TreeNodeEditDialog
|
||||||
from ui.XslFileEditDialog import XslFileEditDialog
|
from ui.XslFileEditDialog import XslFileEditDialog
|
||||||
|
from ui.XmlToXslAssignDialog import XmlToXslAssignDialog
|
||||||
from conf import app_settings, Project, ProjectData, TreeNode, XslFile, XmlFile
|
from conf import app_settings, Project, ProjectData, TreeNode, XslFile, XmlFile
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
@@ -87,6 +88,9 @@ class MainWindow(QMainWindow):
|
|||||||
|
|
||||||
# TreeWidget Styling für größeren vertikalen Abstand
|
# TreeWidget Styling für größeren vertikalen Abstand
|
||||||
self._setup_tree_widget_styling()
|
self._setup_tree_widget_styling()
|
||||||
|
|
||||||
|
# Drag&Drop für TreeWidget aktivieren
|
||||||
|
self._setup_drag_drop()
|
||||||
|
|
||||||
def _setup_theme_menu(self):
|
def _setup_theme_menu(self):
|
||||||
"""Initialisiert das Theme-Menü mit verfügbaren Themes."""
|
"""Initialisiert das Theme-Menü mit verfügbaren Themes."""
|
||||||
@@ -1604,6 +1608,256 @@ class MainWindow(QMainWindow):
|
|||||||
print(f"Fehler beim Speichern der Projekt-Einstellungen: {e}")
|
print(f"Fehler beim Speichern der Projekt-Einstellungen: {e}")
|
||||||
raise
|
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):
|
def closeEvent(self, event):
|
||||||
"""Wird beim Schließen der Anwendung aufgerufen."""
|
"""Wird beim Schließen der Anwendung aufgerufen."""
|
||||||
# PDF-Dokumente schließen ist bei QtPdf automatisch durch Garbage Collection
|
# PDF-Dokumente schließen ist bei QtPdf automatisch durch Garbage Collection
|
||||||
|
|||||||
@@ -0,0 +1,226 @@
|
|||||||
|
from PySide6.QtWidgets import QDialog, QTreeWidgetItem, QCheckBox, QMessageBox
|
||||||
|
from PySide6.QtCore import Qt
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
from ui.XmlToXslAssignDialog_ui import Ui_XmlToXslAssignDialog
|
||||||
|
from conf import TreeNode, XslFile, XmlFile
|
||||||
|
|
||||||
|
|
||||||
|
class XmlToXslAssignDialog(QDialog):
|
||||||
|
"""Dialog zur Zuordnung einer XML-Datei zu XSL-Knoten."""
|
||||||
|
|
||||||
|
def __init__(self, parent=None, xml_file_path=None, project_nodes=None):
|
||||||
|
"""
|
||||||
|
Initialisiert den Dialog.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
parent: Übergeordnetes Widget
|
||||||
|
xml_file_path: Pfad zur XML-Datei
|
||||||
|
project_nodes: Liste der Projekt-Knoten
|
||||||
|
"""
|
||||||
|
super().__init__(parent)
|
||||||
|
|
||||||
|
# UI einrichten
|
||||||
|
self.ui = Ui_XmlToXslAssignDialog()
|
||||||
|
self.ui.setupUi(self)
|
||||||
|
|
||||||
|
# Parameter speichern
|
||||||
|
self.xml_file_path = Path(xml_file_path) if xml_file_path else None
|
||||||
|
self.project_nodes = project_nodes or []
|
||||||
|
|
||||||
|
# Dictionary zum Speichern der Checkbox-Referenzen
|
||||||
|
self.xsl_checkboxes = {} # {xsl_node_id: checkbox}
|
||||||
|
|
||||||
|
# Signale verbinden
|
||||||
|
self.ui.selectAllButton.clicked.connect(self.select_all)
|
||||||
|
self.ui.deselectAllButton.clicked.connect(self.deselect_all)
|
||||||
|
|
||||||
|
# Baum konfigurieren
|
||||||
|
self._setup_tree()
|
||||||
|
|
||||||
|
# Daten laden
|
||||||
|
self._load_data()
|
||||||
|
|
||||||
|
def _setup_tree(self):
|
||||||
|
"""Konfiguriert das TreeWidget."""
|
||||||
|
# Spaltenbreiten setzen
|
||||||
|
self.ui.xslNodesTree.setColumnWidth(0, 300) # XSL-Knoten
|
||||||
|
self.ui.xslNodesTree.setColumnWidth(1, 200) # Details
|
||||||
|
self.ui.xslNodesTree.setColumnWidth(2, 100) # Auswählen
|
||||||
|
|
||||||
|
# Header-Eigenschaften
|
||||||
|
self.ui.xslNodesTree.header().setStretchLastSection(False)
|
||||||
|
|
||||||
|
def _load_data(self):
|
||||||
|
"""Lädt die Daten in den Dialog."""
|
||||||
|
# XML-Datei-Label setzen
|
||||||
|
if self.xml_file_path:
|
||||||
|
self.ui.xmlFileLabel.setText(f"XML-Datei: {self.xml_file_path.name}")
|
||||||
|
|
||||||
|
# Projekt-Knoten in Baum laden
|
||||||
|
self._load_project_nodes()
|
||||||
|
|
||||||
|
def _load_project_nodes(self):
|
||||||
|
"""Lädt die Projekt-Knoten in das TreeWidget (ohne XML-Knoten)."""
|
||||||
|
if not self.project_nodes:
|
||||||
|
return
|
||||||
|
|
||||||
|
# TreeWidget leeren
|
||||||
|
self.ui.xslNodesTree.clear()
|
||||||
|
self.xsl_checkboxes.clear()
|
||||||
|
|
||||||
|
# Alle Root-Nodes laden
|
||||||
|
for node in self.project_nodes:
|
||||||
|
tree_item = self._create_tree_item_from_node(node)
|
||||||
|
if tree_item: # Nur hinzufügen wenn Item erstellt wurde
|
||||||
|
self.ui.xslNodesTree.addTopLevelItem(tree_item)
|
||||||
|
|
||||||
|
# Baum expandieren
|
||||||
|
self.ui.xslNodesTree.expandAll()
|
||||||
|
|
||||||
|
def _create_tree_item_from_node(self, node):
|
||||||
|
"""
|
||||||
|
Erstellt ein QTreeWidgetItem aus einem TreeNode oder XslFile.
|
||||||
|
XML-Knoten werden ausgeschlossen.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
node: TreeNode oder XslFile Objekt
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
QTreeWidgetItem: Das erstellte Tree-Item oder None wenn ausgeschlossen
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
# Erstelle Tree-Item
|
||||||
|
item = QTreeWidgetItem()
|
||||||
|
|
||||||
|
# Setze die Bezeichnung in Spalte 0
|
||||||
|
bez_text = str(node.bez) if node.bez else ""
|
||||||
|
item.setText(0, bez_text)
|
||||||
|
|
||||||
|
# Speichere das komplette Node-Objekt
|
||||||
|
item.setData(0, Qt.ItemDataRole.UserRole, node)
|
||||||
|
|
||||||
|
if isinstance(node, TreeNode):
|
||||||
|
# TreeNode: Zeige Anzahl der Knoten
|
||||||
|
child_count = len(node.children) if node.children else 0
|
||||||
|
item.setText(1, f"{child_count} Knoten")
|
||||||
|
|
||||||
|
# Lade Knoten rekursiv (nur TreeNode und XslFile, keine XML)
|
||||||
|
if node.children:
|
||||||
|
for child in node.children:
|
||||||
|
# Nur TreeNode und XslFile hinzufügen, keine XmlFile
|
||||||
|
if isinstance(child, (TreeNode, XslFile)):
|
||||||
|
child_item = self._create_tree_item_from_node(child)
|
||||||
|
if child_item:
|
||||||
|
item.addChild(child_item)
|
||||||
|
|
||||||
|
elif isinstance(node, XslFile):
|
||||||
|
# XslFile: Zeige XSL-Datei-Pfad und füge Checkbox hinzu
|
||||||
|
item.setText(1, str(node.xsl_file))
|
||||||
|
|
||||||
|
# Aktiviere Checkbox für dieses Item in Spalte 2
|
||||||
|
item.setFlags(item.flags() | Qt.ItemFlag.ItemIsUserCheckable)
|
||||||
|
item.setCheckState(2, Qt.CheckState.Unchecked)
|
||||||
|
|
||||||
|
# Speichere Item-Referenz für XSL-Knoten
|
||||||
|
self.xsl_checkboxes[id(node)] = item
|
||||||
|
|
||||||
|
# Keine Knoten für XslFile hinzufügen (XML-Dateien werden ausgeschlossen)
|
||||||
|
|
||||||
|
return item
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Fehler beim Erstellen des Tree-Items: {e}")
|
||||||
|
return None
|
||||||
|
|
||||||
|
def select_all(self):
|
||||||
|
"""Wählt alle XSL-Knoten aus."""
|
||||||
|
for item in self.xsl_checkboxes.values():
|
||||||
|
item.setCheckState(2, Qt.CheckState.Checked)
|
||||||
|
|
||||||
|
def deselect_all(self):
|
||||||
|
"""Wählt alle XSL-Knoten ab."""
|
||||||
|
for item in self.xsl_checkboxes.values():
|
||||||
|
item.setCheckState(2, Qt.CheckState.Unchecked)
|
||||||
|
|
||||||
|
def get_selected_xsl_nodes(self):
|
||||||
|
"""
|
||||||
|
Gibt die ausgewählten XSL-Knoten zurück.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
list[XslFile]: Liste der ausgewählten XSL-Knoten
|
||||||
|
"""
|
||||||
|
selected_nodes = []
|
||||||
|
|
||||||
|
try:
|
||||||
|
# Durchlaufe alle XSL-Items
|
||||||
|
for node_id, item in self.xsl_checkboxes.items():
|
||||||
|
if item.checkState(2) == Qt.CheckState.Checked:
|
||||||
|
# Finde den entsprechenden XSL-Knoten
|
||||||
|
xsl_node = self._find_xsl_node_by_id(node_id)
|
||||||
|
if xsl_node:
|
||||||
|
selected_nodes.append(xsl_node)
|
||||||
|
|
||||||
|
return selected_nodes
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Fehler beim Sammeln der ausgewählten XSL-Knoten: {e}")
|
||||||
|
return []
|
||||||
|
|
||||||
|
def _find_xsl_node_by_id(self, node_id):
|
||||||
|
"""
|
||||||
|
Findet einen XSL-Knoten anhand seiner ID.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
node_id: Die ID des Knotens (Python id())
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
XslFile: Der gefundene XSL-Knoten oder None
|
||||||
|
"""
|
||||||
|
return self._find_xsl_node_recursive(self.project_nodes, node_id)
|
||||||
|
|
||||||
|
def _find_xsl_node_recursive(self, nodes, target_id):
|
||||||
|
"""
|
||||||
|
Sucht rekursiv nach einem XSL-Knoten mit der angegebenen ID.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
nodes: Liste der Nodes zum Durchsuchen
|
||||||
|
target_id: Die zu suchende ID
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
XslFile: Der gefundene XSL-Knoten oder None
|
||||||
|
"""
|
||||||
|
for node in nodes:
|
||||||
|
if isinstance(node, XslFile) and id(node) == target_id:
|
||||||
|
return node
|
||||||
|
|
||||||
|
# Rekursiv in Knoten suchen (nur bei TreeNode)
|
||||||
|
if isinstance(node, TreeNode) and node.children:
|
||||||
|
found = self._find_xsl_node_recursive(node.children, target_id)
|
||||||
|
if found:
|
||||||
|
return found
|
||||||
|
|
||||||
|
return None
|
||||||
|
|
||||||
|
def get_xml_file_path(self):
|
||||||
|
"""
|
||||||
|
Gibt den Pfad zur XML-Datei zurück.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Path: Pfad zur XML-Datei
|
||||||
|
"""
|
||||||
|
return self.xml_file_path
|
||||||
|
|
||||||
|
def accept(self):
|
||||||
|
"""Überschreibt accept() um Validierung durchzuführen."""
|
||||||
|
selected_nodes = self.get_selected_xsl_nodes()
|
||||||
|
|
||||||
|
if not selected_nodes:
|
||||||
|
QMessageBox.warning(
|
||||||
|
self,
|
||||||
|
"Warnung",
|
||||||
|
"Bitte wählen Sie mindestens einen XSL-Knoten aus."
|
||||||
|
)
|
||||||
|
return
|
||||||
|
|
||||||
|
super().accept()
|
||||||
@@ -0,0 +1,155 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<ui version="4.0">
|
||||||
|
<class>XmlToXslAssignDialog</class>
|
||||||
|
<widget class="QDialog" name="XmlToXslAssignDialog">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>0</x>
|
||||||
|
<y>0</y>
|
||||||
|
<width>700</width>
|
||||||
|
<height>500</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="windowTitle">
|
||||||
|
<string>XML-Datei zu XSL-Knoten zuordnen</string>
|
||||||
|
</property>
|
||||||
|
<property name="modal">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<layout class="QVBoxLayout" name="verticalLayout">
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="infoLabel">
|
||||||
|
<property name="text">
|
||||||
|
<string>Wählen Sie die XSL-Knoten aus, denen die XML-Datei zugeordnet werden soll:</string>
|
||||||
|
</property>
|
||||||
|
<property name="wordWrap">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="xmlFileLabel">
|
||||||
|
<property name="styleSheet">
|
||||||
|
<string>font-weight: bold; color: #0066cc;</string>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>XML-Datei: [wird zur Laufzeit gesetzt]</string>
|
||||||
|
</property>
|
||||||
|
<property name="wordWrap">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QTreeWidget" name="xslNodesTree">
|
||||||
|
<property name="headerHidden">
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
|
<property name="columnCount">
|
||||||
|
<number>3</number>
|
||||||
|
</property>
|
||||||
|
<property name="alternatingRowColors">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<attribute name="headerVisible">
|
||||||
|
<bool>true</bool>
|
||||||
|
</attribute>
|
||||||
|
<column>
|
||||||
|
<property name="text">
|
||||||
|
<string>XSL-Knoten</string>
|
||||||
|
</property>
|
||||||
|
</column>
|
||||||
|
<column>
|
||||||
|
<property name="text">
|
||||||
|
<string>Details</string>
|
||||||
|
</property>
|
||||||
|
</column>
|
||||||
|
<column>
|
||||||
|
<property name="text">
|
||||||
|
<string>Auswählen</string>
|
||||||
|
</property>
|
||||||
|
</column>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<layout class="QHBoxLayout" name="buttonLayout">
|
||||||
|
<item>
|
||||||
|
<widget class="QPushButton" name="selectAllButton">
|
||||||
|
<property name="text">
|
||||||
|
<string>Alle auswählen</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QPushButton" name="deselectAllButton">
|
||||||
|
<property name="text">
|
||||||
|
<string>Alle abwählen</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<spacer name="horizontalSpacer">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Orientation::Horizontal</enum>
|
||||||
|
</property>
|
||||||
|
<property name="sizeHint" stdset="0">
|
||||||
|
<size>
|
||||||
|
<width>40</width>
|
||||||
|
<height>20</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
</spacer>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QDialogButtonBox" name="buttonBox">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Orientation::Horizontal</enum>
|
||||||
|
</property>
|
||||||
|
<property name="standardButtons">
|
||||||
|
<set>QDialogButtonBox::StandardButton::Cancel|QDialogButtonBox::StandardButton::Ok</set>
|
||||||
|
</property>
|
||||||
|
<property name="centerButtons">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
<resources/>
|
||||||
|
<connections>
|
||||||
|
<connection>
|
||||||
|
<sender>buttonBox</sender>
|
||||||
|
<signal>accepted()</signal>
|
||||||
|
<receiver>XmlToXslAssignDialog</receiver>
|
||||||
|
<slot>accept()</slot>
|
||||||
|
<hints>
|
||||||
|
<hint type="sourcelabel">
|
||||||
|
<x>248</x>
|
||||||
|
<y>254</y>
|
||||||
|
</hint>
|
||||||
|
<hint type="destinationlabel">
|
||||||
|
<x>157</x>
|
||||||
|
<y>274</y>
|
||||||
|
</hint>
|
||||||
|
</hints>
|
||||||
|
</connection>
|
||||||
|
<connection>
|
||||||
|
<sender>buttonBox</sender>
|
||||||
|
<signal>rejected()</signal>
|
||||||
|
<receiver>XmlToXslAssignDialog</receiver>
|
||||||
|
<slot>reject()</slot>
|
||||||
|
<hints>
|
||||||
|
<hint type="sourcelabel">
|
||||||
|
<x>316</x>
|
||||||
|
<y>260</y>
|
||||||
|
</hint>
|
||||||
|
<hint type="destinationlabel">
|
||||||
|
<x>286</x>
|
||||||
|
<y>274</y>
|
||||||
|
</hint>
|
||||||
|
</hints>
|
||||||
|
</connection>
|
||||||
|
</connections>
|
||||||
|
</ui>
|
||||||
@@ -0,0 +1,99 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
################################################################################
|
||||||
|
## Form generated from reading UI file 'XmlToXslAssignDialog.ui'
|
||||||
|
##
|
||||||
|
## Created by: Qt User Interface Compiler version 6.9.1
|
||||||
|
##
|
||||||
|
## WARNING! All changes made in this file will be lost when recompiling UI file!
|
||||||
|
################################################################################
|
||||||
|
|
||||||
|
from PySide6.QtCore import (QCoreApplication, QDate, QDateTime, QLocale,
|
||||||
|
QMetaObject, QObject, QPoint, QRect,
|
||||||
|
QSize, QTime, QUrl, Qt)
|
||||||
|
from PySide6.QtGui import (QBrush, QColor, QConicalGradient, QCursor,
|
||||||
|
QFont, QFontDatabase, QGradient, QIcon,
|
||||||
|
QImage, QKeySequence, QLinearGradient, QPainter,
|
||||||
|
QPalette, QPixmap, QRadialGradient, QTransform)
|
||||||
|
from PySide6.QtWidgets import (QAbstractButton, QApplication, QDialog, QDialogButtonBox,
|
||||||
|
QHBoxLayout, QHeaderView, QLabel, QPushButton,
|
||||||
|
QSizePolicy, QSpacerItem, QTreeWidget, QTreeWidgetItem,
|
||||||
|
QVBoxLayout, QWidget)
|
||||||
|
|
||||||
|
class Ui_XmlToXslAssignDialog(object):
|
||||||
|
def setupUi(self, XmlToXslAssignDialog):
|
||||||
|
if not XmlToXslAssignDialog.objectName():
|
||||||
|
XmlToXslAssignDialog.setObjectName(u"XmlToXslAssignDialog")
|
||||||
|
XmlToXslAssignDialog.resize(700, 500)
|
||||||
|
XmlToXslAssignDialog.setModal(True)
|
||||||
|
self.verticalLayout = QVBoxLayout(XmlToXslAssignDialog)
|
||||||
|
self.verticalLayout.setObjectName(u"verticalLayout")
|
||||||
|
self.infoLabel = QLabel(XmlToXslAssignDialog)
|
||||||
|
self.infoLabel.setObjectName(u"infoLabel")
|
||||||
|
self.infoLabel.setWordWrap(True)
|
||||||
|
|
||||||
|
self.verticalLayout.addWidget(self.infoLabel)
|
||||||
|
|
||||||
|
self.xmlFileLabel = QLabel(XmlToXslAssignDialog)
|
||||||
|
self.xmlFileLabel.setObjectName(u"xmlFileLabel")
|
||||||
|
self.xmlFileLabel.setWordWrap(True)
|
||||||
|
|
||||||
|
self.verticalLayout.addWidget(self.xmlFileLabel)
|
||||||
|
|
||||||
|
self.xslNodesTree = QTreeWidget(XmlToXslAssignDialog)
|
||||||
|
self.xslNodesTree.setObjectName(u"xslNodesTree")
|
||||||
|
self.xslNodesTree.setHeaderHidden(False)
|
||||||
|
self.xslNodesTree.setColumnCount(3)
|
||||||
|
self.xslNodesTree.setAlternatingRowColors(True)
|
||||||
|
self.xslNodesTree.header().setVisible(True)
|
||||||
|
|
||||||
|
self.verticalLayout.addWidget(self.xslNodesTree)
|
||||||
|
|
||||||
|
self.buttonLayout = QHBoxLayout()
|
||||||
|
self.buttonLayout.setObjectName(u"buttonLayout")
|
||||||
|
self.selectAllButton = QPushButton(XmlToXslAssignDialog)
|
||||||
|
self.selectAllButton.setObjectName(u"selectAllButton")
|
||||||
|
|
||||||
|
self.buttonLayout.addWidget(self.selectAllButton)
|
||||||
|
|
||||||
|
self.deselectAllButton = QPushButton(XmlToXslAssignDialog)
|
||||||
|
self.deselectAllButton.setObjectName(u"deselectAllButton")
|
||||||
|
|
||||||
|
self.buttonLayout.addWidget(self.deselectAllButton)
|
||||||
|
|
||||||
|
self.horizontalSpacer = QSpacerItem(40, 20, QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Minimum)
|
||||||
|
|
||||||
|
self.buttonLayout.addItem(self.horizontalSpacer)
|
||||||
|
|
||||||
|
|
||||||
|
self.verticalLayout.addLayout(self.buttonLayout)
|
||||||
|
|
||||||
|
self.buttonBox = QDialogButtonBox(XmlToXslAssignDialog)
|
||||||
|
self.buttonBox.setObjectName(u"buttonBox")
|
||||||
|
self.buttonBox.setOrientation(Qt.Orientation.Horizontal)
|
||||||
|
self.buttonBox.setStandardButtons(QDialogButtonBox.StandardButton.Cancel|QDialogButtonBox.StandardButton.Ok)
|
||||||
|
self.buttonBox.setCenterButtons(True)
|
||||||
|
|
||||||
|
self.verticalLayout.addWidget(self.buttonBox)
|
||||||
|
|
||||||
|
|
||||||
|
self.retranslateUi(XmlToXslAssignDialog)
|
||||||
|
self.buttonBox.accepted.connect(XmlToXslAssignDialog.accept)
|
||||||
|
self.buttonBox.rejected.connect(XmlToXslAssignDialog.reject)
|
||||||
|
|
||||||
|
QMetaObject.connectSlotsByName(XmlToXslAssignDialog)
|
||||||
|
# setupUi
|
||||||
|
|
||||||
|
def retranslateUi(self, XmlToXslAssignDialog):
|
||||||
|
XmlToXslAssignDialog.setWindowTitle(QCoreApplication.translate("XmlToXslAssignDialog", u"XML-Datei zu XSL-Knoten zuordnen", None))
|
||||||
|
self.infoLabel.setText(QCoreApplication.translate("XmlToXslAssignDialog", u"W\u00e4hlen Sie die XSL-Knoten aus, denen die XML-Datei zugeordnet werden soll:", None))
|
||||||
|
self.xmlFileLabel.setStyleSheet(QCoreApplication.translate("XmlToXslAssignDialog", u"font-weight: bold; color: #0066cc;", None))
|
||||||
|
self.xmlFileLabel.setText(QCoreApplication.translate("XmlToXslAssignDialog", u"XML-Datei: [wird zur Laufzeit gesetzt]", None))
|
||||||
|
___qtreewidgetitem = self.xslNodesTree.headerItem()
|
||||||
|
___qtreewidgetitem.setText(2, QCoreApplication.translate("XmlToXslAssignDialog", u"Ausw\u00e4hlen", None));
|
||||||
|
___qtreewidgetitem.setText(1, QCoreApplication.translate("XmlToXslAssignDialog", u"Details", None));
|
||||||
|
___qtreewidgetitem.setText(0, QCoreApplication.translate("XmlToXslAssignDialog", u"XSL-Knoten", None));
|
||||||
|
self.selectAllButton.setText(QCoreApplication.translate("XmlToXslAssignDialog", u"Alle ausw\u00e4hlen", None))
|
||||||
|
self.deselectAllButton.setText(QCoreApplication.translate("XmlToXslAssignDialog", u"Alle abw\u00e4hlen", None))
|
||||||
|
# retranslateUi
|
||||||
|
|
||||||
Reference in New Issue
Block a user