#66: Tooltips auf Konfigurationstab, Verarbeitungslauf-Tab und Toolbar
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
+35
@@ -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
|
||||||
|
|||||||
+112
@@ -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: 10–120.";
|
||||||
|
|
||||||
|
// -------------------------------------------------------------------------
|
||||||
|
// 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");
|
||||||
|
}
|
||||||
|
}
|
||||||
+9
@@ -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);
|
||||||
|
|||||||
+22
@@ -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.
|
||||||
*
|
*
|
||||||
|
|||||||
+205
@@ -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: 10–120.",
|
||||||
|
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");
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user