UX: Performance-Einstellungen in Programmeinstellungen integriert

Performance-Einstellungen wurden vom separaten Menüeintrag in den
Programmeinstellungen-Dialog als eigener Tab verschoben:

- Neuer "Performance"-Tab in AppSettings.ui mit drei Konfigurationsbereichen:
  • ThreadPoolExecutor: Worker-Anzahl (1-32, Standard: 8)
  • SaxonWorkerPool: Toggle für persistente JVM-Prozesse
  • FopWorkerPool: Toggle für persistente JVM-Prozesse

- AppSettings.py erweitert:
  • _populate_performance_tab(): Lädt aktuelle Performance-Einstellungen
  • accept(): Speichert Performance-Einstellungen in app_settings

- MainWindow.py bereinigt:
  • _setup_performance_menu() entfernt
  • _open_performance_settings() entfernt
  • Separater Menüeintrag im Projekt-Menü entfernt

- AppSettings_ui.py mit pyside6-uic neu generiert

Vorteile: Alle Programmeinstellungen sind nun zentral an einem Ort
verfügbar, bessere Benutzererfahrung durch konsistente UI-Struktur.

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

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
2026-01-04 19:01:46 +01:00
parent a7a69d27d7
commit 6976d21768
5 changed files with 624 additions and 556 deletions
+2 -2
View File
@@ -7,8 +7,8 @@ Spreche mit mir auf Deutsch! (Communicate with me in German!)
DocuMentor (ehemals xsl-validator) ist eine PySide6-basierte Desktop-Anwendung zur Verwaltung und Validierung von XSL-Transformationen mit XML-Dateien. Sie bietet eine GUI zur Konfiguration von Transformations-Toolchains (Saxon, Apache FOP, diff-pdf) und zur Verwaltung von PDF-Generierungsprojekten mit PostgreSQL-Datenbankintegration. DocuMentor (ehemals xsl-validator) ist eine PySide6-basierte Desktop-Anwendung zur Verwaltung und Validierung von XSL-Transformationen mit XML-Dateien. Sie bietet eine GUI zur Konfiguration von Transformations-Toolchains (Saxon, Apache FOP, diff-pdf) und zur Verwaltung von PDF-Generierungsprojekten mit PostgreSQL-Datenbankintegration.
## PySide6-GUI ## PySide6-GUI
- Beim Erstellen neuer Dialoge sollte immer eine passende UI-Datei erstellt werden - Beim Erstellen neuer Dialoge und Fenster sollte immer eine entsprechende UI-Datei erstellt werden
- Der Entwickler sollte später in der Lage sein, den neuen Dialog über die UI-Datei zu gestalten - Der Entwickler sollte später in der Lage sein, den neuen Dialog bzw. Fenster über diese UI-Datei zu gestalten
- Aus der UI-Datei wird in Visual Studio Code über eine Erweiterung automatisch eine .py-Datei erzeugt - 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 verwendet werden - Die automatisch generierte .py-Datei muss in den Code eingebunden und verwendet werden
+19
View File
@@ -46,6 +46,9 @@ class AppSettingsDlg(QDialog):
self._setup_tables() self._setup_tables()
self._populate_tables() self._populate_tables()
# Performance-Tab initialisieren
self._populate_performance_tab()
def _connect_signals(self): def _connect_signals(self):
"""Verbindet die Signale der UI-Elemente.""" """Verbindet die Signale der UI-Elemente."""
# XSL-Ordner Tab # XSL-Ordner Tab
@@ -271,6 +274,17 @@ class AppSettingsDlg(QDialog):
self.ui.tablePostgreSqlDbs.setItem(row, 4, username_item) self.ui.tablePostgreSqlDbs.setItem(row, 4, username_item)
self.ui.tablePostgreSqlDbs.horizontalHeader().setSectionResizeMode(QHeaderView.ResizeMode.ResizeToContents) self.ui.tablePostgreSqlDbs.horizontalHeader().setSectionResizeMode(QHeaderView.ResizeMode.ResizeToContents)
def _populate_performance_tab(self):
"""Initialisiert den Performance-Tab mit den aktuellen Einstellungen."""
# Worker-Anzahl setzen
self.ui.spinBoxWorkerCount.setValue(self.settings.max_workers)
# SaxonWorkerPool-Checkbox setzen
self.ui.checkBoxUseSaxonPool.setChecked(self.settings.use_saxon_worker_pool)
# FopWorkerPool-Checkbox setzen
self.ui.checkBoxUseFopPool.setChecked(self.settings.use_fop_worker_pool)
# XSL-Ordner Methoden # XSL-Ordner Methoden
def _add_xsl_dir(self): def _add_xsl_dir(self):
"""Fügt einen neuen XSL-Ordner hinzu.""" """Fügt einen neuen XSL-Ordner hinzu."""
@@ -723,6 +737,11 @@ class AppSettingsDlg(QDialog):
self.settings.xsl_dirs = self.temp_xsl_dirs.copy() self.settings.xsl_dirs = self.temp_xsl_dirs.copy()
self.settings.pdf_projects = self.temp_pdf_projects.copy() self.settings.pdf_projects = self.temp_pdf_projects.copy()
# Performance-Einstellungen übernehmen
self.settings.max_workers = self.ui.spinBoxWorkerCount.value()
self.settings.use_saxon_worker_pool = self.ui.checkBoxUseSaxonPool.isChecked()
self.settings.use_fop_worker_pool = self.ui.checkBoxUseFopPool.isChecked()
self.settings.save() self.settings.save()
super().accept() super().accept()
+141 -1
View File
@@ -7,7 +7,7 @@
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>833</width> <width>833</width>
<height>387</height> <height>446</height>
</rect> </rect>
</property> </property>
<property name="windowTitle"> <property name="windowTitle">
@@ -520,6 +520,146 @@
</item> </item>
</layout> </layout>
</widget> </widget>
<widget class="QWidget" name="tabPerformance">
<attribute name="title">
<string>Performance</string>
</attribute>
<layout class="QVBoxLayout" name="verticalLayout_9">
<item>
<widget class="QGroupBox" name="groupBoxWorker">
<property name="title">
<string>ThreadPoolExecutor Einstellungen</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_10">
<item>
<widget class="QLabel" name="labelWorkerCount">
<property name="text">
<string>Anzahl paralleler Worker für Transformationen:</string>
</property>
</widget>
</item>
<item>
<widget class="QSpinBox" name="spinBoxWorkerCount">
<property name="toolTip">
<string>Anzahl der parallelen Worker-Threads für Transformationen (Standard: 8)</string>
</property>
<property name="minimum">
<number>1</number>
</property>
<property name="maximum">
<number>32</number>
</property>
<property name="value">
<number>8</number>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="groupBoxSaxonPool">
<property name="title">
<string>SaxonWorkerPool Einstellungen</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_11">
<item>
<widget class="QCheckBox" name="checkBoxUseSaxonPool">
<property name="toolTip">
<string>Aktiviert persistente JVM-Prozesse für Saxon-Transformationen.
Vorteile: Bis zu 10x schneller durch Eliminierung von JVM-Startup-Overhead
Nachteile: Benötigt JDK (javac) - funktioniert nicht mit JRE allein
Deaktivieren Sie diese Option, wenn:
• Sie nur ein JRE (keine JDK) installiert haben
• Sie Probleme mit dem Worker-Pool haben
• Sie die Funktion testen möchten</string>
</property>
<property name="text">
<string>SaxonWorkerPool verwenden (empfohlen)</string>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="labelSaxonPoolInfo">
<property name="text">
<string>&lt;i&gt;Hinweis: SaxonWorkerPool benötigt ein JDK (Java Development Kit).&lt;br&gt;Mit JRE allein werden Transformationen im Fallback-Modus ausgeführt.&lt;/i&gt;</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="groupBoxFopPool">
<property name="title">
<string>FopWorkerPool Einstellungen</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_12">
<item>
<widget class="QCheckBox" name="checkBoxUseFopPool">
<property name="toolTip">
<string>Aktiviert persistente JVM-Prozesse für Apache FOP PDF-Generierung.
Vorteile: Bis zu 10x schneller durch Eliminierung von JVM-Startup-Overhead
Nachteile: Benötigt JDK (javac) - funktioniert nicht mit JRE allein
Deaktivieren Sie diese Option, wenn:
• Sie nur ein JRE (keine JDK) installiert haben
• Sie Probleme mit dem Worker-Pool haben
• Sie die Funktion testen möchten</string>
</property>
<property name="text">
<string>FopWorkerPool verwenden (empfohlen)</string>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="labelFopPoolInfo">
<property name="text">
<string>&lt;i&gt;Hinweis: FopWorkerPool benötigt ein JDK (Java Development Kit).&lt;br&gt;Mit JRE allein werden PDFs im Fallback-Modus generiert.&lt;/i&gt;</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QLabel" name="label">
<property name="mouseTracking">
<bool>true</bool>
</property>
<property name="text">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;span style=&quot; font-weight:700; font-style:italic;&quot;&gt;Hinweis: Änderungen in diesem Dialog sind unter Umständen erst nach neu start der Anwendung wirksam.&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="alignment">
<set>Qt::AlignmentFlag::AlignCenter</set>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<spacer name="verticalSpacerPerformance">
<property name="orientation">
<enum>Qt::Orientation::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
</widget> </widget>
</item> </item>
<item> <item>
+113 -6
View File
@@ -3,7 +3,7 @@
################################################################################ ################################################################################
## Form generated from reading UI file 'AppSettings.ui' ## Form generated from reading UI file 'AppSettings.ui'
## ##
## Created by: Qt User Interface Compiler version 6.9.1 ## Created by: Qt User Interface Compiler version 6.9.2
## ##
## WARNING! All changes made in this file will be lost when recompiling UI file! ## WARNING! All changes made in this file will be lost when recompiling UI file!
################################################################################ ################################################################################
@@ -15,16 +15,17 @@ from PySide6.QtGui import (QBrush, QColor, QConicalGradient, QCursor,
QFont, QFontDatabase, QGradient, QIcon, QFont, QFontDatabase, QGradient, QIcon,
QImage, QKeySequence, QLinearGradient, QPainter, QImage, QKeySequence, QLinearGradient, QPainter,
QPalette, QPixmap, QRadialGradient, QTransform) QPalette, QPixmap, QRadialGradient, QTransform)
from PySide6.QtWidgets import (QAbstractButton, QApplication, QDialog, QDialogButtonBox, from PySide6.QtWidgets import (QAbstractButton, QApplication, QCheckBox, QDialog,
QFrame, QHBoxLayout, QHeaderView, QPushButton, QDialogButtonBox, QFrame, QGroupBox, QHBoxLayout,
QSizePolicy, QTabWidget, QTableWidget, QTableWidgetItem, QHeaderView, QLabel, QPushButton, QSizePolicy,
QVBoxLayout, QWidget) QSpacerItem, QSpinBox, QTabWidget, QTableWidget,
QTableWidgetItem, QVBoxLayout, QWidget)
class Ui_Dialog(object): class Ui_Dialog(object):
def setupUi(self, Dialog): def setupUi(self, Dialog):
if not Dialog.objectName(): if not Dialog.objectName():
Dialog.setObjectName(u"Dialog") Dialog.setObjectName(u"Dialog")
Dialog.resize(833, 387) Dialog.resize(833, 446)
self.verticalLayout = QVBoxLayout(Dialog) self.verticalLayout = QVBoxLayout(Dialog)
self.verticalLayout.setObjectName(u"verticalLayout") self.verticalLayout.setObjectName(u"verticalLayout")
self.tabSettings = QTabWidget(Dialog) self.tabSettings = QTabWidget(Dialog)
@@ -302,6 +303,79 @@ class Ui_Dialog(object):
self.verticalLayout_7.addWidget(self.frame_6) self.verticalLayout_7.addWidget(self.frame_6)
self.tabSettings.addTab(self.tabPdfProject, "") self.tabSettings.addTab(self.tabPdfProject, "")
self.tabPerformance = QWidget()
self.tabPerformance.setObjectName(u"tabPerformance")
self.verticalLayout_9 = QVBoxLayout(self.tabPerformance)
self.verticalLayout_9.setObjectName(u"verticalLayout_9")
self.groupBoxWorker = QGroupBox(self.tabPerformance)
self.groupBoxWorker.setObjectName(u"groupBoxWorker")
self.verticalLayout_10 = QVBoxLayout(self.groupBoxWorker)
self.verticalLayout_10.setObjectName(u"verticalLayout_10")
self.labelWorkerCount = QLabel(self.groupBoxWorker)
self.labelWorkerCount.setObjectName(u"labelWorkerCount")
self.verticalLayout_10.addWidget(self.labelWorkerCount)
self.spinBoxWorkerCount = QSpinBox(self.groupBoxWorker)
self.spinBoxWorkerCount.setObjectName(u"spinBoxWorkerCount")
self.spinBoxWorkerCount.setMinimum(1)
self.spinBoxWorkerCount.setMaximum(32)
self.spinBoxWorkerCount.setValue(8)
self.verticalLayout_10.addWidget(self.spinBoxWorkerCount)
self.verticalLayout_9.addWidget(self.groupBoxWorker)
self.groupBoxSaxonPool = QGroupBox(self.tabPerformance)
self.groupBoxSaxonPool.setObjectName(u"groupBoxSaxonPool")
self.verticalLayout_11 = QVBoxLayout(self.groupBoxSaxonPool)
self.verticalLayout_11.setObjectName(u"verticalLayout_11")
self.checkBoxUseSaxonPool = QCheckBox(self.groupBoxSaxonPool)
self.checkBoxUseSaxonPool.setObjectName(u"checkBoxUseSaxonPool")
self.verticalLayout_11.addWidget(self.checkBoxUseSaxonPool)
self.labelSaxonPoolInfo = QLabel(self.groupBoxSaxonPool)
self.labelSaxonPoolInfo.setObjectName(u"labelSaxonPoolInfo")
self.labelSaxonPoolInfo.setWordWrap(True)
self.verticalLayout_11.addWidget(self.labelSaxonPoolInfo)
self.verticalLayout_9.addWidget(self.groupBoxSaxonPool)
self.groupBoxFopPool = QGroupBox(self.tabPerformance)
self.groupBoxFopPool.setObjectName(u"groupBoxFopPool")
self.verticalLayout_12 = QVBoxLayout(self.groupBoxFopPool)
self.verticalLayout_12.setObjectName(u"verticalLayout_12")
self.checkBoxUseFopPool = QCheckBox(self.groupBoxFopPool)
self.checkBoxUseFopPool.setObjectName(u"checkBoxUseFopPool")
self.verticalLayout_12.addWidget(self.checkBoxUseFopPool)
self.labelFopPoolInfo = QLabel(self.groupBoxFopPool)
self.labelFopPoolInfo.setObjectName(u"labelFopPoolInfo")
self.labelFopPoolInfo.setWordWrap(True)
self.verticalLayout_12.addWidget(self.labelFopPoolInfo)
self.verticalLayout_9.addWidget(self.groupBoxFopPool)
self.label = QLabel(self.tabPerformance)
self.label.setObjectName(u"label")
self.label.setMouseTracking(True)
self.label.setAlignment(Qt.AlignmentFlag.AlignCenter)
self.label.setWordWrap(True)
self.verticalLayout_9.addWidget(self.label)
self.verticalSpacerPerformance = QSpacerItem(20, 40, QSizePolicy.Policy.Minimum, QSizePolicy.Policy.Expanding)
self.verticalLayout_9.addItem(self.verticalSpacerPerformance)
self.tabSettings.addTab(self.tabPerformance, "")
self.verticalLayout.addWidget(self.tabSettings) self.verticalLayout.addWidget(self.tabSettings)
@@ -347,5 +421,38 @@ class Ui_Dialog(object):
self.addProject.setText(QCoreApplication.translate("Dialog", u"Hinzuf\u00fcgen", None)) self.addProject.setText(QCoreApplication.translate("Dialog", u"Hinzuf\u00fcgen", None))
self.removeProject.setText(QCoreApplication.translate("Dialog", u"Entfernen", None)) self.removeProject.setText(QCoreApplication.translate("Dialog", u"Entfernen", None))
self.tabSettings.setTabText(self.tabSettings.indexOf(self.tabPdfProject), QCoreApplication.translate("Dialog", u"PDF-Projekte", None)) self.tabSettings.setTabText(self.tabSettings.indexOf(self.tabPdfProject), QCoreApplication.translate("Dialog", u"PDF-Projekte", None))
self.groupBoxWorker.setTitle(QCoreApplication.translate("Dialog", u"ThreadPoolExecutor Einstellungen", None))
self.labelWorkerCount.setText(QCoreApplication.translate("Dialog", u"Anzahl paralleler Worker f\u00fcr Transformationen:", None))
#if QT_CONFIG(tooltip)
self.spinBoxWorkerCount.setToolTip(QCoreApplication.translate("Dialog", u"Anzahl der parallelen Worker-Threads f\u00fcr Transformationen (Standard: 8)", None))
#endif // QT_CONFIG(tooltip)
self.groupBoxSaxonPool.setTitle(QCoreApplication.translate("Dialog", u"SaxonWorkerPool Einstellungen", None))
#if QT_CONFIG(tooltip)
self.checkBoxUseSaxonPool.setToolTip(QCoreApplication.translate("Dialog", u"Aktiviert persistente JVM-Prozesse f\u00fcr Saxon-Transformationen.\n"
"Vorteile: Bis zu 10x schneller durch Eliminierung von JVM-Startup-Overhead\n"
"Nachteile: Ben\u00f6tigt JDK (javac) - funktioniert nicht mit JRE allein\n"
"\n"
"Deaktivieren Sie diese Option, wenn:\n"
"\u2022 Sie nur ein JRE (keine JDK) installiert haben\n"
"\u2022 Sie Probleme mit dem Worker-Pool haben\n"
"\u2022 Sie die Funktion testen m\u00f6chten", None))
#endif // QT_CONFIG(tooltip)
self.checkBoxUseSaxonPool.setText(QCoreApplication.translate("Dialog", u"SaxonWorkerPool verwenden (empfohlen)", None))
self.labelSaxonPoolInfo.setText(QCoreApplication.translate("Dialog", u"<i>Hinweis: SaxonWorkerPool ben\u00f6tigt ein JDK (Java Development Kit).<br>Mit JRE allein werden Transformationen im Fallback-Modus ausgef\u00fchrt.</i>", None))
self.groupBoxFopPool.setTitle(QCoreApplication.translate("Dialog", u"FopWorkerPool Einstellungen", None))
#if QT_CONFIG(tooltip)
self.checkBoxUseFopPool.setToolTip(QCoreApplication.translate("Dialog", u"Aktiviert persistente JVM-Prozesse f\u00fcr Apache FOP PDF-Generierung.\n"
"Vorteile: Bis zu 10x schneller durch Eliminierung von JVM-Startup-Overhead\n"
"Nachteile: Ben\u00f6tigt JDK (javac) - funktioniert nicht mit JRE allein\n"
"\n"
"Deaktivieren Sie diese Option, wenn:\n"
"\u2022 Sie nur ein JRE (keine JDK) installiert haben\n"
"\u2022 Sie Probleme mit dem Worker-Pool haben\n"
"\u2022 Sie die Funktion testen m\u00f6chten", None))
#endif // QT_CONFIG(tooltip)
self.checkBoxUseFopPool.setText(QCoreApplication.translate("Dialog", u"FopWorkerPool verwenden (empfohlen)", None))
self.labelFopPoolInfo.setText(QCoreApplication.translate("Dialog", u"<i>Hinweis: FopWorkerPool ben\u00f6tigt ein JDK (Java Development Kit).<br>Mit JRE allein werden PDFs im Fallback-Modus generiert.</i>", None))
self.label.setText(QCoreApplication.translate("Dialog", u"<html><head/><body><p><span style=\" font-weight:700; font-style:italic;\">Hinweis: \u00c4nderungen in diesem Dialog sind unter Umst\u00e4nden erst nach neu start der Anwendung wirksam.</span></p></body></html>", None))
self.tabSettings.setTabText(self.tabSettings.indexOf(self.tabPerformance), QCoreApplication.translate("Dialog", u"Performance", None))
# retranslateUi # retranslateUi
-198
View File
@@ -554,9 +554,6 @@ class MainWindow(QMainWindow):
# Vorhandene Projekte-Menü initialisieren # Vorhandene Projekte-Menü initialisieren
self._setup_projects_menu() self._setup_projects_menu()
# Performance-Einstellungen-Menü initialisieren
self._setup_performance_menu()
# #
if theme := app_settings.theme: if theme := app_settings.theme:
self.change_theme(theme) self.change_theme(theme)
@@ -655,201 +652,6 @@ class MainWindow(QMainWindow):
logger.info(f"Projekte-Menü initialisiert mit {len(app_settings.pdf_projects)} Projekten") logger.info(f"Projekte-Menü initialisiert mit {len(app_settings.pdf_projects)} Projekten")
def _setup_performance_menu(self):
"""Fügt ein Menü-Item für Performance-Einstellungen hinzu."""
# Füge Separator vor der Performance-Einstellung hinzu
self.ui.menuProjekt.addSeparator()
# Erstelle Aktion für Performance-Einstellungen
performance_action = QAction("Performance-Einstellungen...", self)
saxon_pool_status = "aktiviert" if app_settings.use_saxon_worker_pool else "deaktiviert"
fop_pool_status = "aktiviert" if app_settings.use_fop_worker_pool else "deaktiviert"
performance_action.setToolTip(
f"Worker: {app_settings.max_workers} | SaxonWorkerPool: {saxon_pool_status} | FopWorkerPool: {fop_pool_status}"
)
performance_action.triggered.connect(self._open_performance_settings)
# Füge die Aktion zum Projekt-Menü hinzu
self.ui.menuProjekt.addAction(performance_action)
logger.debug(f"Performance-Menü initialisiert (max_workers={app_settings.max_workers})")
def _open_performance_settings(self):
"""Öffnet einen Dialog für Performance-Einstellungen."""
from PySide6.QtWidgets import (
QDialog,
QVBoxLayout,
QHBoxLayout,
QLabel,
QSpinBox,
QCheckBox,
QPushButton,
QGroupBox,
)
# Erstelle benutzerdefinierten Dialog
dialog = QDialog(self)
dialog.setWindowTitle("Performance-Einstellungen")
dialog.setMinimumWidth(450)
layout = QVBoxLayout()
# Worker-Anzahl Einstellung
worker_group = QGroupBox("ThreadPoolExecutor Einstellungen")
worker_layout = QVBoxLayout()
worker_label = QLabel("Anzahl paralleler Worker für Transformationen:")
worker_spinbox = QSpinBox()
worker_spinbox.setMinimum(1)
worker_spinbox.setMaximum(32)
worker_spinbox.setValue(app_settings.max_workers)
worker_spinbox.setToolTip("Anzahl der parallelen Worker-Threads für Transformationen (Standard: 8)")
worker_layout.addWidget(worker_label)
worker_layout.addWidget(worker_spinbox)
worker_group.setLayout(worker_layout)
layout.addWidget(worker_group)
# SaxonWorkerPool Einstellung
pool_group = QGroupBox("SaxonWorkerPool Einstellungen")
pool_layout = QVBoxLayout()
pool_checkbox = QCheckBox("SaxonWorkerPool verwenden (empfohlen)")
pool_checkbox.setChecked(app_settings.use_saxon_worker_pool)
pool_checkbox.setToolTip(
"Aktiviert persistente JVM-Prozesse für Saxon-Transformationen.\n"
"Vorteile: Bis zu 10x schneller durch Eliminierung von JVM-Startup-Overhead\n"
"Nachteile: Benötigt JDK (javac) - funktioniert nicht mit JRE allein\n\n"
"Deaktivieren Sie diese Option, wenn:\n"
"• Sie nur ein JRE (keine JDK) installiert haben\n"
"• Sie Probleme mit dem Worker-Pool haben\n"
"• Sie die Funktion testen möchten"
)
pool_info = QLabel(
"<i>Hinweis: SaxonWorkerPool benötigt ein JDK (Java Development Kit).<br>"
"Mit JRE allein werden Transformationen im Fallback-Modus ausgeführt.</i>"
)
pool_info.setWordWrap(True)
pool_layout.addWidget(pool_checkbox)
pool_layout.addWidget(pool_info)
pool_group.setLayout(pool_layout)
layout.addWidget(pool_group)
# FopWorkerPool Einstellung
fop_pool_group = QGroupBox("FopWorkerPool Einstellungen")
fop_pool_layout = QVBoxLayout()
fop_pool_checkbox = QCheckBox("FopWorkerPool verwenden (empfohlen)")
fop_pool_checkbox.setChecked(app_settings.use_fop_worker_pool)
fop_pool_checkbox.setToolTip(
"Aktiviert persistente JVM-Prozesse für Apache FOP PDF-Generierung.\n"
"Vorteile: Bis zu 10x schneller durch Eliminierung von JVM-Startup-Overhead\n"
"Nachteile: Benötigt JDK (javac) - funktioniert nicht mit JRE allein\n\n"
"Deaktivieren Sie diese Option, wenn:\n"
"• Sie nur ein JRE (keine JDK) installiert haben\n"
"• Sie Probleme mit dem Worker-Pool haben\n"
"• Sie die Funktion testen möchten"
)
fop_pool_info = QLabel(
"<i>Hinweis: FopWorkerPool benötigt ein JDK (Java Development Kit).<br>"
"Mit JRE allein werden PDFs im Fallback-Modus generiert.</i>"
)
fop_pool_info.setWordWrap(True)
fop_pool_layout.addWidget(fop_pool_checkbox)
fop_pool_layout.addWidget(fop_pool_info)
fop_pool_group.setLayout(fop_pool_layout)
layout.addWidget(fop_pool_group)
# OK/Abbrechen Buttons
button_layout = QHBoxLayout()
ok_button = QPushButton("OK")
cancel_button = QPushButton("Abbrechen")
ok_button.clicked.connect(dialog.accept)
cancel_button.clicked.connect(dialog.reject)
button_layout.addStretch()
button_layout.addWidget(ok_button)
button_layout.addWidget(cancel_button)
layout.addLayout(button_layout)
dialog.setLayout(layout)
# Dialog anzeigen
if dialog.exec() == QDialog.DialogCode.Accepted:
# Speichere Änderungen
current_workers = app_settings.max_workers
current_use_pool = app_settings.use_saxon_worker_pool
current_use_fop_pool = app_settings.use_fop_worker_pool
new_workers = worker_spinbox.value()
new_use_pool = pool_checkbox.isChecked()
new_use_fop_pool = fop_pool_checkbox.isChecked()
changes = []
if new_workers != current_workers:
app_settings.max_workers = new_workers
changes.append(f"Worker-Anzahl: {current_workers}{new_workers}")
logger.info(f"max_workers geändert: {current_workers}{new_workers}")
if new_use_pool != current_use_pool:
app_settings.use_saxon_worker_pool = new_use_pool
status = "aktiviert" if new_use_pool else "deaktiviert"
changes.append(f"SaxonWorkerPool: {status}")
logger.info(f"use_saxon_worker_pool geändert: {current_use_pool}{new_use_pool}")
if new_use_fop_pool != current_use_fop_pool:
app_settings.use_fop_worker_pool = new_use_fop_pool
status = "aktiviert" if new_use_fop_pool else "deaktiviert"
changes.append(f"FopWorkerPool: {status}")
logger.info(f"use_fop_worker_pool geändert: {current_use_fop_pool}{new_use_fop_pool}")
if changes:
# WICHTIG: Speichere Settings BEVOR wir Pools neu initialisieren
app_settings.save()
logger.info(f"Performance-Einstellungen gespeichert: {changes}")
# Initialisiere Worker Pools neu falls sich relevante Einstellungen geändert haben
pools_reinitialized = False
if self.project:
# Saxon Worker Pool neu initialisieren?
if new_use_pool != current_use_pool or new_workers != current_workers:
logger.info(
f"Saxon Worker Pool wird neu initialisiert "
f"(use_pool: {current_use_pool}{new_use_pool}, workers: {current_workers}{new_workers})"
)
self._initialize_saxon_worker_pool()
pools_reinitialized = True
# FOP Worker Pool neu initialisieren?
if new_use_fop_pool != current_use_fop_pool or new_workers != current_workers:
logger.info(
f"FOP Worker Pool wird neu initialisiert "
f"(use_pool: {current_use_fop_pool}{new_use_fop_pool}, workers: {current_workers}{new_workers})"
)
self._initialize_fop_worker_pool()
pools_reinitialized = True
else:
logger.warning("Kein Projekt geladen - Worker Pools werden nicht neu initialisiert")
# Informiere Benutzer über Änderungen
changes_text = "\n".join(f"{change}" for change in changes)
status_hint = ""
if pools_reinitialized:
status_hint = "\n\nDie Worker Pools wurden automatisch mit den neuen Einstellungen neu gestartet."
QMessageBox.information(
self,
"Einstellungen gespeichert",
f"Folgende Einstellungen wurden geändert:\n\n{changes_text}{status_hint}",
)
def open_existing_project(self, project: Project): def open_existing_project(self, project: Project):
""" """
Öffnet ein vorhandenes Projekt. Öffnet ein vorhandenes Projekt.