From b64d24a7b7eb96fc7273f2fe208e775b4e0fb2be Mon Sep 17 00:00:00 2001 From: a2geek Date: Sat, 3 Oct 2026 17:17:49 -0500 Subject: [PATCH] First pass at using export settings. --- app/gui-javafx/src/main/java/module-info.java | 1 + .../org/applecommander/javafx/FileView.java | 16 ++-- .../javafx/settings/ExportOption.java | 93 ++++++++++++++++++- .../javafx/settings/Settings.java | 6 +- .../javafx/settings/SettingsDialog.java | 2 +- .../storage/DiskFileStoreAdapter.java | 4 - 6 files changed, 103 insertions(+), 19 deletions(-) diff --git a/app/gui-javafx/src/main/java/module-info.java b/app/gui-javafx/src/main/java/module-info.java index f72f6f5c..20d305e7 100644 --- a/app/gui-javafx/src/main/java/module-info.java +++ b/app/gui-javafx/src/main/java/module-info.java @@ -5,6 +5,7 @@ module org.applecommander.javafx { requires javafx.controls; requires javafx.graphics; requires org.applecommander.api; + requires org.applecommander.applesingle; opens org.applecommander.javafx to javafx.graphics; opens org.applecommander.javafx.settings to javafx.graphics; diff --git a/app/gui-javafx/src/main/java/org/applecommander/javafx/FileView.java b/app/gui-javafx/src/main/java/org/applecommander/javafx/FileView.java index 17604ff7..ae1e079b 100644 --- a/app/gui-javafx/src/main/java/org/applecommander/javafx/FileView.java +++ b/app/gui-javafx/src/main/java/org/applecommander/javafx/FileView.java @@ -39,6 +39,8 @@ import org.applecommander.capability.Capability; import org.applecommander.filestore.Directory; import org.applecommander.filestore.DisplayColumn; import org.applecommander.filestore.FileEntry; +import org.applecommander.javafx.settings.ExportOption; +import org.applecommander.javafx.settings.Settings; import org.applecommander.source.Source; import org.applecommander.source.Sources; @@ -47,7 +49,6 @@ import java.io.IOException; import java.io.UncheckedIOException; import java.nio.file.Files; import java.nio.file.Path; -import java.nio.file.StandardOpenOption; import java.util.ArrayList; import java.util.List; import java.util.Optional; @@ -123,16 +124,17 @@ public class FileView extends BorderPane { fileTable.setOnDragDetected(event -> { if (!fileTable.getSelectionModel().getSelectedItems().isEmpty()) { try { + ExportOption exportOption = Settings.getExportOption(); Path tempDir = Files.createTempDirectory("AppleCommander-drag-"); tempDir.toFile().deleteOnExit(); List files = new ArrayList<>(); - // TODO this should be configured by a setting for (FileEntry fileEntry : fileTable.getSelectionModel().getSelectedItems()) { - Path path = Path.of(TEMP_DIRECTORY, fileEntry.getName()); - Files.write(path, fileEntry.getDataFork().asBytes(), StandardOpenOption.CREATE); - File file = path.toFile(); - file.deleteOnExit(); - files.add(file); + // We may write two files, so copyToPath gives us ALL the names we care about + for (Path path : exportOption.copyToPath(fileEntry, Path.of(TEMP_DIRECTORY, fileEntry.getName()))) { + File file = path.toFile(); + file.deleteOnExit(); + files.add(file); + } } ClipboardContent content = new ClipboardContent(); content.putFiles(files); diff --git a/app/gui-javafx/src/main/java/org/applecommander/javafx/settings/ExportOption.java b/app/gui-javafx/src/main/java/org/applecommander/javafx/settings/ExportOption.java index 6785bc0c..65512944 100644 --- a/app/gui-javafx/src/main/java/org/applecommander/javafx/settings/ExportOption.java +++ b/app/gui-javafx/src/main/java/org/applecommander/javafx/settings/ExportOption.java @@ -19,18 +19,103 @@ */ package org.applecommander.javafx.settings; +import org.applecommander.applesingle.AppleSingle; +import org.applecommander.filestore.FileEntry; + +import java.io.IOException; +import java.io.UncheckedIOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.StandardOpenOption; +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; +import java.util.function.BiFunction; + public enum ExportOption { - RAW_BINARY("Raw Binary (filename)"), - APPLE_SINGLE("AppleSingle (filename.as)"), - ATTRIBUTE_PRESERVATION("ProDOS Attribute Preservation (filename#TTAAAA.ext)"); + RAW_BINARY("Raw Binary (filename)", ExportOption::copyToRawBinary), + APPLE_SINGLE("AppleSingle (filename.as)", ExportOption::copyToAppleSingle), + ATTRIBUTE_PRESERVATION("ProDOS Attribute Preservation (filename#TTAAAA.ext)", ExportOption::copyWithAttributePreservation); private final String description; + private final BiFunction> copyFn; - ExportOption(String description) { + ExportOption(String description, BiFunction> copyFn) { + Objects.requireNonNull(description, "description cannot be null"); + Objects.requireNonNull(copyFn, "copyFn cannot be null"); this.description = description; + this.copyFn = copyFn; } public String getDescription() { return description; } + + public List copyToPath(FileEntry fileEntry, Path destination) { + return copyFn.apply(fileEntry, destination); + } + + public static Path addToFilename(Path path, String suffix) { + String name = path.getFileName().toString(); + int idx = name.lastIndexOf('.'); + if (idx == -1) { + return path.resolveSibling(name.concat(suffix)); + } + name = name.substring(0, idx).concat(suffix).concat(name.substring(idx + 1)); + return path.resolve(name); + } + + public static List copyToRawBinary(FileEntry fileEntry, Path destination) { + try { + List paths = new ArrayList<>(); + paths.add(destination); + Files.write(destination, fileEntry.getDataFork().asBytes(), StandardOpenOption.CREATE); + if (fileEntry.getResourceFork().isPresent()) { + Files.write(addToFilename(destination, "-rsrc"), fileEntry.getResourceFork().get().asBytes(), + StandardOpenOption.CREATE); + } + return paths; + } catch (IOException ex) { + throw new UncheckedIOException(ex); + } + } + + public static List copyToAppleSingle(FileEntry fileEntry, Path destination) { + try { + List paths = new ArrayList<>(); + destination = destination.resolveSibling(destination.getFileName() + ".as"); + paths.add(destination); + // TODO need to get ProDOS-ified file type + some mechanism for access bits + dates. Maybe it fits in FileStore?? + AppleSingle.Builder builder = AppleSingle.builder() + .realName(fileEntry.getName()) + .dataFork(fileEntry.getDataFork().asBytes()); + fileEntry.getResourceFork().ifPresent(resourceFork -> builder.resourceFork(resourceFork.asBytes())); + builder.build().save(destination); + return paths; + } catch (IOException ex) { + throw new UncheckedIOException(ex); + } + } + + public static List copyWithAttributePreservation(FileEntry fileEntry, Path destination) { + try { + List paths = new ArrayList<>(); + String name = fileEntry.getName(); + String ext = fileEntry.getFiletype(); + int idx = name.lastIndexOf('.'); + if (idx > -1) { + ext = name.substring(idx + 1); + name = name.substring(0, idx); + } + Path dataForkPath = destination.resolveSibling(String.format("%s#TTAAAA.%s", name, ext)); + Files.write(dataForkPath, fileEntry.getDataFork().asBytes(), StandardOpenOption.CREATE); + if (fileEntry.getResourceFork().isPresent()) { + Path resourceForkPath = destination.resolve(String.format("%s#TTAAAA_rsrc_.%s", name, ext)); + Files.write(resourceForkPath, fileEntry.getResourceFork().get().asBytes(), StandardOpenOption.CREATE); + } + return paths; + } catch (IOException ex) { + throw new UncheckedIOException(ex); + } + } } diff --git a/app/gui-javafx/src/main/java/org/applecommander/javafx/settings/Settings.java b/app/gui-javafx/src/main/java/org/applecommander/javafx/settings/Settings.java index 80db3041..159b14a9 100644 --- a/app/gui-javafx/src/main/java/org/applecommander/javafx/settings/Settings.java +++ b/app/gui-javafx/src/main/java/org/applecommander/javafx/settings/Settings.java @@ -60,13 +60,13 @@ public abstract class Settings { prefs.put(THEME_SELECTION, themeSelection.name()); } - public static Optional getExportOption() { + public static ExportOption getExportOption() { Preferences prefs = Preferences.userNodeForPackage(AppleCommanderFX.class); String exportName = prefs.get(EXPORT_OPTION, null); if (exportName == null || exportName.isBlank()) { - return Optional.of(ExportOption.RAW_BINARY); + return ExportOption.RAW_BINARY; } - return Optional.of(ExportOption.valueOf(exportName)); + return ExportOption.valueOf(exportName); } public static void setExportOption(ExportOption exportOption) { diff --git a/app/gui-javafx/src/main/java/org/applecommander/javafx/settings/SettingsDialog.java b/app/gui-javafx/src/main/java/org/applecommander/javafx/settings/SettingsDialog.java index 9774226a..01ddda82 100644 --- a/app/gui-javafx/src/main/java/org/applecommander/javafx/settings/SettingsDialog.java +++ b/app/gui-javafx/src/main/java/org/applecommander/javafx/settings/SettingsDialog.java @@ -74,7 +74,7 @@ public class SettingsDialog { Objects.requireNonNull(parent); Settings.getThemeSelection().ifPresent(themeSelection::set); - Settings.getExportOption().ifPresent(exportOption::set); + exportOption.set(Settings.getExportOption()); Window window = dialog.getDialogPane().getScene().getWindow(); diff --git a/lib/ac-api/src/main/java/com/webcodepro/applecommander/storage/DiskFileStoreAdapter.java b/lib/ac-api/src/main/java/com/webcodepro/applecommander/storage/DiskFileStoreAdapter.java index 048f3687..e9aea03c 100644 --- a/lib/ac-api/src/main/java/com/webcodepro/applecommander/storage/DiskFileStoreAdapter.java +++ b/lib/ac-api/src/main/java/com/webcodepro/applecommander/storage/DiskFileStoreAdapter.java @@ -222,10 +222,6 @@ public class DiskFileStoreAdapter implements FileStore { return DataBuffer.wrap(fileEntry.getFileData()); } @Override - public Optional getResourceFork() { - throw new RuntimeException("Not supported by the legacy AppleCommander."); - } - @Override public void setDataFork(DataBuffer fileData) { try { fileEntry.setFileData(fileData.asBytes());