#66: Tooltips auf Konfigurationstab, Verarbeitungslauf-Tab und Toolbar

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-04-30 12:13:00 +02:00
parent 563d9f52db
commit 0fe5359299
5 changed files with 383 additions and 0 deletions
@@ -72,6 +72,8 @@ import javafx.scene.control.Tab;
import javafx.scene.control.TabPane; import javafx.scene.control.TabPane;
import javafx.scene.control.TextField; import javafx.scene.control.TextField;
import javafx.scene.control.TitledPane; import javafx.scene.control.TitledPane;
import javafx.scene.control.Tooltip;
import javafx.util.Duration;
import javafx.scene.input.Clipboard; import javafx.scene.input.Clipboard;
import javafx.scene.input.ClipboardContent; import javafx.scene.input.ClipboardContent;
import javafx.scene.input.KeyCode; import javafx.scene.input.KeyCode;
@@ -1277,6 +1279,12 @@ public final class GuiConfigurationEditorWorkspace {
} }
private void configureActionBar() { private void configureActionBar() {
// Tooltips für Toolbar-Buttons gemäß Spezifikation
applyTooltip(newButton, GuiTooltipTexts.TOOLBAR_NEU);
applyTooltip(openButton, GuiTooltipTexts.TOOLBAR_OEFFNEN);
applyTooltip(saveButton, GuiTooltipTexts.TOOLBAR_SPEICHERN);
applyTooltip(saveAsButton, GuiTooltipTexts.TOOLBAR_SPEICHERN_UNTER);
HBox actionBar = new HBox(10, newButton, openButton, saveButton, saveAsButton); HBox actionBar = new HBox(10, newButton, openButton, saveButton, saveAsButton);
actionBar.setAlignment(Pos.CENTER_LEFT); actionBar.setAlignment(Pos.CENTER_LEFT);
actionBar.setPadding(new Insets(16, 0, 0, 0)); actionBar.setPadding(new Insets(16, 0, 0, 0));
@@ -1364,12 +1372,14 @@ public final class GuiConfigurationEditorWorkspace {
TextField sourceFolderField = boundTextField( TextField sourceFolderField = boundTextField(
editorState.values().sourceFolder(), editorState.values().sourceFolder(),
val -> updateValues(editorState.values().withSourceFolder(val))); val -> updateValues(editorState.values().withSourceFolder(val)));
applyTooltip(sourceFolderField, GuiTooltipTexts.PFADE_QUELLORDNER);
Label sourceFolderErrorLabel = createFieldErrorLabel(); Label sourceFolderErrorLabel = createFieldErrorLabel();
fieldErrorLabels.put("source.folder", sourceFolderErrorLabel); fieldErrorLabels.put("source.folder", sourceFolderErrorLabel);
TextField targetFolderField = boundTextField( TextField targetFolderField = boundTextField(
editorState.values().targetFolder(), editorState.values().targetFolder(),
val -> updateValues(editorState.values().withTargetFolder(val))); val -> updateValues(editorState.values().withTargetFolder(val)));
applyTooltip(targetFolderField, GuiTooltipTexts.PFADE_ZIELORDNER);
Label targetFolderErrorLabel = createFieldErrorLabel(); Label targetFolderErrorLabel = createFieldErrorLabel();
fieldErrorLabels.put("target.folder", targetFolderErrorLabel); fieldErrorLabels.put("target.folder", targetFolderErrorLabel);
@@ -1394,12 +1404,14 @@ public final class GuiConfigurationEditorWorkspace {
TextField sqliteField = boundTextField( TextField sqliteField = boundTextField(
editorState.values().sqliteFile(), editorState.values().sqliteFile(),
val -> updateValues(editorState.values().withSqliteFile(val))); val -> updateValues(editorState.values().withSqliteFile(val)));
applyTooltip(sqliteField, GuiTooltipTexts.PFADE_SQLITE);
Label sqliteErrorLabel = createFieldErrorLabel(); Label sqliteErrorLabel = createFieldErrorLabel();
fieldErrorLabels.put("sqlite.file", sqliteErrorLabel); fieldErrorLabels.put("sqlite.file", sqliteErrorLabel);
TextField promptField = boundTextField( TextField promptField = boundTextField(
editorState.values().promptTemplateFile(), editorState.values().promptTemplateFile(),
val -> updateValues(editorState.values().withPromptTemplateFile(val))); val -> updateValues(editorState.values().withPromptTemplateFile(val)));
applyTooltip(promptField, GuiTooltipTexts.PFADE_PROMPT);
Label promptErrorLabel = createFieldErrorLabel(); Label promptErrorLabel = createFieldErrorLabel();
fieldErrorLabels.put("prompt.template.file", promptErrorLabel); fieldErrorLabels.put("prompt.template.file", promptErrorLabel);
@@ -1487,6 +1499,7 @@ public final class GuiConfigurationEditorWorkspace {
providerComboBox.setConverter(new AiProviderFamilyStringConverter()); providerComboBox.setConverter(new AiProviderFamilyStringConverter());
providerComboBox.getItems().addAll(AiProviderFamily.CLAUDE, AiProviderFamily.OPENAI_COMPATIBLE); providerComboBox.getItems().addAll(AiProviderFamily.CLAUDE, AiProviderFamily.OPENAI_COMPATIBLE);
providerComboBox.setValue(initialProvider); providerComboBox.setValue(initialProvider);
applyTooltip(providerComboBox, GuiTooltipTexts.PROVIDER_COMBOBOX);
// --- "Modelle neu laden" button --- // --- "Modelle neu laden" button ---
Button reloadModelsButton = new Button("Modelle neu laden"); Button reloadModelsButton = new Button("Modelle neu laden");
@@ -1753,6 +1766,7 @@ public final class GuiConfigurationEditorWorkspace {
pState.model(), pState.model(),
val -> updateProviderField(family, pState2 -> new GuiProviderConfigurationState( val -> updateProviderField(family, pState2 -> new GuiProviderConfigurationState(
pState2.baseUrl(), val, pState2.timeoutSeconds(), pState2.apiKey()))); pState2.baseUrl(), val, pState2.timeoutSeconds(), pState2.apiKey())));
modelContainer.applyTooltip(GuiTooltipTexts.PROVIDER_MODELL);
modelFieldContainers.put(family, modelContainer); modelFieldContainers.put(family, modelContainer);
modelCatalogCoordinator.registerFieldContainer(family, modelContainer); modelCatalogCoordinator.registerFieldContainer(family, modelContainer);
Label modelError = createFieldErrorLabel(); Label modelError = createFieldErrorLabel();
@@ -1846,12 +1860,14 @@ public final class GuiConfigurationEditorWorkspace {
TextField maxPagesField = boundTextField( TextField maxPagesField = boundTextField(
editorState.values().maxPages(), editorState.values().maxPages(),
val -> updateValues(editorState.values().withMaxPages(val))); val -> updateValues(editorState.values().withMaxPages(val)));
applyTooltip(maxPagesField, GuiTooltipTexts.LIMITS_MAX_PAGES);
grid.add(new Label("Max. Seiten:"), 0, row); grid.add(new Label("Max. Seiten:"), 0, row);
grid.add(maxPagesField, 1, row); grid.add(maxPagesField, 1, row);
TextField maxCharsField = boundTextField( TextField maxCharsField = boundTextField(
editorState.values().maxTextCharacters(), editorState.values().maxTextCharacters(),
val -> updateValues(editorState.values().withMaxTextCharacters(val))); val -> updateValues(editorState.values().withMaxTextCharacters(val)));
applyTooltip(maxCharsField, GuiTooltipTexts.LIMITS_MAX_TEXT_CHARACTERS);
grid.add(new Label("Max. Zeichen:"), 2, row); grid.add(new Label("Max. Zeichen:"), 2, row);
grid.add(maxCharsField, 3, row); grid.add(maxCharsField, 3, row);
row++; row++;
@@ -1860,6 +1876,7 @@ public final class GuiConfigurationEditorWorkspace {
TextField maxTitleLengthField = boundTextField( TextField maxTitleLengthField = boundTextField(
editorState.values().maxTitleLength(), editorState.values().maxTitleLength(),
val -> updateValues(editorState.values().withMaxTitleLength(val))); val -> updateValues(editorState.values().withMaxTitleLength(val)));
applyTooltip(maxTitleLengthField, GuiTooltipTexts.LIMITS_MAX_TITLE_LENGTH);
grid.add(new Label("Max. Titellänge:"), 0, row); grid.add(new Label("Max. Titellänge:"), 0, row);
grid.add(maxTitleLengthField, 1, row); grid.add(maxTitleLengthField, 1, row);
@@ -1914,9 +1931,11 @@ public final class GuiConfigurationEditorWorkspace {
validateButton.setId("validate-button"); validateButton.setId("validate-button");
validateButton.setOnAction(e -> runValidationAction()); validateButton.setOnAction(e -> runValidationAction());
applyTooltip(validateButton, GuiTooltipTexts.TOOLBAR_VALIDIEREN);
technicalTestsButton.setId("technical-tests-button"); technicalTestsButton.setId("technical-tests-button");
technicalTestsButton.setOnAction(e -> runTechnicalTestsAction()); technicalTestsButton.setOnAction(e -> runTechnicalTestsAction());
applyTooltip(technicalTestsButton, GuiTooltipTexts.TOOLBAR_TECHNISCHE_TESTS);
HBox buttonRow = new HBox(8, validateButton, technicalTestsButton); HBox buttonRow = new HBox(8, validateButton, technicalTestsButton);
buttonRow.setAlignment(Pos.CENTER_LEFT); buttonRow.setAlignment(Pos.CENTER_LEFT);
@@ -2838,6 +2857,22 @@ public final class GuiConfigurationEditorWorkspace {
: exception.getMessage(); : exception.getMessage();
} }
/**
* Setzt einen Tooltip mit einheitlicher Anzeigeverzögerung auf das angegebene Control.
* <p>
* Alle Tooltips in dieser Klasse werden über diese Methode gesetzt, damit ein konsistentes
* Erscheinungsbild gewährleistet ist. Darf nur auf dem JavaFX Application Thread aufgerufen werden.
*
* @param control der Button oder ein anderes {@link javafx.scene.control.Control}, das den
* Tooltip erhalten soll; darf nicht {@code null} sein
* @param text der Tooltip-Text; darf nicht leer sein
*/
private static void applyTooltip(javafx.scene.control.Control control, String text) {
Tooltip tooltip = new Tooltip(text);
tooltip.setShowDelay(Duration.millis(300));
control.setTooltip(tooltip);
}
/** /**
* Speichert den Pfad einer gerade geladenen Konfigurationsdatei. * Speichert den Pfad einer gerade geladenen Konfigurationsdatei.
* Der Pfad wird in den Java Preferences gespeichert und beim nächsten Start * Der Pfad wird in den Java Preferences gespeichert und beim nächsten Start
@@ -0,0 +1,112 @@
package de.gecheckt.pdf.umbenenner.adapter.in.gui;
/**
* Zentrale Konstantenklasse für alle Tooltip-Texte der GUI.
* <p>
* Diese Klasse ist die einzige autoritative Quelle für Tooltip-Beschriftungen aller
* interaktiven Elemente in der Desktop-Oberfläche. Alle Tooltip-Strings werden hier
* definiert und von den jeweiligen UI-Klassen referenziert. Streustrings im
* UI-Code sind unzulässig.
* <p>
* Tooltip-Texte für Status-Icons werden <em>nicht</em> hier gepflegt sie stammen
* ausschließlich aus {@link de.gecheckt.pdf.umbenenner.adapter.in.gui.batchrun.ProcessingStatusPresentation},
* die die autoritative Quelle für alle statusbezogenen Darstellungsinformationen ist.
* <p>
* Alle Texte sind deutschsprachig gemäß Spezifikation.
* Diese Klasse enthält keine JavaFX-Typen und ist nicht instanziierbar.
*/
public final class GuiTooltipTexts {
// -------------------------------------------------------------------------
// Toolbar-Buttons
// -------------------------------------------------------------------------
/** Tooltip für den Button „Neu". */
public static final String TOOLBAR_NEU =
"Neue Konfiguration erstellen.";
/** Tooltip für den Button „Öffnen". */
public static final String TOOLBAR_OEFFNEN =
"Bestehende Konfigurationsdatei (.properties) öffnen.";
/** Tooltip für den Button „Speichern". */
public static final String TOOLBAR_SPEICHERN =
"Aktuelle Konfiguration speichern.";
/** Tooltip für den Button „Speichern unter". */
public static final String TOOLBAR_SPEICHERN_UNTER =
"Konfiguration unter neuem Dateipfad speichern.";
/** Tooltip für den Button „Validieren". */
public static final String TOOLBAR_VALIDIEREN =
"Aktuelle Eingaben auf Vollständigkeit und Korrektheit prüfen.";
/** Tooltip für den Button „Technische Tests ausführen". */
public static final String TOOLBAR_TECHNISCHE_TESTS =
"Dateipfade, Datenbankverbindung und KI-Erreichbarkeit prüfen.";
// -------------------------------------------------------------------------
// Konfigurationstab Pfade
// -------------------------------------------------------------------------
/** Tooltip für das Eingabefeld „Quellordner". */
public static final String PFADE_QUELLORDNER =
"Ordner mit den zu verarbeitenden PDF-Dateien. Inhalt wird nicht verändert.";
/** Tooltip für das Eingabefeld „Zielordner". */
public static final String PFADE_ZIELORDNER =
"Ordner für die umbenannten Kopien.";
/** Tooltip für das Eingabefeld „SQLite-Datei". */
public static final String PFADE_SQLITE =
"Datenbank für Verarbeitungsergebnisse und Datei-Historie.";
/** Tooltip für das Eingabefeld „Prompt-Datei". */
public static final String PFADE_PROMPT =
"Externe Textdatei mit den KI-Anweisungen.";
// -------------------------------------------------------------------------
// Konfigurationstab Provider
// -------------------------------------------------------------------------
/** Tooltip für die Provider-ComboBox. */
public static final String PROVIDER_COMBOBOX =
"Der KI-Dienst, der die Dateinamen generiert.";
/** Tooltip für das Modell-Eingabefeld (ComboBox oder manuelles TextField). */
public static final String PROVIDER_MODELL =
"Das konkrete Sprachmodell des gewählten Providers.";
// -------------------------------------------------------------------------
// Konfigurationstab Verarbeitungslimits
// -------------------------------------------------------------------------
/** Tooltip für das Eingabefeld „max.text.characters". */
public static final String LIMITS_MAX_TEXT_CHARACTERS =
"Maximale Zeichenzahl aus dem PDF-Text. Höhere Werte = mehr Kontext, höhere Kosten.";
/** Tooltip für das Eingabefeld „max.pages". */
public static final String LIMITS_MAX_PAGES =
"Maximale Seitenzahl, die aus einem PDF gelesen wird.";
/** Tooltip für das Eingabefeld „max.title.length". */
public static final String LIMITS_MAX_TITLE_LENGTH =
"Maximale Länge des Dateinamens in Zeichen (ohne Datum und Erweiterung). Gültig: 10120.";
// -------------------------------------------------------------------------
// Verarbeitungslauf-Tab Dateiname-Editor
// -------------------------------------------------------------------------
/** Tooltip für den Button „Dateiname übernehmen". */
public static final String DATEINAME_UEBERNEHMEN =
"Benennt die Zieldatei um und aktualisiert die Datenbank. Nicht rückgängig zu machen.";
/** Tooltip für den Button „Zurücksetzen auf KI-Vorschlag". */
public static final String DATEINAME_ZURUECKSETZEN =
"Stellt den KI-generierten Namen wieder her, ohne zu speichern.";
/** Nicht instanziierbar reine Konstantenklasse. */
private GuiTooltipTexts() {
throw new UnsupportedOperationException("Nicht instanziierbar");
}
}
@@ -6,17 +6,20 @@ import java.util.Optional;
import java.util.Set; import java.util.Set;
import java.util.function.Consumer; import java.util.function.Consumer;
import de.gecheckt.pdf.umbenenner.adapter.in.gui.GuiTooltipTexts;
import de.gecheckt.pdf.umbenenner.application.port.in.DocumentCompletionStatus; import de.gecheckt.pdf.umbenenner.application.port.in.DocumentCompletionStatus;
import javafx.geometry.Insets; import javafx.geometry.Insets;
import javafx.geometry.Pos; import javafx.geometry.Pos;
import javafx.scene.control.Button; import javafx.scene.control.Button;
import javafx.scene.control.Label; import javafx.scene.control.Label;
import javafx.scene.control.TextField; import javafx.scene.control.TextField;
import javafx.scene.control.Tooltip;
import javafx.scene.input.KeyCode; import javafx.scene.input.KeyCode;
import javafx.scene.layout.HBox; import javafx.scene.layout.HBox;
import javafx.scene.layout.Priority; import javafx.scene.layout.Priority;
import javafx.scene.layout.Region; import javafx.scene.layout.Region;
import javafx.scene.layout.VBox; import javafx.scene.layout.VBox;
import javafx.util.Duration;
/** /**
* Detailbereich-Komponente für die Bearbeitung des Zieldateinamens einer selektierten * Detailbereich-Komponente für die Bearbeitung des Zieldateinamens einer selektierten
@@ -86,9 +89,15 @@ public final class FileNameEditorPane {
saveButton.setId("filename-editor-save-button"); saveButton.setId("filename-editor-save-button");
saveButton.setOnAction(e -> fireSaveRequest()); saveButton.setOnAction(e -> fireSaveRequest());
Tooltip saveTooltip = new Tooltip(GuiTooltipTexts.DATEINAME_UEBERNEHMEN);
saveTooltip.setShowDelay(Duration.millis(300));
saveButton.setTooltip(saveTooltip);
resetButton.setId("filename-editor-reset-button"); resetButton.setId("filename-editor-reset-button");
resetButton.setOnAction(e -> resetToAiProposal()); resetButton.setOnAction(e -> resetToAiProposal());
Tooltip resetTooltip = new Tooltip(GuiTooltipTexts.DATEINAME_ZURUECKSETZEN);
resetTooltip.setShowDelay(Duration.millis(300));
resetButton.setTooltip(resetTooltip);
HBox buttonRow = new HBox(8, saveButton, resetButton); HBox buttonRow = new HBox(8, saveButton, resetButton);
buttonRow.setAlignment(Pos.CENTER_LEFT); buttonRow.setAlignment(Pos.CENTER_LEFT);
@@ -8,7 +8,9 @@ import javafx.geometry.Pos;
import javafx.scene.Node; import javafx.scene.Node;
import javafx.scene.control.ComboBox; import javafx.scene.control.ComboBox;
import javafx.scene.control.TextField; import javafx.scene.control.TextField;
import javafx.scene.control.Tooltip;
import javafx.scene.layout.StackPane; import javafx.scene.layout.StackPane;
import javafx.util.Duration;
/** /**
* A container that switches between a non-editable {@link ComboBox} and a manual {@link TextField} * A container that switches between a non-editable {@link ComboBox} and a manual {@link TextField}
@@ -169,6 +171,26 @@ public final class GuiModelFieldContainer extends StackPane {
} }
} }
/**
* Setzt einen Tooltip mit einheitlicher Anzeigeverzögerung auf beide internen Controls
* (ComboBox und TextField). Damit erscheint der Tooltip unabhängig davon, welches der
* beiden Controls gerade sichtbar ist.
* <p>
* Darf nur auf dem JavaFX Application Thread aufgerufen werden.
*
* @param tooltipText der anzuzeigende Tooltip-Text; darf nicht leer sein
*/
public void applyTooltip(String tooltipText) {
Objects.requireNonNull(tooltipText, "tooltipText darf nicht null sein");
Tooltip comboTooltip = new Tooltip(tooltipText);
comboTooltip.setShowDelay(Duration.millis(300));
comboBox.setTooltip(comboTooltip);
Tooltip textTooltip = new Tooltip(tooltipText);
textTooltip.setShowDelay(Duration.millis(300));
textField.setTooltip(textTooltip);
}
/** /**
* Returns the JavaFX node that represents this container and can be added to the scene graph. * Returns the JavaFX node that represents this container and can be added to the scene graph.
* *
@@ -0,0 +1,205 @@
package de.gecheckt.pdf.umbenenner.adapter.in.gui;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertThrows;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.List;
import org.junit.jupiter.api.Test;
/**
* Unit-Tests für {@link GuiTooltipTexts}.
* <p>
* Prüft, dass alle öffentlichen Tooltip-Konstanten vorhanden sind, nicht leer sind
* und den exakten Texten gemäß Spezifikation entsprechen.
*/
class GuiTooltipTextsTest {
// -------------------------------------------------------------------------
// Vollständigkeit und Nicht-Leerheit aller Konstanten
// -------------------------------------------------------------------------
@Test
void alleKonstantenSindNichtNullUndNichtLeer() {
List<String> fehler = new ArrayList<>();
for (Field field : GuiTooltipTexts.class.getDeclaredFields()) {
if (!Modifier.isPublic(field.getModifiers())
|| !Modifier.isStatic(field.getModifiers())
|| !Modifier.isFinal(field.getModifiers())) {
continue;
}
try {
Object value = field.get(null);
if (value == null) {
fehler.add(field.getName() + " ist null");
} else if (value instanceof String s && s.isBlank()) {
fehler.add(field.getName() + " ist leer");
}
} catch (IllegalAccessException e) {
fehler.add(field.getName() + " nicht zugreifbar: " + e.getMessage());
}
}
if (!fehler.isEmpty()) {
org.junit.jupiter.api.Assertions.fail(
"Fehlerhafte Tooltip-Konstanten: " + String.join(", ", fehler));
}
}
// -------------------------------------------------------------------------
// Toolbar-Tooltips exakter Text gemäß Spezifikation
// -------------------------------------------------------------------------
@Test
void toolbar_neu_entsprichtSpezifikation() {
assertNotNull(GuiTooltipTexts.TOOLBAR_NEU);
assertFalse(GuiTooltipTexts.TOOLBAR_NEU.isBlank());
org.junit.jupiter.api.Assertions.assertEquals(
"Neue Konfiguration erstellen.",
GuiTooltipTexts.TOOLBAR_NEU);
}
@Test
void toolbar_oeffnen_entsprichtSpezifikation() {
org.junit.jupiter.api.Assertions.assertEquals(
"Bestehende Konfigurationsdatei (.properties) öffnen.",
GuiTooltipTexts.TOOLBAR_OEFFNEN);
}
@Test
void toolbar_speichern_entsprichtSpezifikation() {
org.junit.jupiter.api.Assertions.assertEquals(
"Aktuelle Konfiguration speichern.",
GuiTooltipTexts.TOOLBAR_SPEICHERN);
}
@Test
void toolbar_speichernUnter_entsprichtSpezifikation() {
org.junit.jupiter.api.Assertions.assertEquals(
"Konfiguration unter neuem Dateipfad speichern.",
GuiTooltipTexts.TOOLBAR_SPEICHERN_UNTER);
}
@Test
void toolbar_validieren_entsprichtSpezifikation() {
org.junit.jupiter.api.Assertions.assertEquals(
"Aktuelle Eingaben auf Vollständigkeit und Korrektheit prüfen.",
GuiTooltipTexts.TOOLBAR_VALIDIEREN);
}
@Test
void toolbar_technischeTests_entsprichtSpezifikation() {
org.junit.jupiter.api.Assertions.assertEquals(
"Dateipfade, Datenbankverbindung und KI-Erreichbarkeit prüfen.",
GuiTooltipTexts.TOOLBAR_TECHNISCHE_TESTS);
}
// -------------------------------------------------------------------------
// Pfade-Tooltips exakter Text gemäß Spezifikation
// -------------------------------------------------------------------------
@Test
void pfade_quellordner_entsprichtSpezifikation() {
org.junit.jupiter.api.Assertions.assertEquals(
"Ordner mit den zu verarbeitenden PDF-Dateien. Inhalt wird nicht verändert.",
GuiTooltipTexts.PFADE_QUELLORDNER);
}
@Test
void pfade_zielordner_entsprichtSpezifikation() {
org.junit.jupiter.api.Assertions.assertEquals(
"Ordner für die umbenannten Kopien.",
GuiTooltipTexts.PFADE_ZIELORDNER);
}
@Test
void pfade_sqlite_entsprichtSpezifikation() {
org.junit.jupiter.api.Assertions.assertEquals(
"Datenbank für Verarbeitungsergebnisse und Datei-Historie.",
GuiTooltipTexts.PFADE_SQLITE);
}
@Test
void pfade_prompt_entsprichtSpezifikation() {
org.junit.jupiter.api.Assertions.assertEquals(
"Externe Textdatei mit den KI-Anweisungen.",
GuiTooltipTexts.PFADE_PROMPT);
}
// -------------------------------------------------------------------------
// Provider-Tooltips exakter Text gemäß Spezifikation
// -------------------------------------------------------------------------
@Test
void provider_combobox_entsprichtSpezifikation() {
org.junit.jupiter.api.Assertions.assertEquals(
"Der KI-Dienst, der die Dateinamen generiert.",
GuiTooltipTexts.PROVIDER_COMBOBOX);
}
@Test
void provider_modell_entsprichtSpezifikation() {
org.junit.jupiter.api.Assertions.assertEquals(
"Das konkrete Sprachmodell des gewählten Providers.",
GuiTooltipTexts.PROVIDER_MODELL);
}
// -------------------------------------------------------------------------
// Verarbeitungslimits-Tooltips exakter Text gemäß Spezifikation
// -------------------------------------------------------------------------
@Test
void limits_maxTextCharacters_entsprichtSpezifikation() {
org.junit.jupiter.api.Assertions.assertEquals(
"Maximale Zeichenzahl aus dem PDF-Text. Höhere Werte = mehr Kontext, höhere Kosten.",
GuiTooltipTexts.LIMITS_MAX_TEXT_CHARACTERS);
}
@Test
void limits_maxPages_entsprichtSpezifikation() {
org.junit.jupiter.api.Assertions.assertEquals(
"Maximale Seitenzahl, die aus einem PDF gelesen wird.",
GuiTooltipTexts.LIMITS_MAX_PAGES);
}
@Test
void limits_maxTitleLength_entsprichtSpezifikation() {
org.junit.jupiter.api.Assertions.assertEquals(
"Maximale Länge des Dateinamens in Zeichen (ohne Datum und Erweiterung). Gültig: 10120.",
GuiTooltipTexts.LIMITS_MAX_TITLE_LENGTH);
}
// -------------------------------------------------------------------------
// Verarbeitungslauf-Tab-Tooltips exakter Text gemäß Spezifikation
// -------------------------------------------------------------------------
@Test
void dateiname_uebernehmen_entsprichtSpezifikation() {
org.junit.jupiter.api.Assertions.assertEquals(
"Benennt die Zieldatei um und aktualisiert die Datenbank. Nicht rückgängig zu machen.",
GuiTooltipTexts.DATEINAME_UEBERNEHMEN);
}
@Test
void dateiname_zuruecksetzen_entsprichtSpezifikation() {
org.junit.jupiter.api.Assertions.assertEquals(
"Stellt den KI-generierten Namen wieder her, ohne zu speichern.",
GuiTooltipTexts.DATEINAME_ZURUECKSETZEN);
}
// -------------------------------------------------------------------------
// Nicht instanziierbar
// -------------------------------------------------------------------------
@Test
void konstruktorWirftException() throws Exception {
Constructor<GuiTooltipTexts> ctor = GuiTooltipTexts.class.getDeclaredConstructor();
ctor.setAccessible(true);
assertThrows(java.lang.reflect.InvocationTargetException.class, ctor::newInstance,
"Der private Konstruktor muss UnsupportedOperationException werfen");
}
}