diff --git a/src/ui/MainWinddow.ui b/src/ui/MainWinddow.ui index 81df27c..1f94a8f 100644 --- a/src/ui/MainWinddow.ui +++ b/src/ui/MainWinddow.ui @@ -95,76 +95,6 @@ - - - - QFrame::Shadow::Raised - - - - 0 - - - 0 - - - 0 - - - 0 - - - - - Qt::LayoutDirection::LeftToRight - - - nur geänderte generieren - - - - - - - - - - false - - - Alle generieren - - - - - - - - - - Qt::Orientation::Horizontal - - - - 40 - 20 - - - - - - - - lade aus FN2 - - - - - - - - - @@ -188,8 +118,8 @@ 0 0 - 68 - 728 + 54 + 716 @@ -416,8 +346,8 @@ 0 0 - 726 - 697 + 881 + 684 @@ -449,7 +379,7 @@ 0 0 1263 - 22 + 33 @@ -469,7 +399,20 @@ Thema + + + false + + + Aktion + + + + + + + @@ -507,10 +450,36 @@ false + + + Vorhandene Projekte + + + Alle XML-Dateien transformieren + + + + + + + + Alle XML-Dateien neu transformieren (force) + + + + + FN2 + + + + + Aus Datenbank laden + + diff --git a/src/ui/MainWinddow_ui.py b/src/ui/MainWinddow_ui.py index c12381d..d64d08b 100644 --- a/src/ui/MainWinddow_ui.py +++ b/src/ui/MainWinddow_ui.py @@ -3,7 +3,7 @@ ################################################################################ ## Form generated from reading UI file 'MainWinddow.ui' ## -## Created by: Qt User Interface Compiler version 6.9.2 +## Created by: Qt User Interface Compiler version 6.10.1 ## ## WARNING! All changes made in this file will be lost when recompiling UI file! ################################################################################ @@ -42,6 +42,18 @@ class Ui_MainWindow(object): self.actionVorhandene_Projekte = QAction(MainWindow) self.actionVorhandene_Projekte.setObjectName(u"actionVorhandene_Projekte") self.actionVorhandene_Projekte.setEnabled(False) + icon3 = QIcon(QIcon.fromTheme(u"folder-open")) + self.actionVorhandene_Projekte.setIcon(icon3) + self.actionAlle_XML_Dateien_transformieren = QAction(MainWindow) + self.actionAlle_XML_Dateien_transformieren.setObjectName(u"actionAlle_XML_Dateien_transformieren") + self.actionAlle_XML_Dateien_neu_transformieren_force = QAction(MainWindow) + self.actionAlle_XML_Dateien_neu_transformieren_force.setObjectName(u"actionAlle_XML_Dateien_neu_transformieren_force") + icon4 = QIcon(QIcon.fromTheme(QIcon.ThemeIcon.ViewRefresh)) + self.actionAlle_XML_Dateien_neu_transformieren_force.setIcon(icon4) + self.actionFN2 = QAction(MainWindow) + self.actionFN2.setObjectName(u"actionFN2") + self.actionAus_Datenbank_laden = QAction(MainWindow) + self.actionAus_Datenbank_laden.setObjectName(u"actionAus_Datenbank_laden") self.centralwidget = QWidget(MainWindow) self.centralwidget.setObjectName(u"centralwidget") self.horizontalLayout = QHBoxLayout(self.centralwidget) @@ -83,42 +95,6 @@ class Ui_MainWindow(object): self.verticalLayout.addWidget(self.treeWidget) - self.frame_2 = QFrame(self.frame) - self.frame_2.setObjectName(u"frame_2") - self.frame_2.setFrameShadow(QFrame.Shadow.Raised) - self.horizontalLayout_2 = QHBoxLayout(self.frame_2) - self.horizontalLayout_2.setObjectName(u"horizontalLayout_2") - self.horizontalLayout_2.setContentsMargins(0, 0, 0, 0) - self.pushButton = QPushButton(self.frame_2) - self.pushButton.setObjectName(u"pushButton") - self.pushButton.setLayoutDirection(Qt.LayoutDirection.LeftToRight) - icon3 = QIcon(QIcon.fromTheme(QIcon.ThemeIcon.MediaPlaybackStart)) - self.pushButton.setIcon(icon3) - - self.horizontalLayout_2.addWidget(self.pushButton) - - self.pushButton_2 = QPushButton(self.frame_2) - self.pushButton_2.setObjectName(u"pushButton_2") - self.pushButton_2.setAutoFillBackground(False) - icon4 = QIcon(QIcon.fromTheme(QIcon.ThemeIcon.MediaSeekForward)) - self.pushButton_2.setIcon(icon4) - - self.horizontalLayout_2.addWidget(self.pushButton_2) - - self.horizontalSpacer = QSpacerItem(40, 20, QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Minimum) - - self.horizontalLayout_2.addItem(self.horizontalSpacer) - - self.pB_lade_aus_fn2 = QPushButton(self.frame_2) - self.pB_lade_aus_fn2.setObjectName(u"pB_lade_aus_fn2") - icon5 = QIcon(QIcon.fromTheme(QIcon.ThemeIcon.GoDown)) - self.pB_lade_aus_fn2.setIcon(icon5) - - self.horizontalLayout_2.addWidget(self.pB_lade_aus_fn2) - - - self.verticalLayout.addWidget(self.frame_2) - self.splitter.addWidget(self.frame) self.scrollArea = QScrollArea(self.splitter) self.scrollArea.setObjectName(u"scrollArea") @@ -132,7 +108,7 @@ class Ui_MainWindow(object): self.scrollArea.setWidgetResizable(True) self.scrollAreaWidgetContents = QWidget() self.scrollAreaWidgetContents.setObjectName(u"scrollAreaWidgetContents") - self.scrollAreaWidgetContents.setGeometry(QRect(0, 0, 68, 728)) + self.scrollAreaWidgetContents.setGeometry(QRect(0, 0, 54, 716)) self.verticalLayout_2 = QVBoxLayout(self.scrollAreaWidgetContents) self.verticalLayout_2.setObjectName(u"verticalLayout_2") self.label = QLabel(self.scrollAreaWidgetContents) @@ -234,7 +210,7 @@ class Ui_MainWindow(object): self.scrollArea_2.setWidgetResizable(True) self.scrollAreaWidgetContents_2 = QWidget() self.scrollAreaWidgetContents_2.setObjectName(u"scrollAreaWidgetContents_2") - self.scrollAreaWidgetContents_2.setGeometry(QRect(0, 0, 726, 697)) + self.scrollAreaWidgetContents_2.setGeometry(QRect(0, 0, 881, 684)) self.verticalLayout_3 = QVBoxLayout(self.scrollAreaWidgetContents_2) self.verticalLayout_3.setObjectName(u"verticalLayout_3") self.verticalLayout_3.setContentsMargins(0, 0, 0, 0) @@ -249,17 +225,21 @@ class Ui_MainWindow(object): MainWindow.setCentralWidget(self.centralwidget) self.menubar = QMenuBar(MainWindow) self.menubar.setObjectName(u"menubar") - self.menubar.setGeometry(QRect(0, 0, 1263, 22)) + self.menubar.setGeometry(QRect(0, 0, 1263, 33)) self.menuProjekt = QMenu(self.menubar) self.menuProjekt.setObjectName(u"menuProjekt") self.menuThema = QMenu(self.menubar) self.menuThema.setObjectName(u"menuThema") + self.menuAktion = QMenu(self.menubar) + self.menuAktion.setObjectName(u"menuAktion") + self.menuAktion.setEnabled(False) MainWindow.setMenuBar(self.menubar) self.statusbar = QStatusBar(MainWindow) self.statusbar.setObjectName(u"statusbar") MainWindow.setStatusBar(self.statusbar) self.menubar.addAction(self.menuProjekt.menuAction()) + self.menubar.addAction(self.menuAktion.menuAction()) self.menubar.addAction(self.menuThema.menuAction()) self.menuProjekt.addAction(self.actionNeu) self.menuProjekt.addSeparator() @@ -268,6 +248,10 @@ class Ui_MainWindow(object): self.menuProjekt.addAction(self.actionEinstellungen) self.menuProjekt.addSeparator() self.menuProjekt.addAction(self.actionBeenden) + self.menuAktion.addAction(self.actionAlle_XML_Dateien_transformieren) + self.menuAktion.addAction(self.actionAlle_XML_Dateien_neu_transformieren_force) + self.menuAktion.addSeparator() + self.menuAktion.addAction(self.actionAus_Datenbank_laden) self.retranslateUi(MainWindow) self.actionBeenden.triggered.connect(MainWindow.close) @@ -287,9 +271,10 @@ class Ui_MainWindow(object): self.actionEinstellungen.setShortcut(QCoreApplication.translate("MainWindow", u"Ctrl+S", None)) #endif // QT_CONFIG(shortcut) self.actionVorhandene_Projekte.setText(QCoreApplication.translate("MainWindow", u"Vorhandene Projekte", None)) - self.pushButton.setText(QCoreApplication.translate("MainWindow", u"nur ge\u00e4nderte generieren", None)) - self.pushButton_2.setText(QCoreApplication.translate("MainWindow", u"Alle generieren", None)) - self.pB_lade_aus_fn2.setText(QCoreApplication.translate("MainWindow", u"lade aus FN2", None)) + self.actionAlle_XML_Dateien_transformieren.setText(QCoreApplication.translate("MainWindow", u"Alle XML-Dateien transformieren", None)) + self.actionAlle_XML_Dateien_neu_transformieren_force.setText(QCoreApplication.translate("MainWindow", u"Alle XML-Dateien neu transformieren (force)", None)) + self.actionFN2.setText(QCoreApplication.translate("MainWindow", u"FN2", None)) + self.actionAus_Datenbank_laden.setText(QCoreApplication.translate("MainWindow", u"Aus Datenbank laden", None)) self.label.setText("") self.label_2.setText("") self.view_ref_pdf.setText(QCoreApplication.translate("MainWindow", u"Vorher (Referenz)", None)) @@ -304,5 +289,6 @@ class Ui_MainWindow(object): self.accept_changes.setText(QCoreApplication.translate("MainWindow", u"\u2705 \u00c4nderungen \u00fcbernehmen", None)) self.menuProjekt.setTitle(QCoreApplication.translate("MainWindow", u"Projekt", None)) self.menuThema.setTitle(QCoreApplication.translate("MainWindow", u"Thema", None)) + self.menuAktion.setTitle(QCoreApplication.translate("MainWindow", u"Aktion", None)) # retranslateUi diff --git a/src/ui/MainWindow.py b/src/ui/MainWindow.py index 072454b..6f09d6e 100644 --- a/src/ui/MainWindow.py +++ b/src/ui/MainWindow.py @@ -284,6 +284,10 @@ class MainWindow( # Worker-Pools werden jetzt erst beim Start der Transformation initialisiert (lazy loading) + # Aktiviere das Aktions-Menü, da ein Projekt geladen wurde + self.ui.menuAktion.setEnabled(True) + logger.info("Aktions-Menü aktiviert nach Projekt-Laden") + except Exception as e: logger.error(f"Fehler beim Laden des Projekts '{project.name}': {e}") # Fallback: Erstelle Standard-Einstellungen @@ -326,8 +330,6 @@ class MainWindow( def _connect_signals(self): """Verbindet Signale mit den entsprechenden Slots.""" - # Button-Klicks verbinden - self.ui.pushButton.clicked.connect(self.on_button_clicked) # Zoom-Slider verbinden self.ui.zoom.valueChanged.connect(self.apply_zoom) @@ -340,6 +342,8 @@ class MainWindow( # Menü-Aktionen verbinden self.ui.actionNeu.triggered.connect(self.open_new_project_dialog) self.ui.actionEinstellungen.triggered.connect(self.open_settings_dialog) + self.ui.actionAlle_XML_Dateien_transformieren.triggered.connect(self._transform_all_xml_files) + self.ui.actionAlle_XML_Dateien_neu_transformieren_force.triggered.connect(self._transform_all_xml_files_force) # Worker-Pool-Metriken Menüeintrag (programmatisch hinzufügen) from PySide6.QtGui import QAction @@ -360,8 +364,8 @@ class MainWindow( else: self.ui.menuProjekt.addAction(self.action_worker_metrics) - # Button "lade aus FN2" verbinden - self.ui.pB_lade_aus_fn2.clicked.connect(self.on_load_from_fn2_clicked) + # Menü-Aktion "Aus Datenbank laden" verbinden (macht das Gleiche wie Button) + self.ui.actionAus_Datenbank_laden.triggered.connect(self.on_load_from_fn2_clicked) # Button "Accept Changes" verbinden self.ui.accept_changes.clicked.connect(self._on_accept_changes_clicked) @@ -462,10 +466,6 @@ class MainWindow( logger.error(f"Fehler beim Erstellen der Projekt-Struktur: {e}") raise - def on_button_clicked(self): - """Wird ausgeführt, wenn der Button geklickt wird.""" - logger.debug("Button wurde geklickt!") - def _update_diff_icons_for_existing_pdfs(self): """ Durchläuft alle XML-Items und setzt Icons für bereits existierende Diff-PDFs. diff --git a/src/ui/mixins/transformation.py b/src/ui/mixins/transformation.py index efe348c..c251cd0 100644 --- a/src/ui/mixins/transformation.py +++ b/src/ui/mixins/transformation.py @@ -740,3 +740,128 @@ class TransformationMixin: "Abgeschlossen mit Fehlern", f"{successful_count} von {total_count} Transformationen erfolgreich\n{failed_count} fehlgeschlagen\n\nGesamtdauer: {duration_str}", ) + + def _transform_all_xml_files(self): + """ + Transformiert ALLE XML-Dateien in allen TreeNodes des TreeWidgets. + Nur Dateien, die nicht up-to-date sind, werden transformiert. + """ + try: + if not self.project or not self.pdf_project: + QMessageBox.warning(self, "Fehler", "Kein Projekt geladen") + return + + # Sammle alle XSL/XML-Paare aus allen Root-Nodes + all_jobs = [] + root = self.ui.treeWidget.invisibleRootItem() + + for i in range(root.childCount()): + root_item = root.child(i) + root_node = root_item.data(0, Qt.ItemDataRole.UserRole) + + if isinstance(root_node, TreeNode): + # Sammle alle XSL/XML-Paare rekursiv + xsl_xml_pairs = self._collect_all_xsl_xml_pairs_recursive(root_node, root_item) + + # Erstelle TransformationJobs + for xsl_file_obj, xml_file_obj, xsl_file_item in xsl_xml_pairs: + job = self._create_transformation_job(xsl_file_obj, xml_file_obj, xsl_file_item) + if job: + all_jobs.append(job) + + elif isinstance(root_node, XslFile): + # Direkt XslFile als Root-Element + for xml_file_obj in root_node.xmls: + job = self._create_transformation_job(root_node, xml_file_obj, root_item) + if job: + all_jobs.append(job) + + if not all_jobs: + QMessageBox.information(self, "Info", "Keine XML-Dateien zum Transformieren gefunden") + return + + # Frage Benutzer um Bestätigung + reply = QMessageBox.question( + self, + "Alle XML-Dateien transformieren", + f"Möchten Sie wirklich alle {len(all_jobs)} XML-Dateien transformieren?\n\n" + f"Nur Dateien mit Änderungen werden verarbeitet.", + QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No, + QMessageBox.StandardButton.Yes, + ) + + if reply != QMessageBox.StandardButton.Yes: + logger.info("Transformation abgebrochen durch Benutzer") + return + + logger.info(f"Starte Transformation für alle {len(all_jobs)} XML-Dateien (nicht-force)") + + # Starte Transformation in separatem Thread + self._start_transformation(all_jobs, force=False) + + except Exception as e: + logger.error(f"Fehler beim Transformieren aller XML-Dateien: {e}") + QMessageBox.critical(self, "Fehler", f"Fehler beim Starten der Transformation: {str(e)}") + + def _transform_all_xml_files_force(self): + """ + Transformiert ALLE XML-Dateien in allen TreeNodes des TreeWidgets (force). + Alle Dateien werden unabhängig vom Änderungsstatus neu transformiert. + """ + try: + if not self.project or not self.pdf_project: + QMessageBox.warning(self, "Fehler", "Kein Projekt geladen") + return + + # Sammle alle XSL/XML-Paare aus allen Root-Nodes + all_jobs = [] + root = self.ui.treeWidget.invisibleRootItem() + + for i in range(root.childCount()): + root_item = root.child(i) + root_node = root_item.data(0, Qt.ItemDataRole.UserRole) + + if isinstance(root_node, TreeNode): + # Sammle alle XSL/XML-Paare rekursiv + xsl_xml_pairs = self._collect_all_xsl_xml_pairs_recursive(root_node, root_item) + + # Erstelle TransformationJobs + for xsl_file_obj, xml_file_obj, xsl_file_item in xsl_xml_pairs: + job = self._create_transformation_job(xsl_file_obj, xml_file_obj, xsl_file_item) + if job: + all_jobs.append(job) + + elif isinstance(root_node, XslFile): + # Direkt XslFile als Root-Element + for xml_file_obj in root_node.xmls: + job = self._create_transformation_job(root_node, xml_file_obj, root_item) + if job: + all_jobs.append(job) + + if not all_jobs: + QMessageBox.information(self, "Info", "Keine XML-Dateien zum Transformieren gefunden") + return + + # Frage Benutzer um Bestätigung (mit Warnung wegen force) + reply = QMessageBox.question( + self, + "Alle XML-Dateien neu transformieren (force)", + f"Möchten Sie wirklich ALLE {len(all_jobs)} XML-Dateien NEU transformieren?\n\n" + f"⚠ WARNUNG: Im Force-Modus werden alle Dateien unabhängig von ihrem Status neu verarbeitet!\n" + f"Dies kann längere Zeit in Anspruch nehmen.", + QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No, + QMessageBox.StandardButton.No, + ) + + if reply != QMessageBox.StandardButton.Yes: + logger.info("Force-Transformation abgebrochen durch Benutzer") + return + + logger.info(f"Starte Force-Transformation für alle {len(all_jobs)} XML-Dateien") + + # Starte Transformation in separatem Thread (mit force=True) + self._start_transformation(all_jobs, force=True) + + except Exception as e: + logger.error(f"Fehler beim Force-Transformieren aller XML-Dateien: {e}") + QMessageBox.critical(self, "Fehler", f"Fehler beim Starten der Force-Transformation: {str(e)}")