Schritte 11-13: Config-Tab-Sperre, Batch-Button-Sperre, Scheduler-Close-Guard
Schritt 11: updateLockState() implementiert in GuiConfigurationEditorWorkspace - schedulerLockActive-Feld eingeführt - applyBatchRunLockState() delegiert an neues applyConfigTabLockState() - applyConfigTabLockState() vereint Batch-Run- und Scheduler-Sperre: Banner, sectionsBox, Neu/Öffnen/Speichern/Speichern-unter werden gesperrt wenn Scheduler aktiv oder Lauf aktiv Schritt 12: updateSchedulerState() implementiert in GuiBatchRunTab - schedulerActive-Feld eingeführt - Starten-Button wird deaktiviert + Tooltip gesetzt wenn Scheduler läuft - updateButtonStates() berücksichtigt schedulerActive damit Sperre beim Laufende nicht verloren geht Schritt 13: Scheduler-Close-Guard in PdfUmbenennerGuiApplication - installSchedulerCloseGuard() als äußerste Schicht des Close-Handlers - Zeigt Informationsdialog und verhindert Beenden wenn Scheduler aktiv - Bestehender Workspace-/Tray-Handler bleibt erhalten wenn Scheduler gestoppt Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
+47
-23
@@ -477,13 +477,19 @@ public final class GuiConfigurationEditorWorkspace {
|
|||||||
private final GuiPromptEditorTab promptEditorTab;
|
private final GuiPromptEditorTab promptEditorTab;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Hint banner shown at the top of the configuration tab while a processing run is
|
* Hint banner shown at the top of the configuration tab while a processing run or
|
||||||
* active. Visible + managed state are flipped from the batch run tab's listener when
|
* the automatic scheduler is active. Visible + managed state are controlled by
|
||||||
* the running flag toggles.
|
* {@link #applyConfigTabLockState()}.
|
||||||
*/
|
*/
|
||||||
final Label configurationLockBanner = new Label(
|
final Label configurationLockBanner = new Label(
|
||||||
"Konfiguration während eines laufenden Verarbeitungslaufs nicht editierbar");
|
"Konfiguration während eines laufenden Verarbeitungslaufs nicht editierbar");
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@code true} while the automatic scheduler is in any non-{@code STOPPED} state.
|
||||||
|
* Updated by {@link #updateLockState(SchedulerStatus)} from the 1 Hz refresh timeline.
|
||||||
|
*/
|
||||||
|
private boolean schedulerLockActive = false;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Reference to the configuration tab so the running-state listener can disable its
|
* Reference to the configuration tab so the running-state listener can disable its
|
||||||
* content while a batch run is active.
|
* content while a batch run is active.
|
||||||
@@ -695,23 +701,41 @@ public final class GuiConfigurationEditorWorkspace {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Applies the "batch run active" UI lock state to the configuration tab and the
|
* Applies the "batch run active" UI lock state to the configuration tab.
|
||||||
* action bar.
|
|
||||||
* <p>
|
* <p>
|
||||||
* While a run is active the configuration editor is made non-interactive, the lock
|
* Delegates to {@link #applyConfigTabLockState()} so that both the batch-run lock
|
||||||
* banner is shown at the top of Tab 1, and the main action buttons (Neu, Öffnen,
|
* and the scheduler lock are evaluated together. Called whenever the batch-run
|
||||||
* Speichern, Speichern unter) are disabled. When the run ends, the locks are
|
* running state changes.
|
||||||
* released and the editor returns to its normal state.
|
|
||||||
*/
|
*/
|
||||||
void applyBatchRunLockState() {
|
void applyBatchRunLockState() {
|
||||||
boolean running = batchRunTab != null && batchRunTab.isRunning();
|
applyConfigTabLockState();
|
||||||
configurationLockBanner.setVisible(running);
|
}
|
||||||
configurationLockBanner.setManaged(running);
|
|
||||||
sectionsBox.setDisable(running);
|
/**
|
||||||
newButton.setDisable(running);
|
* Evaluates the combined lock state (batch run active <em>or</em> scheduler active)
|
||||||
openButton.setDisable(running);
|
* and applies it to the configuration tab.
|
||||||
saveButton.setDisable(running);
|
* <p>
|
||||||
saveAsButton.setDisable(running);
|
* When either source is locked the banner is shown, all input sections are disabled
|
||||||
|
* and the action buttons (Neu, Öffnen, Speichern, Speichern unter) are disabled.
|
||||||
|
* The banner text describes the dominant lock source.
|
||||||
|
*/
|
||||||
|
private void applyConfigTabLockState() {
|
||||||
|
boolean batchRunning = batchRunTab != null && batchRunTab.isRunning();
|
||||||
|
boolean locked = batchRunning || schedulerLockActive;
|
||||||
|
|
||||||
|
String bannerText = schedulerLockActive
|
||||||
|
? "⚠ Konfiguration gesperrt – Scheduler läuft (oder Lauf aktiv)."
|
||||||
|
+ " Scheduler beenden bzw. Lauf abwarten um Änderungen vorzunehmen."
|
||||||
|
: "Konfiguration während eines laufenden Verarbeitungslaufs nicht editierbar";
|
||||||
|
|
||||||
|
configurationLockBanner.setText(bannerText);
|
||||||
|
configurationLockBanner.setVisible(locked);
|
||||||
|
configurationLockBanner.setManaged(locked);
|
||||||
|
sectionsBox.setDisable(locked);
|
||||||
|
newButton.setDisable(locked);
|
||||||
|
openButton.setDisable(locked);
|
||||||
|
saveButton.setDisable(locked);
|
||||||
|
saveAsButton.setDisable(locked);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -1116,17 +1140,17 @@ public final class GuiConfigurationEditorWorkspace {
|
|||||||
/**
|
/**
|
||||||
* Aktualisiert den Sperr-Zustand des Konfig-Tabs anhand des aktuellen Scheduler-Status.
|
* Aktualisiert den Sperr-Zustand des Konfig-Tabs anhand des aktuellen Scheduler-Status.
|
||||||
* <p>
|
* <p>
|
||||||
* Muss auf dem JavaFX Application Thread aufgerufen werden. Wird von
|
* Setzt {@link #schedulerLockActive} und ruft {@link #applyConfigTabLockState()} auf,
|
||||||
* {@link #onSchedulerStatusRefresh} und der Status-Refresh-Timeline (1 Hz) indirekt
|
* sodass Banner, Eingabefelder und Aktionsbuttons des Konfig-Tabs sofort in den
|
||||||
* aufgerufen.
|
* korrekten Zustand versetzt werden.
|
||||||
* <p>
|
* <p>
|
||||||
* Die konkrete Reaktion (z. B. Banner-Anzeige und Speichern-Button-Sperre während ein
|
* Muss auf dem JavaFX Application Thread aufgerufen werden.
|
||||||
* Scheduler-Lauf aktiv ist) wird in einem späteren Implementierungsschritt ergänzt.
|
|
||||||
*
|
*
|
||||||
* @param status aktueller Scheduler-Status; darf nicht {@code null} sein
|
* @param status aktueller Scheduler-Status; darf nicht {@code null} sein
|
||||||
*/
|
*/
|
||||||
public void updateLockState(SchedulerStatus status) {
|
public void updateLockState(SchedulerStatus status) {
|
||||||
// Stub – Implementierung folgt in späterem Schritt
|
schedulerLockActive = status.state().isActive();
|
||||||
|
applyConfigTabLockState();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
+37
@@ -8,6 +8,7 @@ import javafx.application.Application;
|
|||||||
import javafx.application.Platform;
|
import javafx.application.Platform;
|
||||||
import javafx.event.EventHandler;
|
import javafx.event.EventHandler;
|
||||||
import javafx.scene.Scene;
|
import javafx.scene.Scene;
|
||||||
|
import javafx.scene.control.Alert;
|
||||||
import javafx.scene.control.Menu;
|
import javafx.scene.control.Menu;
|
||||||
import javafx.scene.control.MenuBar;
|
import javafx.scene.control.MenuBar;
|
||||||
import javafx.scene.control.MenuItem;
|
import javafx.scene.control.MenuItem;
|
||||||
@@ -110,6 +111,9 @@ public class PdfUmbenennerGuiApplication extends Application {
|
|||||||
installTrayCloseHandler(primaryStage, workspace);
|
installTrayCloseHandler(primaryStage, workspace);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Scheduler-Close-Guard als äußerste Schicht: verhindert Beenden während Scheduler aktiv
|
||||||
|
installSchedulerCloseGuard(primaryStage);
|
||||||
|
|
||||||
primaryStage.setMaximized(true);
|
primaryStage.setMaximized(true);
|
||||||
primaryStage.show();
|
primaryStage.show();
|
||||||
|
|
||||||
@@ -180,6 +184,39 @@ public class PdfUmbenennerGuiApplication extends Application {
|
|||||||
return new MenuBar(databaseMenu);
|
return new MenuBar(databaseMenu);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Legt den Scheduler-Close-Guard als äußerste Schicht des Close-Request-Handlers an.
|
||||||
|
* <p>
|
||||||
|
* Ist kein {@link de.gecheckt.pdf.umbenenner.application.port.in.SchedulerControlUseCase}
|
||||||
|
* vorhanden, bleibt der bestehende Handler unverändert. Ist der Scheduler aktiv
|
||||||
|
* (Zustand != {@code STOPPED}), wird das Schließen verhindert und ein
|
||||||
|
* Informationsdialog angezeigt. Ist der Scheduler gestoppt, wird der bisherige
|
||||||
|
* Handler (SystemTray + Workspace-Dirty-Guard) aufgerufen.
|
||||||
|
*
|
||||||
|
* @param stage das primäre Fenster; darf nicht {@code null} sein
|
||||||
|
*/
|
||||||
|
private void installSchedulerCloseGuard(Stage stage) {
|
||||||
|
guiStartupContext.schedulerControlUseCase().ifPresent(uc -> {
|
||||||
|
EventHandler<WindowEvent> existingHandler = stage.getOnCloseRequest();
|
||||||
|
stage.setOnCloseRequest(event -> {
|
||||||
|
if (uc.getStatus().state().isActive()) {
|
||||||
|
event.consume();
|
||||||
|
Alert alert = new Alert(Alert.AlertType.INFORMATION);
|
||||||
|
alert.setTitle("Anwendung kann nicht beendet werden");
|
||||||
|
alert.setHeaderText(null);
|
||||||
|
alert.setContentText(
|
||||||
|
"Ein Lauf ist aktiv oder der Scheduler läuft.\n"
|
||||||
|
+ "Bitte beende den Scheduler bzw. warte auf das Ende des Laufs.");
|
||||||
|
alert.showAndWait();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (existingHandler != null) {
|
||||||
|
existingHandler.handle(event);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Legt einen Close-Request-Handler an, der bei sauberem Zustand das Fenster in den
|
* Legt einen Close-Request-Handler an, der bei sauberem Zustand das Fenster in den
|
||||||
* System-Tray minimiert statt es zu schließen.
|
* System-Tray minimiert statt es zu schließen.
|
||||||
|
|||||||
+13
-6
@@ -196,6 +196,9 @@ public final class GuiBatchRunTab {
|
|||||||
private final Button resetStatusButton = new Button("Status zurücksetzen");
|
private final Button resetStatusButton = new Button("Status zurücksetzen");
|
||||||
private final ReadOnlyBooleanWrapper runningProperty = new ReadOnlyBooleanWrapper(false);
|
private final ReadOnlyBooleanWrapper runningProperty = new ReadOnlyBooleanWrapper(false);
|
||||||
|
|
||||||
|
/** {@code true} while the automatic scheduler is in any non-{@code STOPPED} state. */
|
||||||
|
private boolean schedulerActive = false;
|
||||||
|
|
||||||
/** Dateiname-Editor-Komponente im Detailbereich. */
|
/** Dateiname-Editor-Komponente im Detailbereich. */
|
||||||
private final FileNameEditorPane fileNameEditor = new FileNameEditorPane();
|
private final FileNameEditorPane fileNameEditor = new FileNameEditorPane();
|
||||||
|
|
||||||
@@ -496,16 +499,20 @@ public final class GuiBatchRunTab {
|
|||||||
/**
|
/**
|
||||||
* Aktualisiert den Tab-Zustand anhand des aktuellen Scheduler-Status.
|
* Aktualisiert den Tab-Zustand anhand des aktuellen Scheduler-Status.
|
||||||
* <p>
|
* <p>
|
||||||
* Muss auf dem JavaFX Application Thread aufgerufen werden. Wird von der
|
* Deaktiviert den Starten-Button und setzt einen erklärenden Tooltip, solange
|
||||||
* zentralen Status-Refresh-Timeline (1 Hz) aufgerufen.
|
* der Scheduler aktiv ist. Wenn der Scheduler gestoppt ist, wird der normale
|
||||||
|
* Button-Zustand wiederhergestellt (Starten erlaubt sofern kein Lauf läuft).
|
||||||
* <p>
|
* <p>
|
||||||
* Die konkrete Reaktion (z. B. Deaktivierung des Starten-Buttons während ein
|
* Muss auf dem JavaFX Application Thread aufgerufen werden.
|
||||||
* Scheduler-Lauf aktiv ist) wird in einem späteren Implementierungsschritt ergänzt.
|
|
||||||
*
|
*
|
||||||
* @param status aktueller Scheduler-Status; darf nicht {@code null} sein
|
* @param status aktueller Scheduler-Status; darf nicht {@code null} sein
|
||||||
*/
|
*/
|
||||||
public void updateSchedulerState(SchedulerStatus status) {
|
public void updateSchedulerState(SchedulerStatus status) {
|
||||||
// Stub – Implementierung folgt in späterem Schritt
|
schedulerActive = status.state().isActive();
|
||||||
|
startButton.setDisable(runningProperty.get() || schedulerActive);
|
||||||
|
startButton.setTooltip(new Tooltip(schedulerActive
|
||||||
|
? "Manuelle Läufe sind während aktivem Scheduler nicht möglich."
|
||||||
|
: GuiTooltipTexts.BATCHRUN_STARTEN));
|
||||||
}
|
}
|
||||||
|
|
||||||
// -------------------------------------------------------------------------
|
// -------------------------------------------------------------------------
|
||||||
@@ -1485,7 +1492,7 @@ public final class GuiBatchRunTab {
|
|||||||
|
|
||||||
private void updateButtonStates() {
|
private void updateButtonStates() {
|
||||||
boolean running = runningProperty.get();
|
boolean running = runningProperty.get();
|
||||||
startButton.setDisable(running);
|
startButton.setDisable(running || schedulerActive);
|
||||||
if (!running) {
|
if (!running) {
|
||||||
cancelButton.setDisable(true);
|
cancelButton.setDisable(true);
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
Reference in New Issue
Block a user