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
-198
View File
@@ -554,9 +554,6 @@ class MainWindow(QMainWindow):
# Vorhandene Projekte-Menü initialisieren
self._setup_projects_menu()
# Performance-Einstellungen-Menü initialisieren
self._setup_performance_menu()
#
if theme := app_settings.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")
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):
"""
Öffnet ein vorhandenes Projekt.