mirror of
https://github.com/AppleCommander/AppleCommander.git
synced 2026-10-24 23:02:27 +00:00
Enabling drag and drop between AppleCommander windows. Internally, uses the AppleSingle format.
This commit is contained in:
1 parent
6a8db12494
commit
33f2eeae7b
3 files changed
+130
-28
No files matched your search
@@ -37,6 +37,7 @@ import javafx.scene.layout.StackPane;
|
||||
import javafx.scene.layout.VBox;
|
||||
import javafx.scene.paint.Color;
|
||||
import javafx.scene.shape.Rectangle;
|
||||
import org.applecommander.filestore.FileStore;
|
||||
import org.applecommander.usage.BlockUsage;
|
||||
import org.applecommander.usage.DiskUsage;
|
||||
import org.applecommander.usage.DiskUsage.UsageType;
|
||||
@@ -79,24 +80,14 @@ public class DiskUsageView extends StackPane {
|
||||
// Chart view
|
||||
pieChartView = new PieChart();
|
||||
pieChartView.setTitle("Disk Usage");
|
||||
fileStoreWindow.fileStoreSelection().selectedItemProperty().addListener((observable, oldValue, newValue) -> {
|
||||
if (newValue != null) {
|
||||
Optional<DiskUsage> opt = newValue.get(DiskUsage.class);
|
||||
if (opt.isEmpty()) {
|
||||
// nothing to view
|
||||
return;
|
||||
}
|
||||
DiskUsage usage = opt.get();
|
||||
// Somewhat arbitrary, but the grid view really lags in HDD's; even with the drawing deferred.
|
||||
largeDisk.set(usage.getTotal() > 2000);
|
||||
if (!largeDisk.get()) {
|
||||
updateGridView(usage);
|
||||
viewMode.set(Mode.GRID_VIEW);
|
||||
}
|
||||
else {
|
||||
viewMode.set(Mode.CHART_VIEW);
|
||||
}
|
||||
updateChartView(usage);
|
||||
|
||||
// Refresh on updates
|
||||
fileStoreWindow.fileStoreSelection().selectedItemProperty().addListener((_, _, newFileStore) -> {
|
||||
updateDisplay(newFileStore);
|
||||
});
|
||||
fileStoreWindow.hasChangedProperty().addListener((_, _, hasChanged) -> {
|
||||
if (hasChanged) {
|
||||
updateDisplay(fileStoreWindow.fileStoreSelection().getSelectedItem());
|
||||
}
|
||||
});
|
||||
|
||||
@@ -120,6 +111,24 @@ public class DiskUsageView extends StackPane {
|
||||
viewMode.set(Mode.GRID_VIEW);
|
||||
}
|
||||
|
||||
public void updateDisplay(FileStore fileStore) {
|
||||
if (fileStore == null) return;
|
||||
Optional<DiskUsage> opt = fileStore.get(DiskUsage.class);
|
||||
if (opt.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
DiskUsage usage = opt.get();
|
||||
largeDisk.set(usage.getTotal() > 2000);
|
||||
if (!largeDisk.get()) {
|
||||
updateGridView(usage);
|
||||
viewMode.set(Mode.GRID_VIEW);
|
||||
}
|
||||
else {
|
||||
viewMode.set(Mode.CHART_VIEW);
|
||||
}
|
||||
updateChartView(usage);
|
||||
}
|
||||
|
||||
public void bindScene(Scene scene) {
|
||||
// Function keys for view modes
|
||||
applyShortcutToButton(scene, usageGridToggle, "Grid View",
|
||||
|
||||
@@ -33,25 +33,35 @@ import javafx.scene.input.*;
|
||||
import javafx.scene.layout.BorderPane;
|
||||
import javafx.scene.layout.HBox;
|
||||
import javafx.scene.layout.VBox;
|
||||
import org.applecommander.applesingle.AppleSingle;
|
||||
import org.applecommander.applesingle.FileDatesInfo;
|
||||
import org.applecommander.applesingle.ProdosFileInfo;
|
||||
import org.applecommander.capability.Capability;
|
||||
import org.applecommander.filestore.*;
|
||||
import org.applecommander.javafx.settings.ExportOption;
|
||||
import org.applecommander.javafx.settings.Settings;
|
||||
import org.applecommander.source.Source;
|
||||
import org.applecommander.source.Sources;
|
||||
import org.applecommander.util.DataBuffer;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.UncheckedIOException;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
import static org.applecommander.javafx.FxUtils.*;
|
||||
|
||||
public class FileView extends BorderPane {
|
||||
// See https://en.wikipedia.org/wiki/AppleSingle_and_AppleDouble_formats
|
||||
public static final DataFormat APPLESINGLE_MIME = new DataFormat("application/applefile");
|
||||
|
||||
private final FileStoreWindow fileStoreWindow;
|
||||
private final HBox breadcrumbBar;
|
||||
private final ToggleButton nativeToolButton;
|
||||
@@ -157,9 +167,12 @@ public class FileView extends BorderPane {
|
||||
selectedDirectory.set(directoryPath.isEmpty() ? null : directoryPath.getLast());
|
||||
});
|
||||
|
||||
selectedDirectory.addListener((_, _, newValue) -> {
|
||||
selectedDirectory.addListener((_, _, _) -> {
|
||||
populateDiskRows();
|
||||
});
|
||||
fileStoreWindow.hasChangedProperty().addListener((_, _, _) -> {
|
||||
populateDiskRows();
|
||||
});
|
||||
}
|
||||
|
||||
public void createNewFileTable() {
|
||||
@@ -202,6 +215,7 @@ public class FileView extends BorderPane {
|
||||
fileTable.setOnDragDetected(event -> {
|
||||
if (!fileTable.getSelectionModel().getSelectedItems().isEmpty()) {
|
||||
try {
|
||||
// If we are dragging OUT of AppleCommander, we need to create working files:
|
||||
ExportOption exportOption = Settings.getExportOption();
|
||||
Path tempDir = Files.createTempDirectory("AppleCommander-drag-");
|
||||
tempDir.toFile().deleteOnExit();
|
||||
@@ -216,6 +230,12 @@ public class FileView extends BorderPane {
|
||||
}
|
||||
ClipboardContent content = new ClipboardContent();
|
||||
content.putFiles(files);
|
||||
// Internal drag format is AppleSingle, and one file at a time:
|
||||
AppleSingle appleSingle = ExportOption.createAppleSingle(fileTable.getSelectionModel().getSelectedItem());
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
appleSingle.save(baos);
|
||||
content.put(APPLESINGLE_MIME, ByteBuffer.wrap(baos.toByteArray()));
|
||||
// Now we're ready, so allow it to proceed:
|
||||
Dragboard db = fileTable.startDragAndDrop(TransferMode.COPY_OR_MOVE);
|
||||
db.setContent(content);
|
||||
} catch (IOException e) {
|
||||
@@ -224,10 +244,79 @@ public class FileView extends BorderPane {
|
||||
}
|
||||
event.consume();
|
||||
});
|
||||
fileTable.setOnDragOver(event -> {
|
||||
FileStore fileStore = fileStoreWindow.fileStoreSelection().getSelectedItem();
|
||||
Directory directory = selectedDirectory.get();
|
||||
Dragboard db = event.getDragboard();
|
||||
boolean internalDrag = db.hasContent(APPLESINGLE_MIME);
|
||||
boolean externalDrag = db.hasFiles();
|
||||
boolean canCreateFiles = fileStore != null && fileStore.can(Capability.CREATE_FILES) && directory instanceof WritableDirectory;
|
||||
if ((internalDrag || externalDrag) && canCreateFiles) {
|
||||
event.acceptTransferModes(TransferMode.COPY_OR_MOVE);
|
||||
}
|
||||
event.consume();
|
||||
});
|
||||
fileTable.setOnDragDropped(event -> {
|
||||
Dragboard db = event.getDragboard();
|
||||
boolean success = false;
|
||||
try {
|
||||
if (db.hasContent(APPLESINGLE_MIME)) {
|
||||
// Give preference to internal dragging.
|
||||
ByteBuffer data = (ByteBuffer) db.getContent(APPLESINGLE_MIME);
|
||||
AppleSingle appleSingle = AppleSingle.read(data.array());
|
||||
ProdosAttributes prodosAttributes = createProdosAttributes(appleSingle);
|
||||
createFile(prodosAttributes, appleSingle.getDataFork(), appleSingle.getResourceFork());
|
||||
success = true;
|
||||
} else if (db.hasFiles()) {
|
||||
// From the file system.
|
||||
System.out.println("DROPPED");
|
||||
System.out.println(db.getFiles());
|
||||
success = true;
|
||||
}
|
||||
} catch (IOException e) {
|
||||
FxUtils.showErrorDialog("Unable to drop files", e);
|
||||
}
|
||||
event.setDropCompleted(success);
|
||||
event.consume();
|
||||
});
|
||||
|
||||
managedProperty().bind(fileTable.visibleProperty());
|
||||
}
|
||||
|
||||
public ProdosAttributes createProdosAttributes(AppleSingle appleSingle) {
|
||||
ProdosAttributes.Builder builder = ProdosAttributes.builder().name("NEWFILE").BIN(0x0000);
|
||||
if (appleSingle.getRealName() != null) {
|
||||
builder.name(appleSingle.getRealName());
|
||||
}
|
||||
if (appleSingle.getFileDatesInfo() != null) {
|
||||
FileDatesInfo fileDatesInfo = appleSingle.getFileDatesInfo();
|
||||
builder.creation(Date.from(fileDatesInfo.getCreationInstant()));
|
||||
builder.modification(Date.from(fileDatesInfo.getModificationInstant()));
|
||||
}
|
||||
if (appleSingle.getProdosFileInfo() != null) {
|
||||
ProdosFileInfo prodosFileInfo = appleSingle.getProdosFileInfo();
|
||||
builder.auxType(prodosFileInfo.getAuxType());
|
||||
builder.fileType(prodosFileInfo.getFileType());
|
||||
builder.locked((prodosFileInfo.getAccess() & 0xe3) == 0xe3);
|
||||
}
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
public void createFile(ProdosAttributes prodosAttributes, byte[] dataFork, byte[] resourceFork) {
|
||||
Directory directory = selectedDirectory.get();
|
||||
if (directory instanceof WritableDirectory writableDirectory) {
|
||||
WritableFileEntry fileEntry = writableDirectory.createFrom(prodosAttributes);
|
||||
fileEntry.setDataFork(DataBuffer.wrap(dataFork));
|
||||
if (resourceFork != null) {
|
||||
fileEntry.setResourceFork(DataBuffer.wrap(resourceFork));
|
||||
}
|
||||
fileStoreWindow.hasChangedProperty().set(true);
|
||||
}
|
||||
else {
|
||||
throw new RuntimeException("This is not a writable directory");
|
||||
}
|
||||
}
|
||||
|
||||
public void bindScene(Scene scene) {
|
||||
// Function keys for view modes
|
||||
applyShortcutToButton(scene, nativeToolButton, "Native View",
|
||||
|
||||
@@ -84,20 +84,24 @@ public enum ExportOption {
|
||||
}
|
||||
}
|
||||
|
||||
public static AppleSingle createAppleSingle(FileEntry fileEntry) {
|
||||
ProdosAttributes attributes = fileEntry.getProdosAttributes();
|
||||
AppleSingle.Builder builder = AppleSingle.builder()
|
||||
.realName(fileEntry.getName())
|
||||
.access(attributes.access())
|
||||
.auxType(attributes.auxType())
|
||||
.fileType(attributes.fileType())
|
||||
.dataFork(fileEntry.getDataFork().asBytes());
|
||||
fileEntry.getResourceFork().ifPresent(resourceFork -> builder.resourceFork(resourceFork.asBytes()));
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
public static List<Path> copyToAppleSingle(Path directory, FileEntry fileEntry) {
|
||||
try {
|
||||
List<Path> paths = new ArrayList<>();
|
||||
Path destination = directory.resolve(fileEntry.getName() + ".as");
|
||||
paths.add(destination);
|
||||
ProdosAttributes attributes = fileEntry.getProdosAttributes();
|
||||
AppleSingle.Builder builder = AppleSingle.builder()
|
||||
.realName(fileEntry.getName())
|
||||
.access(attributes.access())
|
||||
.auxType(attributes.auxType())
|
||||
.fileType(attributes.fileType())
|
||||
.dataFork(fileEntry.getDataFork().asBytes());
|
||||
fileEntry.getResourceFork().ifPresent(resourceFork -> builder.resourceFork(resourceFork.asBytes()));
|
||||
builder.build().save(destination);
|
||||
createAppleSingle(fileEntry).save(destination);
|
||||
return paths;
|
||||
} catch (IOException ex) {
|
||||
throw new UncheckedIOException(ex);
|
||||
|
||||
Reference in new issue
Block a user