mirror of
https://github.com/xpipe-io/xpipe.git
synced 2024-07-04 22:10:56 +12:00
Various file system fixes
This commit is contained in:
parent
491d3c201c
commit
01a3177843
|
@ -91,6 +91,8 @@ final class FileListComp extends AnchorPane {
|
||||||
table.setColumnResizePolicy(TableView.CONSTRAINED_RESIZE_POLICY);
|
table.setColumnResizePolicy(TableView.CONSTRAINED_RESIZE_POLICY);
|
||||||
filenameCol.minWidthProperty().bind(table.widthProperty().multiply(0.5));
|
filenameCol.minWidthProperty().bind(table.widthProperty().multiply(0.5));
|
||||||
|
|
||||||
|
var draggedOverDirectory = new SimpleBooleanProperty();
|
||||||
|
|
||||||
table.setOnKeyPressed(event -> {
|
table.setOnKeyPressed(event -> {
|
||||||
if (event.isControlDown()
|
if (event.isControlDown()
|
||||||
&& event.getCode().equals(KeyCode.C)
|
&& event.getCode().equals(KeyCode.C)
|
||||||
|
@ -119,10 +121,7 @@ final class FileListComp extends AnchorPane {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var cm = new FileContextMenu(
|
var cm = new FileContextMenu(fileList.getModel(), row.getItem(), editing);
|
||||||
fileList.getModel(),
|
|
||||||
row.getItem(),
|
|
||||||
editing);
|
|
||||||
if (t.getButton() == MouseButton.SECONDARY) {
|
if (t.getButton() == MouseButton.SECONDARY) {
|
||||||
cm.show(row, t.getScreenX(), t.getScreenY());
|
cm.show(row, t.getScreenX(), t.getScreenY());
|
||||||
}
|
}
|
||||||
|
@ -134,12 +133,20 @@ final class FileListComp extends AnchorPane {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
draggedOverDirectory.addListener((observable, oldValue, newValue) -> {
|
||||||
|
row.pseudoClassStateChanged(DRAG, newValue);
|
||||||
|
});
|
||||||
|
|
||||||
row.setOnDragOver(event -> {
|
row.setOnDragOver(event -> {
|
||||||
if (row.equals(event.getGestureSource())) {
|
if (row.equals(event.getGestureSource())) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
row.pseudoClassStateChanged(DRAG, true);
|
if (row.getItem() == null || !row.getItem().isDirectory()) {
|
||||||
|
draggedOverDirectory.set(true);
|
||||||
|
} else {
|
||||||
|
row.pseudoClassStateChanged(DRAG, true);
|
||||||
|
}
|
||||||
event.acceptTransferModes(TransferMode.ANY);
|
event.acceptTransferModes(TransferMode.ANY);
|
||||||
event.consume();
|
event.consume();
|
||||||
});
|
});
|
||||||
|
@ -162,12 +169,13 @@ final class FileListComp extends AnchorPane {
|
||||||
});
|
});
|
||||||
|
|
||||||
row.setOnDragExited(event -> {
|
row.setOnDragExited(event -> {
|
||||||
row.pseudoClassStateChanged(DRAG, false);
|
if (row.getItem() != null && row.getItem().isDirectory()) {
|
||||||
event.consume();
|
row.pseudoClassStateChanged(DRAG, false);
|
||||||
|
} else {
|
||||||
|
draggedOverDirectory.set(false);
|
||||||
|
}
|
||||||
|
|
||||||
if (event.getGestureSource() == null && event.getDragboard().hasFiles()) {
|
if (event.getGestureSource() == null && event.getDragboard().hasFiles()) {
|
||||||
row.pseudoClassStateChanged(DRAG, false);
|
|
||||||
event.consume();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// if (event.getGestureSource() != null) {
|
// if (event.getGestureSource() != null) {
|
||||||
|
@ -207,28 +215,31 @@ final class FileListComp extends AnchorPane {
|
||||||
// });
|
// });
|
||||||
|
|
||||||
row.setOnDragDropped(event -> {
|
row.setOnDragDropped(event -> {
|
||||||
|
draggedOverDirectory.set(false);
|
||||||
|
|
||||||
// Accept drops from outside the app window
|
// Accept drops from outside the app window
|
||||||
if (event.getGestureSource() == null && event.getDragboard().hasFiles()) {
|
if (event.getGestureSource() == null && event.getDragboard().hasFiles()) {
|
||||||
event.setDropCompleted(true);
|
|
||||||
Dragboard db = event.getDragboard();
|
Dragboard db = event.getDragboard();
|
||||||
var list = db.getFiles().stream().map(File::toPath).toList();
|
var list = db.getFiles().stream().map(File::toPath).toList();
|
||||||
var target = row.getItem() != null
|
var target = row.getItem() != null && row.getItem().isDirectory()
|
||||||
? row.getItem()
|
? row.getItem()
|
||||||
: fileList.getModel().getCurrentDirectory();
|
: fileList.getModel().getCurrentDirectory();
|
||||||
fileList.getModel().dropLocalFilesIntoAsync(target, list);
|
fileList.getModel().dropLocalFilesIntoAsync(target, list);
|
||||||
|
event.setDropCompleted(true);
|
||||||
|
event.consume();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Accept drops from inside the app window
|
// Accept drops from inside the app window
|
||||||
if (event.getGestureSource() != null) {
|
if (event.getGestureSource() != null) {
|
||||||
event.setDropCompleted(true);
|
var files = FileBrowserClipboard.retrieveDrag(event.getDragboard())
|
||||||
var files = FileBrowserClipboard.retrieveDrag(event.getDragboard()).getEntries();
|
.getEntries();
|
||||||
var target = row.getItem() != null
|
var target = row.getItem() != null
|
||||||
? row.getItem()
|
? row.getItem()
|
||||||
: fileList.getModel().getCurrentDirectory();
|
: fileList.getModel().getCurrentDirectory();
|
||||||
fileList.getModel().dropFilesIntoAsync(target, files, false);
|
fileList.getModel().dropFilesIntoAsync(target, files, false);
|
||||||
|
event.setDropCompleted(true);
|
||||||
|
event.consume();
|
||||||
}
|
}
|
||||||
|
|
||||||
event.consume();
|
|
||||||
});
|
});
|
||||||
|
|
||||||
return row;
|
return row;
|
||||||
|
|
|
@ -76,7 +76,7 @@ public class FileSystemHelper {
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void dropFilesInto(
|
public static void dropFilesInto(
|
||||||
FileSystem.FileEntry target, List<FileSystem.FileEntry> files, boolean explicitCopy) {
|
FileSystem.FileEntry target, List<FileSystem.FileEntry> files, boolean explicitCopy) throws Exception {
|
||||||
if (files.size() == 0) {
|
if (files.size() == 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -91,68 +91,59 @@ public class FileSystemHelper {
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void dropFileAcrossSameFileSystem(
|
private static void dropFileAcrossSameFileSystem(
|
||||||
FileSystem.FileEntry target, FileSystem.FileEntry file, boolean explicitCopy) {
|
FileSystem.FileEntry target, FileSystem.FileEntry source, boolean explicitCopy) throws Exception {
|
||||||
// Prevent dropping directory into itself
|
// Prevent dropping directory into itself
|
||||||
if (FileNames.startsWith(file.getPath(), target.getPath())) {
|
if (FileNames.startsWith(source.getPath(), target.getPath())) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
var sourceFile = source.getPath();
|
||||||
var sourceFile = file.getPath();
|
var targetFile = FileNames.join(target.getPath(), FileNames.getFileName(sourceFile));
|
||||||
var targetFile = FileNames.join(target.getPath(), FileNames.getFileName(sourceFile));
|
if (explicitCopy) {
|
||||||
if (explicitCopy) {
|
target.getFileSystem().copy(sourceFile, targetFile);
|
||||||
target.getFileSystem().copy(sourceFile, targetFile);
|
} else {
|
||||||
} else {
|
target.getFileSystem().move(sourceFile, targetFile);
|
||||||
target.getFileSystem().move(sourceFile, targetFile);
|
|
||||||
}
|
|
||||||
} catch (Exception ex) {
|
|
||||||
ErrorEvent.fromThrowable(ex).handle();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void dropFileAcrossFileSystems(FileSystem.FileEntry target, FileSystem.FileEntry file) {
|
private static void dropFileAcrossFileSystems(FileSystem.FileEntry target, FileSystem.FileEntry source)
|
||||||
|
throws Exception {
|
||||||
var flatFiles = new HashMap<FileSystem.FileEntry, String>();
|
var flatFiles = new HashMap<FileSystem.FileEntry, String>();
|
||||||
|
|
||||||
// Prevent dropping directory into itself
|
// Prevent dropping directory into itself
|
||||||
if (file.getFileSystem().equals(target.getFileSystem())
|
if (source.getFileSystem().equals(target.getFileSystem())
|
||||||
&& FileNames.startsWith(file.getPath(), target.getPath())) {
|
&& FileNames.startsWith(source.getPath(), target.getPath())) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
if (source.isDirectory()) {
|
||||||
if (file.isDirectory()) {
|
var directoryName = FileNames.getFileName(source.getPath());
|
||||||
flatFiles.put(file, FileNames.getFileName(file.getPath()));
|
flatFiles.put(source, directoryName);
|
||||||
try (var stream = file.getFileSystem().listFilesRecursively(file.getPath())) {
|
|
||||||
stream.forEach(fileEntry -> {
|
var baseRelative = FileNames.toDirectory(FileNames.getParent(source.getPath()));
|
||||||
flatFiles.put(fileEntry, FileNames.relativize(file.getPath(), fileEntry.getPath()));
|
try (var stream = source.getFileSystem().listFilesRecursively(source.getPath())) {
|
||||||
});
|
stream.forEach(fileEntry -> {
|
||||||
}
|
flatFiles.put(fileEntry, FileNames.toUnix(FileNames.relativize(baseRelative, fileEntry.getPath())));
|
||||||
} else {
|
});
|
||||||
flatFiles.put(file, FileNames.getFileName(file.getPath()));
|
|
||||||
}
|
}
|
||||||
} catch (Exception ex) {
|
} else {
|
||||||
ErrorEvent.fromThrowable(ex).handle();
|
flatFiles.put(source, FileNames.getFileName(source.getPath()));
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for (var e : flatFiles.entrySet()) {
|
for (var e : flatFiles.entrySet()) {
|
||||||
var sourceFile = e.getKey();
|
var sourceFile = e.getKey();
|
||||||
var targetFile = FileNames.join(target.getPath(), e.getValue());
|
var targetFile = FileNames.join(target.getPath(), e.getValue());
|
||||||
try {
|
if (sourceFile.getFileSystem().equals(target.getFileSystem())) {
|
||||||
if (sourceFile.getFileSystem().equals(target.getFileSystem())) {
|
throw new IllegalStateException();
|
||||||
throw new IllegalStateException();
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (sourceFile.isDirectory()) {
|
if (sourceFile.isDirectory()) {
|
||||||
target.getFileSystem().mkdirs(targetFile);
|
target.getFileSystem().mkdirs(targetFile);
|
||||||
} else {
|
} else {
|
||||||
try (var in = sourceFile.getFileSystem().openInput(sourceFile.getPath());
|
try (var in = sourceFile.getFileSystem().openInput(sourceFile.getPath());
|
||||||
var out = target.getFileSystem().openOutput(targetFile)) {
|
var out = target.getFileSystem().openOutput(targetFile)) {
|
||||||
in.transferTo(out);
|
in.transferTo(out);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} catch (Exception ex) {
|
|
||||||
ErrorEvent.fromThrowable(ex).handle();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -190,7 +190,7 @@ public class AppInstaller {
|
||||||
.start()) {
|
.start()) {
|
||||||
c.discardOrThrow();
|
c.discardOrThrow();
|
||||||
}
|
}
|
||||||
pc.executeSimpleCommand("xpipe daemon start");
|
pc.executeSimpleCommand("xpipe open");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -198,7 +198,7 @@ public class AppInstaller {
|
||||||
public void installLocal(String file) throws Exception {
|
public void installLocal(String file) throws Exception {
|
||||||
var command = "set -x\n" + "DEBIAN_FRONTEND=noninteractive sudo apt-get remove -qy xpipe\n"
|
var command = "set -x\n" + "DEBIAN_FRONTEND=noninteractive sudo apt-get remove -qy xpipe\n"
|
||||||
+ "DEBIAN_FRONTEND=noninteractive sudo apt-get install -qy \"" + file + "\"\n"
|
+ "DEBIAN_FRONTEND=noninteractive sudo apt-get install -qy \"" + file + "\"\n"
|
||||||
+ "xpipe daemon start";
|
+ "xpipe open";
|
||||||
TerminalHelper.open("X-Pipe Updater", command);
|
TerminalHelper.open("X-Pipe Updater", command);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -218,13 +218,13 @@ public class AppInstaller {
|
||||||
.start()) {
|
.start()) {
|
||||||
c.discardOrThrow();
|
c.discardOrThrow();
|
||||||
}
|
}
|
||||||
pc.executeSimpleCommand("xpipe daemon start");
|
pc.executeSimpleCommand("xpipe open");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void installLocal(String file) throws Exception {
|
public void installLocal(String file) throws Exception {
|
||||||
var command = "set -x\n" + "sudo rpm -U -v --force \"" + file + "\"\n" + "xpipe daemon start";
|
var command = "set -x\n" + "sudo rpm -U -v --force \"" + file + "\"\n" + "xpipe open";
|
||||||
TerminalHelper.open("X-Pipe Updater", command);
|
TerminalHelper.open("X-Pipe Updater", command);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -245,14 +245,14 @@ public class AppInstaller {
|
||||||
.start()) {
|
.start()) {
|
||||||
c.discardOrThrow();
|
c.discardOrThrow();
|
||||||
}
|
}
|
||||||
pc.executeSimpleCommand("xpipe daemon start");
|
pc.executeSimpleCommand("xpipe open");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void installLocal(String file) throws Exception {
|
public void installLocal(String file) throws Exception {
|
||||||
var command = "set -x\n" + "sudo installer -verboseR -allowUntrusted -pkg \"" + file + "\" -target /\n"
|
var command = "set -x\n" + "sudo installer -verboseR -allowUntrusted -pkg \"" + file + "\" -target /\n"
|
||||||
+ "xpipe daemon start";
|
+ "xpipe open";
|
||||||
TerminalHelper.open("X-Pipe Updater", command);
|
TerminalHelper.open("X-Pipe Updater", command);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -67,10 +67,13 @@ public class FileNames {
|
||||||
|
|
||||||
public static String toUnix(String file) {
|
public static String toUnix(String file) {
|
||||||
var joined = String.join("/", split(file));
|
var joined = String.join("/", split(file));
|
||||||
return file.startsWith("/") ? "/" + joined : joined;
|
var prefix = file.startsWith("/") ? "/" : "";
|
||||||
|
var suffix = file.endsWith("/") || file.endsWith("\\") ? "/" : "";
|
||||||
|
return prefix + joined + suffix;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static String toWindows(String file) {
|
public static String toWindows(String file) {
|
||||||
return String.join("\\", split(file));
|
var suffix = file.endsWith("/") || file.endsWith("\\") ? "\\" : "";
|
||||||
|
return String.join("\\", split(file)) + suffix;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,9 +1,10 @@
|
||||||
package io.xpipe.core.process;
|
package io.xpipe.core.process;
|
||||||
|
|
||||||
import io.xpipe.core.charsetter.Charsetter;
|
import io.xpipe.core.charsetter.Charsetter;
|
||||||
import lombok.SneakyThrows;
|
|
||||||
|
|
||||||
import java.io.*;
|
import java.io.InputStream;
|
||||||
|
import java.io.InputStreamReader;
|
||||||
|
import java.io.OutputStream;
|
||||||
import java.nio.charset.Charset;
|
import java.nio.charset.Charset;
|
||||||
import java.util.function.Consumer;
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
|
@ -20,31 +21,9 @@ public interface CommandProcessControl extends ProcessControl {
|
||||||
|
|
||||||
ShellProcessControl getParent();
|
ShellProcessControl getParent();
|
||||||
|
|
||||||
default InputStream startExternalStdout() throws Exception {
|
InputStream startExternalStdout() throws Exception;
|
||||||
start();
|
|
||||||
discardErr();
|
|
||||||
return new FilterInputStream(getStdout()) {
|
|
||||||
@Override
|
|
||||||
@SneakyThrows
|
|
||||||
public void close() throws IOException {
|
|
||||||
CommandProcessControl.this.close();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
default OutputStream startExternalStdin() throws Exception {
|
OutputStream startExternalStdin() throws Exception;
|
||||||
start();
|
|
||||||
discardOut();
|
|
||||||
discardErr();
|
|
||||||
return new FilterOutputStream(getStdin()) {
|
|
||||||
@Override
|
|
||||||
@SneakyThrows
|
|
||||||
public void close() throws IOException {
|
|
||||||
closeStdin();
|
|
||||||
CommandProcessControl.this.close();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean waitFor();
|
public boolean waitFor();
|
||||||
|
|
||||||
|
|
|
@ -5,9 +5,14 @@ import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.io.OutputStream;
|
import java.io.OutputStream;
|
||||||
import java.nio.charset.Charset;
|
import java.nio.charset.Charset;
|
||||||
|
import java.util.concurrent.ExecutorService;
|
||||||
|
|
||||||
public interface ProcessControl extends Closeable, AutoCloseable {
|
public interface ProcessControl extends Closeable, AutoCloseable {
|
||||||
|
|
||||||
|
ExecutorService getStdoutReader();
|
||||||
|
|
||||||
|
ExecutorService getStderrReader();
|
||||||
|
|
||||||
ProcessControl sensitive();
|
ProcessControl sensitive();
|
||||||
|
|
||||||
String prepareTerminalOpen() throws Exception;
|
String prepareTerminalOpen() throws Exception;
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
package io.xpipe.core.store;
|
package io.xpipe.core.store;
|
||||||
|
|
||||||
|
import io.xpipe.core.impl.FileNames;
|
||||||
import io.xpipe.core.process.ShellProcessControl;
|
import io.xpipe.core.process.ShellProcessControl;
|
||||||
import lombok.NonNull;
|
import lombok.NonNull;
|
||||||
import lombok.Value;
|
import lombok.Value;
|
||||||
|
@ -26,6 +27,19 @@ public interface FileSystem extends Closeable, AutoCloseable {
|
||||||
boolean hidden;
|
boolean hidden;
|
||||||
Boolean executable;
|
Boolean executable;
|
||||||
long size;
|
long size;
|
||||||
|
|
||||||
|
public FileEntry(
|
||||||
|
@NonNull FileSystem fileSystem, @NonNull String path, @NonNull Instant date, boolean directory, boolean hidden, Boolean executable,
|
||||||
|
long size
|
||||||
|
) {
|
||||||
|
this.fileSystem = fileSystem;
|
||||||
|
this.path = directory ? FileNames.toDirectory(path) : path;
|
||||||
|
this.date = date;
|
||||||
|
this.directory = directory;
|
||||||
|
this.hidden = hidden;
|
||||||
|
this.executable = executable;
|
||||||
|
this.size = size;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Optional<ShellProcessControl> getShell();
|
Optional<ShellProcessControl> getShell();
|
||||||
|
@ -54,6 +68,10 @@ public interface FileSystem extends Closeable, AutoCloseable {
|
||||||
|
|
||||||
default Stream<FileEntry> listFilesRecursively(String file) throws Exception {
|
default Stream<FileEntry> listFilesRecursively(String file) throws Exception {
|
||||||
return listFiles(file).flatMap(fileEntry -> {
|
return listFiles(file).flatMap(fileEntry -> {
|
||||||
|
if (!fileEntry.isDirectory()) {
|
||||||
|
return Stream.of(fileEntry);
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
return listFilesRecursively(fileEntry.getPath());
|
return listFilesRecursively(fileEntry.getPath());
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
|
|
Loading…
Reference in a new issue