Skip to content

Commit

Permalink
Remove DirectoryOpenPicker and unify directory selection.
Browse files Browse the repository at this point in the history
Replaced the DirectoryOpenPicker interface with a more unified approach for handling directories through existing FileOpenPicker. Enhanced ExtensionFilter to support directory selection with the `allowDirectory` flag. Streamlined related picker and dropper code for better maintainability and flexibility.
  • Loading branch information
FlorianKirmaier committed Feb 17, 2025
1 parent adff6f3 commit d56fb40
Show file tree
Hide file tree
Showing 12 changed files with 148 additions and 416 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@
import one.jpro.platform.file.ExtensionFilter;
import one.jpro.platform.file.FileSource;
import one.jpro.platform.file.dropper.FileDropper;
import one.jpro.platform.file.picker.DirectoryOpenPicker;
import one.jpro.platform.file.picker.FileOpenPicker;
import one.jpro.platform.file.picker.FileSavePicker;
import org.apache.commons.io.FilenameUtils;
Expand Down Expand Up @@ -62,6 +61,7 @@ public class TextEditorSample extends Application {

private static final PseudoClass FILES_DRAG_OVER_PSEUDO_CLASS = PseudoClass.getPseudoClass("files-drag-over");
private static final ExtensionFilter SUBTITLE_EXTENSION_FILTER = ExtensionFilter.of("Subtitle files", ".srt");
private static final ExtensionFilter SUBTITLE_EXTENSION_FILTER_OR_DIR = ExtensionFilter.of("Subtitle files", true, ".srt");
private static final ExtensionFilter MARKDOWN_EXTENSION_FILTER = ExtensionFilter.of("Markdown files", ".md");
private static final ExtensionFilter CSV_EXTENSION_FILTER = ExtensionFilter.of("CSV files", ".csv");
private final ObjectProperty<File> lastOpenedFile = new SimpleObjectProperty<>(this, "lastOpenedFile");
Expand All @@ -88,7 +88,7 @@ public Parent createRoot(Stage stage) {
StackPane contentPane = new StackPane(textArea, dropPane);

FileDropper fileDropper = FileDropper.create(contentPane);
fileDropper.setExtensionFilter(SUBTITLE_EXTENSION_FILTER);
fileDropper.setExtensionFilter(SUBTITLE_EXTENSION_FILTER_OR_DIR);
fileDropper.setOnDragEntered(event -> {
dropPane.pseudoClassStateChanged(FILES_DRAG_OVER_PSEUDO_CLASS, true);
contentPane.getChildren().setAll(textArea, dropPane);
Expand Down Expand Up @@ -118,7 +118,8 @@ public Parent createRoot(Stage stage) {

Button openDirectory = new Button("Open Directory", new FontIcon(Material2AL.FOLDER_OPEN));
if(!WebAPI.isBrowser()) {
DirectoryOpenPicker directoryOpenPicker = DirectoryOpenPicker.create(openDirectory);
FileOpenPicker directoryOpenPicker = FileOpenPicker.create(openDirectory);
directoryOpenPicker.getExtensionFilters().add(ExtensionFilter.DIRECTORY);
directoryOpenPicker.setOnFilesSelected(fileSources -> {
fileSources.stream().findFirst().ifPresent(fileSource -> {
// Note: We only test whether choosing a directory works
Expand Down Expand Up @@ -174,9 +175,14 @@ private void openFile(List<? extends FileSource> fileSources, TextArea textArea)
fileSource.uploadFileAsync()
.thenCompose(file -> {
try {
final String fileContent = new String(Files.readAllBytes(file.toPath()));
Platform.runLater(() -> textArea.setText(fileContent));
return CompletableFuture.completedFuture(file);
if(file.isDirectory()) {
LOGGER.info("Chosen directory: " + file.getAbsolutePath());
return CompletableFuture.completedFuture(file);
} else {
final String fileContent = new String(Files.readAllBytes(file.toPath()));
Platform.runLater(() -> textArea.setText(fileContent));
return CompletableFuture.completedFuture(file);
}
} catch (IOException ex) {
LOGGER.error("Error reading file: {}", file.getAbsolutePath(), ex);
return CompletableFuture.failedFuture(ex);
Expand Down
29 changes: 13 additions & 16 deletions jpro-file/src/main/java/one/jpro/platform/file/ExtensionFilter.java
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,10 @@
* @param extensions a list of the accepted file name extensions
* @author Besmir Beqiri
*/
public record ExtensionFilter(String description, List<String> extensions) {
public record ExtensionFilter(String description, boolean allowDirectory, List<String> extensions) {

public static final ExtensionFilter ANY = new ExtensionFilter("All Files", List.of("."));
public static final ExtensionFilter ANY = new ExtensionFilter("All Files", false, List.of("."));
public static final ExtensionFilter DIRECTORY = new ExtensionFilter("Directory", true, List.of());

/**
* Compact constructor for {@code ExtensionFilter}.
Expand All @@ -37,8 +38,8 @@ public record ExtensionFilter(String description, List<String> extensions) {
* @throws NullPointerException if the description or the extension are {@code null}
* @throws IllegalArgumentException if the description or the extension are empty
*/
public ExtensionFilter(String description, String extension) {
this(description, List.of(extension));
public ExtensionFilter(String description, String... extension) {
this(description, false, List.of(extension));
}

/**
Expand All @@ -54,23 +55,23 @@ public ExtensionFilter(String description, String extension) {
* @throws IllegalArgumentException if the description or the extensions are empty
*/
public static ExtensionFilter of(String description, String... extensions) {
return new ExtensionFilter(description, List.of(extensions));
return new ExtensionFilter(description, false, List.of(extensions));
}

/**
* Creates an {@code ExtensionFilter} with the specified description
* and the file name extension.
* and the file name extensions.
* <p>
* File name extension should be specified in the {@code *.<extension>} format.
*
* @param description the textual description for the filter
* @param extension the accepted file name extension
* @param extensions an array of the accepted file name extensions
* @return the created {@code ExtensionFilter}
* @throws NullPointerException if the description or the extension is {@code null}
* @throws IllegalArgumentException if the description or the extension is empty
* @throws NullPointerException if the description or the extensions are {@code null}
* @throws IllegalArgumentException if the description or the extensions are empty
*/
public static ExtensionFilter of(String description, String extension) {
return new ExtensionFilter(description, extension);
public static ExtensionFilter of(String description, boolean allowDirectory, String... extensions) {
return new ExtensionFilter(description, allowDirectory, List.of(extensions));
}

/**
Expand All @@ -92,7 +93,7 @@ public static FileChooser.ExtensionFilter toJavaFXExtensionFilter(ExtensionFilte
*/
public static ExtensionFilter fromJavaFXExtensionFilter(FileChooser.ExtensionFilter extensionFilter) {
if (extensionFilter == null) return null;
return new ExtensionFilter(extensionFilter.getDescription(),
return new ExtensionFilter(extensionFilter.getDescription(), false,
extensionFilter.getExtensions().stream()
.filter(ext -> ext.startsWith("*"))
.map(ext -> ext.substring(1)).toList());
Expand All @@ -119,10 +120,6 @@ private static void validateArgs(final String description, final List<String> ex
throw new NullPointerException("Extensions must not be null");
}

if (extensions.isEmpty()) {
throw new IllegalArgumentException("At least one extension must be defined");
}

for (String extension : extensions) {
if (extension == null) {
throw new NullPointerException("Extension must not be null");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -161,7 +161,12 @@ public EventDispatchChain buildEventDispatchChain(EventDispatchChain tail) {
boolean hasSupportedExtension(List<File> files) {
final ExtensionFilter extensionFilter = getExtensionFilter();
return extensionFilter == null || files.stream()
.anyMatch(file -> extensionFilter.extensions().stream()
.anyMatch(extension -> file.getName().toLowerCase().endsWith(extension)));
.anyMatch(file -> {
if(extensionFilter.allowDirectory() && file.isDirectory()) {
return true;
}
return extensionFilter.extensions().stream()
.anyMatch(extension -> file.getName().toLowerCase().endsWith(extension));
});
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,10 @@
import one.jpro.platform.file.NativeFileSource;
import one.jpro.platform.file.event.DataTransfer;
import one.jpro.platform.file.event.FileDragEvent;
import one.jpro.platform.file.picker.NativeFileOpenPicker;
import one.jpro.platform.file.util.NodeUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.File;
import java.util.List;
Expand All @@ -27,13 +30,18 @@
* @author Indrit Beqiri
*/
public class NativeFileDropper extends BaseFileDropper {
private static final Logger logger = LoggerFactory.getLogger(NativeFileDropper.class);

public NativeFileDropper(Node node) {
super(node);

NodeUtils.addEventHandler(node, DragEvent.DRAG_OVER, dragEvent -> {
logger.debug("Drag over event detected: {}", dragEvent);
logger.debug("Dragboard has files: {}", dragEvent.getDragboard().hasFiles());
if (dragEvent.getDragboard().hasFiles()) {
List<File> files = dragEvent.getDragboard().getFiles();
logger.debug("Files: {}", files);
logger.debug("hasSupportedExtension: {}", hasSupportedExtension(files));
if (hasSupportedExtension(files)) {
dragEvent.acceptTransferModes(TransferMode.COPY);
setFilesDragOver(true);
Expand Down Expand Up @@ -61,9 +69,16 @@ public NativeFileDropper(Node node) {
NodeUtils.addEventHandler(node, DragEvent.DRAG_DROPPED, dragEvent -> {
if (dragEvent.getDragboard().hasFiles()) {
final ExtensionFilter extensionFilter = getExtensionFilter();
var allowDirectory = extensionFilter.allowDirectory();
List<NativeFileSource> nativeFileSources = dragEvent.getDragboard().getFiles().stream()
.filter(file -> extensionFilter != null && extensionFilter.extensions().stream()
.anyMatch(extension -> file.getName().toLowerCase().endsWith(extension)))
.anyMatch(extension -> {
if(file.isDirectory()) {
return allowDirectory;
} else {
return file.getName().toLowerCase().endsWith(extension);
}
}))
.map(NativeFileSource::new)
.toList();

Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import javafx.beans.property.ObjectProperty;
import javafx.beans.property.SimpleObjectProperty;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import javafx.beans.value.ChangeListener;
import javafx.collections.FXCollections;
Expand All @@ -12,6 +13,7 @@
import one.jpro.platform.file.ExtensionFilter;
import org.jetbrains.annotations.NotNull;

import java.io.File;
import java.util.Objects;

import static one.jpro.platform.file.ExtensionFilter.toJavaFXExtensionFilter;
Expand Down Expand Up @@ -46,6 +48,14 @@ public final Node getNode() {
// initial file name property
StringProperty initialFileName;

@Override
public final StringProperty initialFileNameProperty() {
if (initialFileName == null) {
initialFileName = new SimpleStringProperty(this, "initialFileName");
}
return initialFileName;
}

@Override
public final String getInitialFileName() {
return (initialFileName == null) ? null : initialFileName.get();
Expand All @@ -56,6 +66,43 @@ public final void setInitialFileName(final String value) {
initialFileNameProperty().setValue(value);
}

ObjectProperty<File> initialDirectory;

@Override
public final ObjectProperty<File> initialDirectoryProperty() {
if (initialDirectory == null) {
initialDirectory = new SimpleObjectProperty<>(this, "initialDirectory");
}
return initialDirectory;
}

@Override
public final File getInitialDirectory() {
return (initialDirectory != null) ? initialDirectory.get() : null;
}

@Override
public final void setInitialDirectory(final File value) {
initialDirectoryProperty().set(value);
}

StringProperty title = new SimpleStringProperty(this, "title");

@Override
public final String getTitle() {
return title.get();
}

@Override
public final void setTitle(final String value) {
titleProperty().set(value);
}

@Override
public final StringProperty titleProperty() {
return title;
}

private final ObservableList<ExtensionFilter> extensionFilters = FXCollections.observableArrayList();

@Override
Expand Down

This file was deleted.

Loading

0 comments on commit d56fb40

Please sign in to comment.