mirror of
https://github.com/xpipe-io/xpipe.git
synced 2024-11-21 23:20:23 +00:00
File transfer fixes
This commit is contained in:
parent
d41b3017f6
commit
a7d825be67
11 changed files with 237 additions and 155 deletions
|
@ -0,0 +1,83 @@
|
|||
package io.xpipe.app.browser;
|
||||
|
||||
import io.xpipe.app.browser.fs.OpenFileSystemModel;
|
||||
import io.xpipe.app.prefs.AppPrefs;
|
||||
import io.xpipe.app.util.BooleanScope;
|
||||
import io.xpipe.app.util.FileBridge;
|
||||
import io.xpipe.app.util.FileOpener;
|
||||
import io.xpipe.core.store.FileNames;
|
||||
import io.xpipe.core.store.FileSystem;
|
||||
|
||||
import java.io.OutputStream;
|
||||
|
||||
public class BrowserFileOpener {
|
||||
|
||||
public static void openWithAnyApplication(OpenFileSystemModel model, FileSystem.FileEntry entry) {
|
||||
var file = entry.getPath();
|
||||
var key = entry.getPath().hashCode() + entry.getFileSystem().hashCode();
|
||||
FileBridge.get()
|
||||
.openIO(
|
||||
FileNames.getFileName(file),
|
||||
key,
|
||||
new BooleanScope(model.getBusy()).exclusive(),
|
||||
() -> {
|
||||
return entry.getFileSystem().openInput(file);
|
||||
},
|
||||
(size) -> {
|
||||
if (model.isClosed()) {
|
||||
return OutputStream.nullOutputStream();
|
||||
}
|
||||
|
||||
return entry.getFileSystem().openOutput(file, size);
|
||||
},
|
||||
s -> FileOpener.openWithAnyApplication(s));
|
||||
}
|
||||
|
||||
public static void openInDefaultApplication(OpenFileSystemModel model, FileSystem.FileEntry entry) {
|
||||
var file = entry.getPath();
|
||||
var key = entry.getPath().hashCode() + entry.getFileSystem().hashCode();
|
||||
FileBridge.get()
|
||||
.openIO(
|
||||
FileNames.getFileName(file),
|
||||
key,
|
||||
new BooleanScope(model.getBusy()).exclusive(),
|
||||
() -> {
|
||||
return entry.getFileSystem().openInput(file);
|
||||
},
|
||||
(size) -> {
|
||||
if (model.isClosed()) {
|
||||
return OutputStream.nullOutputStream();
|
||||
}
|
||||
|
||||
return entry.getFileSystem().openOutput(file, size);
|
||||
},
|
||||
s -> FileOpener.openInDefaultApplication(s));
|
||||
}
|
||||
|
||||
public static void openInTextEditor(OpenFileSystemModel model, FileSystem.FileEntry entry) {
|
||||
var editor = AppPrefs.get().externalEditor().getValue();
|
||||
if (editor == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
var file = entry.getPath();
|
||||
var key = entry.getPath().hashCode() + entry.getFileSystem().hashCode();
|
||||
FileBridge.get()
|
||||
.openIO(
|
||||
FileNames.getFileName(file),
|
||||
key,
|
||||
new BooleanScope(model.getBusy()).exclusive(),
|
||||
() -> {
|
||||
return entry.getFileSystem().openInput(file);
|
||||
|
||||
},
|
||||
(size) -> {
|
||||
if (model.isClosed()) {
|
||||
return OutputStream.nullOutputStream();
|
||||
}
|
||||
|
||||
return entry.getFileSystem().openOutput(file, size);
|
||||
},
|
||||
FileOpener::openInTextEditor);
|
||||
}
|
||||
}
|
|
@ -28,7 +28,7 @@ public interface LeafAction extends BrowserAction {
|
|||
}
|
||||
|
||||
ThreadHelper.runFailableAsync(() -> {
|
||||
BooleanScope.execute(model.getBusy(), () -> {
|
||||
BooleanScope.executeExclusive(model.getBusy(), () -> {
|
||||
// Start shell in case we exited
|
||||
model.getFileSystem().getShell().orElseThrow().start();
|
||||
execute(model, selected);
|
||||
|
@ -77,7 +77,7 @@ public interface LeafAction extends BrowserAction {
|
|||
}));
|
||||
mi.setOnAction(event -> {
|
||||
ThreadHelper.runFailableAsync(() -> {
|
||||
BooleanScope.execute(model.getBusy(), () -> {
|
||||
BooleanScope.executeExclusive(model.getBusy(), () -> {
|
||||
// Start shell in case we exited
|
||||
model.getFileSystem().getShell().orElseThrow().start();
|
||||
execute(model, selected);
|
||||
|
|
|
@ -79,7 +79,7 @@ public final class OpenFileSystemModel extends BrowserSessionTab<FileSystemStore
|
|||
|
||||
@Override
|
||||
public void init() throws Exception {
|
||||
BooleanScope.execute(busy, () -> {
|
||||
BooleanScope.executeExclusive(busy, () -> {
|
||||
var fs = entry.getStore().createFileSystem();
|
||||
if (fs.getShell().isPresent()) {
|
||||
ProcessControlProvider.get().withDefaultScripts(fs.getShell().get());
|
||||
|
@ -100,7 +100,7 @@ public final class OpenFileSystemModel extends BrowserSessionTab<FileSystemStore
|
|||
|
||||
@Override
|
||||
public void close() {
|
||||
BooleanScope.execute(busy, () -> {
|
||||
BooleanScope.executeExclusive(busy, () -> {
|
||||
if (fileSystem == null) {
|
||||
return;
|
||||
}
|
||||
|
@ -140,7 +140,7 @@ public final class OpenFileSystemModel extends BrowserSessionTab<FileSystemStore
|
|||
return;
|
||||
}
|
||||
|
||||
BooleanScope.execute(busy, () -> {
|
||||
BooleanScope.executeExclusive(busy, () -> {
|
||||
if (entry.getStore() instanceof ShellStore s) {
|
||||
c.accept(fileSystem.getShell().orElseThrow());
|
||||
if (refresh) {
|
||||
|
@ -153,7 +153,7 @@ public final class OpenFileSystemModel extends BrowserSessionTab<FileSystemStore
|
|||
|
||||
@SneakyThrows
|
||||
public void refresh() {
|
||||
BooleanScope.execute(busy, () -> {
|
||||
BooleanScope.executeExclusive(busy, () -> {
|
||||
cdSyncWithoutCheck(currentPath.get());
|
||||
});
|
||||
}
|
||||
|
@ -339,7 +339,7 @@ public final class OpenFileSystemModel extends BrowserSessionTab<FileSystemStore
|
|||
|
||||
public void dropLocalFilesIntoAsync(FileSystem.FileEntry entry, List<Path> files) {
|
||||
ThreadHelper.runFailableAsync(() -> {
|
||||
BooleanScope.execute(busy, () -> {
|
||||
BooleanScope.executeExclusive(busy, () -> {
|
||||
if (fileSystem == null) {
|
||||
return;
|
||||
}
|
||||
|
@ -361,7 +361,7 @@ public final class OpenFileSystemModel extends BrowserSessionTab<FileSystemStore
|
|||
}
|
||||
|
||||
ThreadHelper.runFailableAsync(() -> {
|
||||
BooleanScope.execute(busy, () -> {
|
||||
BooleanScope.executeExclusive(busy, () -> {
|
||||
if (fileSystem == null) {
|
||||
return;
|
||||
}
|
||||
|
@ -384,7 +384,7 @@ public final class OpenFileSystemModel extends BrowserSessionTab<FileSystemStore
|
|||
}
|
||||
|
||||
ThreadHelper.runFailableAsync(() -> {
|
||||
BooleanScope.execute(busy, () -> {
|
||||
BooleanScope.executeExclusive(busy, () -> {
|
||||
if (fileSystem == null) {
|
||||
return;
|
||||
}
|
||||
|
@ -408,7 +408,7 @@ public final class OpenFileSystemModel extends BrowserSessionTab<FileSystemStore
|
|||
}
|
||||
|
||||
ThreadHelper.runFailableAsync(() -> {
|
||||
BooleanScope.execute(busy, () -> {
|
||||
BooleanScope.executeExclusive(busy, () -> {
|
||||
if (fileSystem == null) {
|
||||
return;
|
||||
}
|
||||
|
@ -431,7 +431,7 @@ public final class OpenFileSystemModel extends BrowserSessionTab<FileSystemStore
|
|||
}
|
||||
|
||||
ThreadHelper.runFailableAsync(() -> {
|
||||
BooleanScope.execute(busy, () -> {
|
||||
BooleanScope.executeExclusive(busy, () -> {
|
||||
if (fileSystem == null) {
|
||||
return;
|
||||
}
|
||||
|
@ -466,7 +466,7 @@ public final class OpenFileSystemModel extends BrowserSessionTab<FileSystemStore
|
|||
return;
|
||||
}
|
||||
|
||||
BooleanScope.execute(busy, () -> {
|
||||
BooleanScope.executeExclusive(busy, () -> {
|
||||
if (fileSystem.getShell().isPresent()) {
|
||||
var connection = fileSystem.getShell().get();
|
||||
var name = (directory != null ? directory + " - " : "")
|
||||
|
|
|
@ -1,27 +1,17 @@
|
|||
package io.xpipe.app.util;
|
||||
|
||||
import io.xpipe.app.fxcomps.util.PlatformThread;
|
||||
import io.xpipe.core.util.FailableRunnable;
|
||||
|
||||
import javafx.beans.property.BooleanProperty;
|
||||
|
||||
public class BooleanScope implements AutoCloseable {
|
||||
|
||||
private final BooleanProperty prop;
|
||||
private boolean invert;
|
||||
private boolean forcePlatform;
|
||||
private boolean wait;
|
||||
|
||||
public BooleanScope(BooleanProperty prop) {
|
||||
this.prop = prop;
|
||||
}
|
||||
|
||||
public static <E extends Throwable> void execute(BooleanProperty prop, FailableRunnable<E> r) throws E {
|
||||
try (var ignored = new BooleanScope(prop).start()) {
|
||||
r.run();
|
||||
}
|
||||
}
|
||||
|
||||
public static <E extends Throwable> void executeExclusive(BooleanProperty prop, FailableRunnable<E> r) throws E {
|
||||
try (var ignored = new BooleanScope(prop).exclusive().start()) {
|
||||
r.run();
|
||||
|
@ -33,37 +23,19 @@ public class BooleanScope implements AutoCloseable {
|
|||
return this;
|
||||
}
|
||||
|
||||
public BooleanScope invert() {
|
||||
this.invert = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
public BooleanScope forcePlatform() {
|
||||
this.forcePlatform = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
public BooleanScope start() {
|
||||
public synchronized BooleanScope start() {
|
||||
if (wait) {
|
||||
while (!invert == prop.get()) {
|
||||
while (prop.get()) {
|
||||
ThreadHelper.sleep(50);
|
||||
}
|
||||
}
|
||||
if (forcePlatform) {
|
||||
PlatformThread.runLaterIfNeeded(() -> prop.setValue(!invert));
|
||||
} else {
|
||||
prop.setValue(!invert);
|
||||
}
|
||||
prop.setValue(true);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
if (forcePlatform) {
|
||||
PlatformThread.runLaterIfNeeded(() -> prop.setValue(invert));
|
||||
} else {
|
||||
prop.setValue(invert);
|
||||
}
|
||||
public synchronized void close() {
|
||||
prop.setValue(false);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,16 +7,18 @@ import io.xpipe.app.prefs.AppPrefs;
|
|||
import io.xpipe.core.process.OsType;
|
||||
import io.xpipe.core.util.FailableFunction;
|
||||
import io.xpipe.core.util.FailableSupplier;
|
||||
|
||||
import lombok.Getter;
|
||||
import org.apache.commons.io.FileUtils;
|
||||
|
||||
import java.io.*;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.StandardWatchEventKinds;
|
||||
import java.nio.file.WatchEvent;
|
||||
import java.time.Duration;
|
||||
import java.time.Instant;
|
||||
import java.util.*;
|
||||
import java.util.function.BiConsumer;
|
||||
|
@ -24,6 +26,37 @@ import java.util.function.Consumer;
|
|||
|
||||
public class FileBridge {
|
||||
|
||||
private static class FixedSizeInputStream extends SimpleFilterInputStream {
|
||||
|
||||
private long count;
|
||||
private final long size;
|
||||
|
||||
protected FixedSizeInputStream(InputStream in, long size) {
|
||||
super(in);
|
||||
this.size = size;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int read() throws IOException {
|
||||
if (count >= size) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
var read = in.read();
|
||||
count++;
|
||||
if (read == -1) {
|
||||
return 0;
|
||||
} else {
|
||||
return read;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int available() throws IOException {
|
||||
return (int) (size - count);
|
||||
}
|
||||
}
|
||||
|
||||
private static final Path TEMP = ShellTemp.getLocalTempDataDirectory("bridge");
|
||||
private static FileBridge INSTANCE;
|
||||
private final Set<Entry> openEntries = new HashSet<>();
|
||||
|
@ -95,16 +128,17 @@ public class FileBridge {
|
|||
if (e.hasChanged()) {
|
||||
event("Registering change for file " + TEMP.relativize(e.file) + " for editor entry " + e.getName());
|
||||
e.registerChange();
|
||||
var expectedSize = Files.size(e.file);
|
||||
try (var in = Files.newInputStream(e.file)) {
|
||||
var actualSize = (long) in.available();
|
||||
if (expectedSize != actualSize) {
|
||||
event("Expected file size " + expectedSize + " but got size " + actualSize + ". Ignoring change ...");
|
||||
return;
|
||||
var started = Instant.now();
|
||||
try (var fixedIn = new FixedSizeInputStream(new BufferedInputStream(in), actualSize)) {
|
||||
e.writer.accept(fixedIn, actualSize);
|
||||
}
|
||||
|
||||
e.writer.accept(in, actualSize);
|
||||
var taken = Duration.between(started, Instant.now());
|
||||
event("Wrote " + HumanReadableFormat.byteCount(actualSize) + " in " + taken.toMillis() + "ms");
|
||||
}
|
||||
} else {
|
||||
event("File doesn't seem to be changed");
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
ErrorEvent.fromThrowable(ex).omit().handle();
|
||||
|
@ -134,45 +168,10 @@ public class FileBridge {
|
|||
return Optional.empty();
|
||||
}
|
||||
|
||||
public void openReadOnlyString(String input, Consumer<String> fileConsumer) {
|
||||
if (input == null) {
|
||||
input = "";
|
||||
}
|
||||
|
||||
var id = UUID.randomUUID();
|
||||
String s = input;
|
||||
openIO(
|
||||
id.toString(),
|
||||
id,
|
||||
() -> new ByteArrayInputStream(s.getBytes(StandardCharsets.UTF_8)),
|
||||
null,
|
||||
fileConsumer);
|
||||
}
|
||||
|
||||
public void openString(
|
||||
String keyName, Object key, String input, Consumer<String> output, Consumer<String> fileConsumer) {
|
||||
if (input == null) {
|
||||
input = "";
|
||||
}
|
||||
|
||||
String s = input;
|
||||
openIO(
|
||||
keyName,
|
||||
key,
|
||||
() -> new ByteArrayInputStream(s.getBytes(StandardCharsets.UTF_8)),
|
||||
(size) -> new ByteArrayOutputStream(s.length()) {
|
||||
@Override
|
||||
public void close() throws IOException {
|
||||
super.close();
|
||||
output.accept(new String(toByteArray(), StandardCharsets.UTF_8));
|
||||
}
|
||||
},
|
||||
fileConsumer);
|
||||
}
|
||||
|
||||
public synchronized void openIO(
|
||||
String keyName,
|
||||
Object key,
|
||||
BooleanScope scope,
|
||||
FailableSupplier<InputStream> input,
|
||||
FailableFunction<Long, OutputStream, Exception> output,
|
||||
Consumer<String> consumer) {
|
||||
|
@ -206,12 +205,22 @@ public class FileBridge {
|
|||
return;
|
||||
}
|
||||
|
||||
var entry = new Entry(file, key, keyName, (in, size) -> {
|
||||
var entry = new Entry(file, key, keyName, scope, (in, size) -> {
|
||||
if (output != null) {
|
||||
try (var out = output.apply(size)) {
|
||||
in.transferTo(out);
|
||||
} catch (Exception ex) {
|
||||
ErrorEvent.fromThrowable(ex).handle();
|
||||
if (scope != null) {
|
||||
try (var ignored = scope.start()) {
|
||||
try (var out = output.apply(size)) {
|
||||
in.transferTo(out);
|
||||
} catch (Exception ex) {
|
||||
ErrorEvent.fromThrowable(ex).handle();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
try (var out = output.apply(size)) {
|
||||
in.transferTo(out);
|
||||
} catch (Exception ex) {
|
||||
ErrorEvent.fromThrowable(ex).handle();
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
@ -227,13 +236,15 @@ public class FileBridge {
|
|||
private final Path file;
|
||||
private final Object key;
|
||||
private final String name;
|
||||
private final BooleanScope scope;
|
||||
private final BiConsumer<InputStream, Long> writer;
|
||||
private Instant lastModified;
|
||||
|
||||
public Entry(Path file, Object key, String name, BiConsumer<InputStream, Long> writer) {
|
||||
public Entry(Path file, Object key, String name, BooleanScope scope, BiConsumer<InputStream, Long> writer) {
|
||||
this.file = file;
|
||||
this.key = key;
|
||||
this.name = name;
|
||||
this.scope = scope;
|
||||
this.writer = writer;
|
||||
}
|
||||
|
||||
|
|
|
@ -5,64 +5,20 @@ import io.xpipe.app.prefs.AppPrefs;
|
|||
import io.xpipe.core.process.CommandBuilder;
|
||||
import io.xpipe.core.process.CommandControl;
|
||||
import io.xpipe.core.process.OsType;
|
||||
import io.xpipe.core.store.FileNames;
|
||||
import io.xpipe.core.store.FileSystem;
|
||||
|
||||
import lombok.SneakyThrows;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.FilterInputStream;
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Path;
|
||||
import java.util.UUID;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
public class FileOpener {
|
||||
|
||||
public static void openWithAnyApplication(FileSystem.FileEntry entry) {
|
||||
var file = entry.getPath();
|
||||
var key = entry.getPath().hashCode() + entry.getFileSystem().hashCode();
|
||||
FileBridge.get()
|
||||
.openIO(
|
||||
FileNames.getFileName(file),
|
||||
key,
|
||||
() -> {
|
||||
return entry.getFileSystem().openInput(file);
|
||||
},
|
||||
(size) -> entry.getFileSystem().openOutput(file, size),
|
||||
s -> openWithAnyApplication(s));
|
||||
}
|
||||
|
||||
public static void openInDefaultApplication(FileSystem.FileEntry entry) {
|
||||
var file = entry.getPath();
|
||||
var key = entry.getPath().hashCode() + entry.getFileSystem().hashCode();
|
||||
FileBridge.get()
|
||||
.openIO(
|
||||
FileNames.getFileName(file),
|
||||
key,
|
||||
() -> {
|
||||
return entry.getFileSystem().openInput(file);
|
||||
},
|
||||
(size) -> entry.getFileSystem().openOutput(file, size),
|
||||
s -> openInDefaultApplication(s));
|
||||
}
|
||||
|
||||
public static void openInTextEditor(FileSystem.FileEntry entry) {
|
||||
var editor = AppPrefs.get().externalEditor().getValue();
|
||||
if (editor == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
var file = entry.getPath();
|
||||
var key = entry.getPath().hashCode() + entry.getFileSystem().hashCode();
|
||||
FileBridge.get()
|
||||
.openIO(
|
||||
FileNames.getFileName(file),
|
||||
key,
|
||||
() -> {
|
||||
return entry.getFileSystem().openInput(file);
|
||||
},
|
||||
(size) -> entry.getFileSystem().openOutput(file, size),
|
||||
FileOpener::openInTextEditor);
|
||||
}
|
||||
|
||||
public static void openInTextEditor(String localFile) {
|
||||
var editor = AppPrefs.get().externalEditor().getValue();
|
||||
if (editor == null) {
|
||||
|
@ -119,11 +75,40 @@ public class FileOpener {
|
|||
}
|
||||
|
||||
public static void openReadOnlyString(String input) {
|
||||
FileBridge.get().openReadOnlyString(input, s -> openInTextEditor(s));
|
||||
if (input == null) {
|
||||
input = "";
|
||||
}
|
||||
|
||||
var id = UUID.randomUUID();
|
||||
String s = input;
|
||||
FileBridge.get().openIO(
|
||||
id.toString(),
|
||||
id,
|
||||
null,
|
||||
() -> new ByteArrayInputStream(s.getBytes(StandardCharsets.UTF_8)),
|
||||
null,
|
||||
v -> openInTextEditor(v));
|
||||
}
|
||||
|
||||
public static void openString(String keyName, Object key, String input, Consumer<String> output) {
|
||||
FileBridge.get().openString(keyName, key, input, output, file -> openInTextEditor(file));
|
||||
if (input == null) {
|
||||
input = "";
|
||||
}
|
||||
|
||||
String s = input;
|
||||
FileBridge.get().openIO(
|
||||
keyName,
|
||||
key,
|
||||
null,
|
||||
() -> new ByteArrayInputStream(s.getBytes(StandardCharsets.UTF_8)),
|
||||
(size) -> new ByteArrayOutputStream(s.length()) {
|
||||
@Override
|
||||
public void close() throws IOException {
|
||||
super.close();
|
||||
output.accept(new String(toByteArray(), StandardCharsets.UTF_8));
|
||||
}
|
||||
},
|
||||
file -> openInTextEditor(file));
|
||||
}
|
||||
|
||||
public static void openCommandOutput(String keyName, Object key, CommandControl cc) {
|
||||
|
@ -131,6 +116,7 @@ public class FileOpener {
|
|||
.openIO(
|
||||
keyName,
|
||||
key,
|
||||
null,
|
||||
() -> new FilterInputStream(cc.getStdout()) {
|
||||
@Override
|
||||
@SneakyThrows
|
||||
|
|
|
@ -110,7 +110,7 @@ public class ScanAlert {
|
|||
window.close();
|
||||
});
|
||||
|
||||
BooleanScope.execute(busy, () -> {
|
||||
BooleanScope.executeExclusive(busy, () -> {
|
||||
entry.get().get().setExpanded(true);
|
||||
var copy = new ArrayList<>(selected);
|
||||
for (var a : copy) {
|
||||
|
@ -177,7 +177,7 @@ public class ScanAlert {
|
|||
}
|
||||
|
||||
ThreadHelper.runFailableAsync(() -> {
|
||||
BooleanScope.execute(busy, () -> {
|
||||
BooleanScope.executeExclusive(busy, () -> {
|
||||
if (shellControl != null) {
|
||||
shellControl.close();
|
||||
shellControl = null;
|
||||
|
|
|
@ -0,0 +1,30 @@
|
|||
package io.xpipe.app.util;
|
||||
|
||||
import lombok.NonNull;
|
||||
|
||||
import java.io.FilterInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
||||
public abstract class SimpleFilterInputStream extends FilterInputStream {
|
||||
|
||||
protected SimpleFilterInputStream(InputStream in) {
|
||||
super(in);
|
||||
}
|
||||
|
||||
@Override
|
||||
public abstract int read() throws IOException;
|
||||
|
||||
@Override
|
||||
public int read(byte @NonNull [] b, int off, int len) throws IOException {
|
||||
for (int i = off; i < off + len; i++) {
|
||||
var r = (byte) read();
|
||||
if (r == -1) {
|
||||
return i - off == 0 ? -1 : i - off;
|
||||
}
|
||||
|
||||
b[i] = r;
|
||||
}
|
||||
return len;
|
||||
}
|
||||
}
|
|
@ -1,11 +1,11 @@
|
|||
package io.xpipe.ext.base.browser;
|
||||
|
||||
import io.xpipe.app.browser.BrowserFileOpener;
|
||||
import io.xpipe.app.browser.action.LeafAction;
|
||||
import io.xpipe.app.browser.file.BrowserEntry;
|
||||
import io.xpipe.app.browser.fs.OpenFileSystemModel;
|
||||
import io.xpipe.app.core.AppI18n;
|
||||
import io.xpipe.app.prefs.AppPrefs;
|
||||
import io.xpipe.app.util.FileOpener;
|
||||
import io.xpipe.core.store.FileKind;
|
||||
|
||||
import javafx.beans.value.ObservableValue;
|
||||
|
@ -28,7 +28,7 @@ public class EditFileAction implements LeafAction {
|
|||
@Override
|
||||
public void execute(OpenFileSystemModel model, List<BrowserEntry> entries) {
|
||||
for (BrowserEntry entry : entries) {
|
||||
FileOpener.openInTextEditor(entry.getRawFileEntry());
|
||||
BrowserFileOpener.openInTextEditor(model, entry.getRawFileEntry());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
package io.xpipe.ext.base.browser;
|
||||
|
||||
import io.xpipe.app.browser.BrowserFileOpener;
|
||||
import io.xpipe.app.browser.action.LeafAction;
|
||||
import io.xpipe.app.browser.file.BrowserEntry;
|
||||
import io.xpipe.app.browser.fs.OpenFileSystemModel;
|
||||
import io.xpipe.app.core.AppI18n;
|
||||
import io.xpipe.app.util.FileOpener;
|
||||
import io.xpipe.core.store.FileKind;
|
||||
|
||||
import javafx.beans.value.ObservableValue;
|
||||
|
@ -22,7 +22,7 @@ public class OpenFileDefaultAction implements LeafAction {
|
|||
@Override
|
||||
public void execute(OpenFileSystemModel model, List<BrowserEntry> entries) {
|
||||
for (var entry : entries) {
|
||||
FileOpener.openInDefaultApplication(entry.getRawFileEntry());
|
||||
BrowserFileOpener.openInDefaultApplication(model, entry.getRawFileEntry());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
package io.xpipe.ext.base.browser;
|
||||
|
||||
import io.xpipe.app.browser.BrowserFileOpener;
|
||||
import io.xpipe.app.browser.action.LeafAction;
|
||||
import io.xpipe.app.browser.file.BrowserEntry;
|
||||
import io.xpipe.app.browser.fs.OpenFileSystemModel;
|
||||
import io.xpipe.app.core.AppI18n;
|
||||
import io.xpipe.app.util.FileOpener;
|
||||
import io.xpipe.core.process.OsType;
|
||||
import io.xpipe.core.store.FileKind;
|
||||
|
||||
|
@ -23,7 +23,7 @@ public class OpenFileWithAction implements LeafAction {
|
|||
@Override
|
||||
public void execute(OpenFileSystemModel model, List<BrowserEntry> entries) {
|
||||
var e = entries.getFirst();
|
||||
FileOpener.openWithAnyApplication(e.getRawFileEntry());
|
||||
BrowserFileOpener.openWithAnyApplication(model, e.getRawFileEntry());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
Loading…
Reference in a new issue