Meldungsbereich: leeren bei Neu/Öffnen und Button zum manuellen Leeren

- pendingMessages wird in applyEditorState() geleert, bevor die neue
  Konfiguration angezeigt wird (gilt für Neu und Öffnen)
- Neuer Button "Meldungen leeren" unterhalb des Meldungsbereichs;
  ruft clearMessages() auf, das pendingMessages leert und die Ansicht
  aktualisiert
- Dokumentation in docs/gui-bedienanleitung.md ergänzt
- Zwei neue Smoke-Tests: Neu löscht bisherige Meldungen,
  clearMessages() leert den Bereich vollständig

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-04-22 11:33:13 +02:00
parent e07b460cdd
commit 1996f31f43
3 changed files with 105 additions and 0 deletions
+11
View File
@@ -112,6 +112,17 @@ Per Rechtsklick steht zusätzlich ein Kontextmenü zur Verfügung:
| **Meldung kopieren** | Kopiert alle markierten Zeilen in die Zwischenablage (nur aktiv, wenn eine Auswahl besteht) | | **Meldung kopieren** | Kopiert alle markierten Zeilen in die Zwischenablage (nur aktiv, wenn eine Auswahl besteht) |
| **Alle Meldungen kopieren** | Kopiert alle aktuell angezeigten Meldungen in die Zwischenablage | | **Alle Meldungen kopieren** | Kopiert alle aktuell angezeigten Meldungen in die Zwischenablage |
#### Meldungen leeren
Unterhalb des Meldungsbereichs befindet sich der Button **„Meldungen leeren"**.
Ein Klick darauf entfernt alle aktuell angezeigten Meldungen sofort und
vollständig.
Beim Laden einer neuen oder bestehenden Konfiguration über **„Neu"** oder
**„Öffnen"** wird der Meldungsbereich automatisch geleert, sodass keine
Meldungen aus einer früheren Sitzung oder einer vorher geladenen Datei sichtbar
bleiben.
--- ---
## 4. Aktionen ## 4. Aktionen
@@ -150,6 +150,12 @@ public final class GuiConfigurationEditorWorkspace {
*/ */
final Button technicalTestsButton = new Button("Technische Tests ausführen"); final Button technicalTestsButton = new Button("Technische Tests ausführen");
/**
* The "Meldungen leeren" button below the central message area.
* Package-private to allow state assertions in smoke tests.
*/
final Button clearMessagesButton = new Button("Meldungen leeren");
private static final Path DEFAULT_SAVE_PATH = Paths.get("config/application.properties"); private static final Path DEFAULT_SAVE_PATH = Paths.get("config/application.properties");
private final GuiConfigurationFileLoader configurationFileLoader; private final GuiConfigurationFileLoader configurationFileLoader;
@@ -896,6 +902,7 @@ public final class GuiConfigurationEditorWorkspace {
this.welcomeGuidanceVisible = false; this.welcomeGuidanceVisible = false;
statusLabel.setVisible(false); statusLabel.setVisible(false);
statusLabel.setManaged(false); statusLabel.setManaged(false);
pendingMessages.clear();
refreshView(); refreshView();
runEditorValidation(); runEditorValidation();
} }
@@ -1560,6 +1567,11 @@ public final class GuiConfigurationEditorWorkspace {
card.getChildren().add(messagesListView); card.getChildren().add(messagesListView);
clearMessagesButton.setOnAction(e -> clearMessages());
HBox clearButtonRow = new HBox(clearMessagesButton);
clearButtonRow.setAlignment(Pos.CENTER_RIGHT);
card.getChildren().add(clearButtonRow);
// Populate immediately so the area is not blank before the first validation run. // Populate immediately so the area is not blank before the first validation run.
refreshMessagesArea(); refreshMessagesArea();
return card; return card;
@@ -1832,6 +1844,17 @@ public final class GuiConfigurationEditorWorkspace {
} }
} }
/**
* Removes all entries from the central message area.
* <p>
* Clears {@link #pendingMessages} and refreshes the visible message area.
* Must be called on the JavaFX Application Thread.
*/
void clearMessages() {
pendingMessages.clear();
refreshMessagesArea();
}
/** /**
* Formats a message timestamp as {@code [HH:mm:ss]} in the system default zone. * Formats a message timestamp as {@code [HH:mm:ss]} in the system default zone.
* *
@@ -24,6 +24,7 @@ import org.junit.jupiter.api.io.TempDir;
import de.gecheckt.pdf.umbenenner.adapter.in.gui.editor.GuiConfigurationEditorStateFactory; import de.gecheckt.pdf.umbenenner.adapter.in.gui.editor.GuiConfigurationEditorStateFactory;
import de.gecheckt.pdf.umbenenner.adapter.in.gui.editor.GuiConfigurationFileSnapshot; import de.gecheckt.pdf.umbenenner.adapter.in.gui.editor.GuiConfigurationFileSnapshot;
import de.gecheckt.pdf.umbenenner.adapter.in.gui.editor.GuiMessageEntry;
import de.gecheckt.pdf.umbenenner.adapter.in.gui.editor.GuiMessageSeverity; import de.gecheckt.pdf.umbenenner.adapter.in.gui.editor.GuiMessageSeverity;
import de.gecheckt.pdf.umbenenner.application.config.provider.AiProviderFamily; import de.gecheckt.pdf.umbenenner.application.config.provider.AiProviderFamily;
import de.gecheckt.pdf.umbenenner.application.port.out.modelcatalog.EffectiveApiKeyDescriptor; import de.gecheckt.pdf.umbenenner.application.port.out.modelcatalog.EffectiveApiKeyDescriptor;
@@ -609,6 +610,76 @@ class GuiMessageAreaSmokeTest {
}); });
} }
// =========================================================================
// Scenario: message area is cleared when a new configuration is applied
// =========================================================================
/**
* Smoke test: after "Neu" is triggered on a workspace that already has a message, the
* central message area must no longer contain that pre-existing message entry.
* <p>
* This verifies that {@code applyEditorState} clears {@code pendingMessages} so that
* messages from a previous configuration do not bleed into the freshly loaded one.
*/
@Test
void newConfiguration_clearsPreviousMessages() throws Exception {
runOnFx(() -> {
GuiConfigurationEditorWorkspace ws = new GuiConfigurationEditorWorkspace(Optional.empty());
// Seed a message that must not survive a "Neu" action.
ws.pendingMessages.add(
GuiMessageEntry.of(GuiMessageSeverity.ERROR, "Alter Fehler", "Test"));
ws.refreshMessagesArea();
assertFalse(ws.pendingMessages.isEmpty(),
"Pre-condition: pending messages must not be empty before 'Neu'");
ws.requestNewConfiguration();
assertFalse(
ws.pendingMessages.stream()
.anyMatch(m -> "Alter Fehler".equals(m.text())),
"The pre-existing message must have been removed after 'Neu'");
});
}
// =========================================================================
// Scenario: "Meldungen leeren" button clears the message area
// =========================================================================
/**
* Smoke test: invoking {@code clearMessages()} removes all entries from
* {@code pendingMessages} and causes the visible message area to show the
* placeholder instead of previous entries.
*/
@Test
void clearMessages_removesAllEntries() throws Exception {
runOnFx(() -> {
GuiConfigurationEditorWorkspace ws = new GuiConfigurationEditorWorkspace(Optional.empty());
ws.requestNewConfiguration();
// Seed some messages.
ws.pendingMessages.add(
GuiMessageEntry.of(GuiMessageSeverity.INFO, "Info-Meldung", "Test"));
ws.pendingMessages.add(
GuiMessageEntry.of(GuiMessageSeverity.WARNING, "Warnung", "Test"));
ws.refreshMessagesArea();
assertFalse(ws.pendingMessages.isEmpty(),
"Pre-condition: pending messages must not be empty before clearing");
ws.clearMessages();
assertTrue(ws.pendingMessages.isEmpty(),
"pendingMessages must be empty after clearMessages()");
assertTrue(ws.messagesAreaBox.getChildren().isEmpty()
|| ws.messagesAreaBox.getChildren().stream()
.noneMatch(n -> n instanceof javafx.scene.text.TextFlow tf
&& tf.getChildren().stream()
.anyMatch(c -> c instanceof javafx.scene.text.Text t
&& (t.getText().contains("Info-Meldung")
|| t.getText().contains("Warnung")))),
"messagesAreaBox must not contain the cleared message texts after clearMessages()");
});
}
// ========================================================================= // =========================================================================
// Scenario: ai.provider.active field-error label is registered and shown // Scenario: ai.provider.active field-error label is registered and shown
// ========================================================================= // =========================================================================