Fix #63: Datei-Filter in pickFile wirksam machen
Neues funktionales Interface FilePickerDialog eingefuehrt, das Titel, Anfangspfad und ExtensionFilter-Liste entgegennimmt. showNativeFileChooser wendet die Filter auf den FileChooser an. pickFile reicht die Filter durch. Test-Stubs verwenden die aktualisierte Drei-Parameter-Signatur. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
+33
@@ -0,0 +1,33 @@
|
||||
package de.gecheckt.pdf.umbenenner.adapter.in.gui;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import javafx.stage.FileChooser;
|
||||
|
||||
/**
|
||||
* Funktionales Interface fuer den Datei-Auswaehldialog der GUI.
|
||||
* <p>
|
||||
* Kapselt die Abhaengigkeit zum nativen {@link FileChooser} in einem
|
||||
* injizierbaren Hook, der in Tests durch eine einfache Lambda-Implementierung
|
||||
* ersetzt werden kann. Die Standardimplementierung oeffnet einen echten
|
||||
* nativen Datei-Dialog; Test-Stubs koennen einen festen Pfad zurueckgeben
|
||||
* oder {@code null} simulieren (Abbrechen).
|
||||
* <p>
|
||||
* Im Gegensatz zur frueheren {@code BiFunction}-Variante nimmt dieser Hook
|
||||
* auch die Liste der {@link FileChooser.ExtensionFilter} entgegen, damit der
|
||||
* native Dialog die Filter tatsaechlich anwenden kann.
|
||||
*/
|
||||
@FunctionalInterface
|
||||
interface FilePickerDialog {
|
||||
|
||||
/**
|
||||
* Oeffnet den Datei-Auswaehldialog und gibt den ausgewaehlten absoluten
|
||||
* Pfad zurueck.
|
||||
*
|
||||
* @param title der Titel des Dialogs
|
||||
* @param initialPath der Anfangspfad als Hinweis; darf leer oder {@code null} sein
|
||||
* @param filters Liste der Dateitypfilter; darf leer sein, aber nicht {@code null}
|
||||
* @return der ausgewaehlte absolute Pfad als String, oder {@code null} wenn abgebrochen
|
||||
*/
|
||||
String pick(String title, String initialPath, List<FileChooser.ExtensionFilter> filters);
|
||||
}
|
||||
+32
-24
@@ -235,17 +235,16 @@ public final class GuiConfigurationEditorWorkspace {
|
||||
this::showNativeDirectoryChooser;
|
||||
|
||||
/**
|
||||
* Dialog function for file-picker buttons; package-private to allow substitution in tests.
|
||||
* Receives the dialog title and the current field text (used as an initial path hint), and
|
||||
* returns the selected absolute path string or {@code null} when the dialog is cancelled.
|
||||
* Dialog-Hook fuer Datei-Auswaehldialoge; package-private, damit Tests eine Stub-Implementierung
|
||||
* injizieren koennen. Empfaengt Titel, aktuellen Feldtext (als Anfangspfad-Hinweis) und die
|
||||
* Liste der Dateitypfilter; gibt den ausgewaehlten absoluten Pfad oder {@code null} zurueck.
|
||||
* <p>
|
||||
* The default implementation opens a native {@link FileChooser}. Tests may replace
|
||||
* this with a lambda that returns a fixed string without opening a native dialog.
|
||||
* <p>
|
||||
* Extension filters are applied by the default implementation only; test stubs bypass them.
|
||||
* Die Standardimplementierung oeffnet einen nativen {@link FileChooser} und wendet die
|
||||
* uebergebenen Filter an. Test-Stubs koennen die Filter ignorieren und einen festen Pfad
|
||||
* zurueckgeben.
|
||||
*/
|
||||
java.util.function.BiFunction<String, String, String> filePickerDialog =
|
||||
(title, initialPath) -> showNativeFileChooser(title, initialPath);
|
||||
FilePickerDialog filePickerDialog =
|
||||
(title, initialPath, filters) -> showNativeFileChooser(title, initialPath, filters);
|
||||
|
||||
/**
|
||||
* Guard that mediates the protection dialog before destructive actions.
|
||||
@@ -2462,20 +2461,21 @@ public final class GuiConfigurationEditorWorkspace {
|
||||
}
|
||||
|
||||
/**
|
||||
* Opens a file-picker dialog using the injectable {@link #filePickerDialog} hook.
|
||||
* Oeffnet einen Datei-Auswaehldialog ueber den injizierbaren {@link #filePickerDialog}-Hook.
|
||||
* <p>
|
||||
* In production the hook delegates to a native {@link FileChooser}. In tests the hook
|
||||
* can be replaced with a lambda that returns a fixed string. Windows mapped drive letters
|
||||
* are preserved unchanged.
|
||||
* In der Produktion delegiert der Hook an einen nativen {@link FileChooser} und wendet
|
||||
* die uebergebenen Filter an. In Tests kann der Hook durch eine Lambda-Implementierung
|
||||
* ersetzt werden, die einen festen Pfad zurueckgibt. Windows-Laufwerksbuchstaben
|
||||
* (z. B. {@code S:\}) werden unveraendert weitergegeben.
|
||||
*
|
||||
* @param title the dialog title
|
||||
* @param initialPath the pre-selected path text; may be empty or {@code null}
|
||||
* @param filters extension filters (only applied by the native default implementation)
|
||||
* @return the selected absolute path string, or {@code null} when the dialog was cancelled
|
||||
* @param title der Titel des Datei-Dialogs
|
||||
* @param initialPath der Anfangspfad als Hinweis; darf leer oder {@code null} sein
|
||||
* @param filters Dateitypfilter, die im nativen Dialog angezeigt werden
|
||||
* @return den ausgewaehlten absoluten Pfad, oder {@code null} wenn der Dialog abgebrochen wurde
|
||||
*/
|
||||
private String pickFile(String title, String initialPath,
|
||||
FileChooser.ExtensionFilter... filters) {
|
||||
return filePickerDialog.apply(title, initialPath);
|
||||
return filePickerDialog.pick(title, initialPath, List.of(filters));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -2500,22 +2500,30 @@ public final class GuiConfigurationEditorWorkspace {
|
||||
}
|
||||
|
||||
/**
|
||||
* Default native file-chooser implementation used by {@link #filePickerDialog}.
|
||||
* Standardimplementierung des nativen Datei-Auswaehldialogs fuer {@link #filePickerDialog}.
|
||||
* <p>
|
||||
* Wendet alle uebergebenen Dateitypfilter auf den {@link FileChooser} an, bevor der Dialog
|
||||
* geoeffnet wird.
|
||||
*
|
||||
* @param title the dialog title
|
||||
* @param initialPath the initial path hint; may be empty or {@code null}
|
||||
* @return the selected absolute path string, or {@code null} when cancelled or unavailable
|
||||
* @param title der Titel des Datei-Dialogs
|
||||
* @param initialPath der Anfangspfad als Hinweis; darf leer oder {@code null} sein
|
||||
* @param filters anzuwendende Dateitypfilter; darf leer, aber nicht {@code null} sein
|
||||
* @return den ausgewaehlten absoluten Pfad, oder {@code null} wenn abgebrochen oder nicht verfuegbar
|
||||
*/
|
||||
private String showNativeFileChooser(String title, String initialPath) {
|
||||
private String showNativeFileChooser(String title, String initialPath,
|
||||
List<FileChooser.ExtensionFilter> filters) {
|
||||
FileChooser chooser = new FileChooser();
|
||||
chooser.setTitle(title);
|
||||
setInitialPathForFileChooser(chooser, initialPath);
|
||||
if (!filters.isEmpty()) {
|
||||
chooser.getExtensionFilters().addAll(filters);
|
||||
}
|
||||
Window owner = root.getScene() == null ? null : root.getScene().getWindow();
|
||||
try {
|
||||
File selected = chooser.showOpenDialog(owner);
|
||||
return selected == null ? null : selected.getAbsolutePath();
|
||||
} catch (UnsupportedOperationException e) {
|
||||
LOG.debug("GUI-Editor: Datei-Dialog nicht verf\u00fcgbar (headless).");
|
||||
LOG.debug("GUI-Editor: Datei-Dialog nicht verfuegbar (headless).");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
+3
-3
@@ -202,11 +202,11 @@ class GuiEditorFieldBindingTest {
|
||||
String originalSqlite = ws.editorState().values().sqliteFile();
|
||||
|
||||
// Replace the file-picker hook: always return null (cancel).
|
||||
ws.filePickerDialog = (title, initialPath) -> null;
|
||||
ws.filePickerDialog = (title, initialPath, filters) -> null;
|
||||
|
||||
// Simulate button handler: null result means do nothing.
|
||||
String picked = ws.filePickerDialog.apply("SQLite-Datei ausw\u00e4hlen",
|
||||
ws.editorState().values().sqliteFile());
|
||||
String picked = ws.filePickerDialog.pick("SQLite-Datei ausw\u00e4hlen",
|
||||
ws.editorState().values().sqliteFile(), java.util.List.of());
|
||||
if (picked != null) {
|
||||
ws.editorState = ws.editorState()
|
||||
.withValues(ws.editorState().values().withSqliteFile(picked));
|
||||
|
||||
Reference in New Issue
Block a user