mirror of
https://github.com/xpipe-io/xpipe.git
synced 2024-11-25 09:00:26 +00:00
More browser fixes
This commit is contained in:
parent
7ca4d64e2d
commit
305f8d69e8
14 changed files with 150 additions and 100 deletions
|
@ -1,8 +1,6 @@
|
|||
package io.xpipe.app.browser;
|
||||
|
||||
import io.xpipe.app.util.ThreadHelper;
|
||||
import io.xpipe.core.store.DataStore;
|
||||
import io.xpipe.core.store.FileSystem;
|
||||
import io.xpipe.core.store.ShellStore;
|
||||
import javafx.beans.property.Property;
|
||||
import javafx.beans.property.SimpleObjectProperty;
|
||||
|
@ -18,20 +16,6 @@ public class BrowserModel {
|
|||
private final ObservableList<OpenFileSystemModel> openFileSystems = FXCollections.observableArrayList();
|
||||
private final Property<OpenFileSystemModel> selected = new SimpleObjectProperty<>();
|
||||
|
||||
public OpenFileSystemModel getOpenModelFor(DataStore store) {
|
||||
return openFileSystems.stream()
|
||||
.filter(model -> model.getStore().equals(store))
|
||||
.findFirst()
|
||||
.orElseThrow();
|
||||
}
|
||||
|
||||
public OpenFileSystemModel getOpenModelFor(FileSystem fileSystem) {
|
||||
return openFileSystems.stream()
|
||||
.filter(model -> model.getFileSystem().equals(fileSystem))
|
||||
.findFirst()
|
||||
.orElseThrow();
|
||||
}
|
||||
|
||||
public void closeFileSystem(OpenFileSystemModel open) {
|
||||
ThreadHelper.runAsync(() -> {
|
||||
open.closeSync();
|
||||
|
@ -41,7 +25,7 @@ public class BrowserModel {
|
|||
|
||||
public void openFileSystem(ShellStore store) {
|
||||
var found = openFileSystems.stream()
|
||||
.filter(fileSystemModel -> fileSystemModel.getStore().equals(store))
|
||||
.filter(fileSystemModel -> fileSystemModel.getStore().getValue().equals(store))
|
||||
.findFirst();
|
||||
if (found.isPresent()) {
|
||||
selected.setValue(found.get());
|
||||
|
|
|
@ -2,10 +2,7 @@
|
|||
|
||||
package io.xpipe.app.browser;
|
||||
|
||||
import io.xpipe.app.util.ExternalEditor;
|
||||
import io.xpipe.app.util.ScriptHelper;
|
||||
import io.xpipe.app.util.TerminalHelper;
|
||||
import io.xpipe.app.util.ThreadHelper;
|
||||
import io.xpipe.app.util.*;
|
||||
import io.xpipe.core.process.OsType;
|
||||
import io.xpipe.core.process.ShellProcessControl;
|
||||
import io.xpipe.core.store.FileSystem;
|
||||
|
@ -21,11 +18,15 @@ import java.util.List;
|
|||
|
||||
final class FileContextMenu extends ContextMenu {
|
||||
|
||||
public boolean isScript(FileSystem.FileEntry e) {
|
||||
public boolean isExecutable(FileSystem.FileEntry e) {
|
||||
if (e.isDirectory()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (e.getExecutable() != null && e.getExecutable()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
var shell = e.getFileSystem().getShell();
|
||||
if (shell.isEmpty()) {
|
||||
return false;
|
||||
|
@ -33,7 +34,7 @@ final class FileContextMenu extends ContextMenu {
|
|||
|
||||
var os = shell.get().getOsType();
|
||||
var ending = FilenameUtils.getExtension(e.getPath()).toLowerCase();
|
||||
if (os.equals(OsType.WINDOWS) && List.of("bat", "ps1", "cmd").contains(ending)) {
|
||||
if (os.equals(OsType.WINDOWS) && List.of("exe", "bat", "ps1", "cmd").contains(ending)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -65,7 +66,7 @@ final class FileContextMenu extends ContextMenu {
|
|||
});
|
||||
getItems().add(terminal);
|
||||
} else {
|
||||
if (isScript(entry)) {
|
||||
if (isExecutable(entry)) {
|
||||
var execute = new MenuItem("Run in terminal");
|
||||
execute.setOnAction(event -> {
|
||||
ThreadHelper.runFailableAsync(() -> {
|
||||
|
@ -91,23 +92,21 @@ final class FileContextMenu extends ContextMenu {
|
|||
event.consume();
|
||||
});
|
||||
getItems().add(executeInBackground);
|
||||
}
|
||||
|
||||
var open = new MenuItem("Open default");
|
||||
open.setOnAction(event -> {
|
||||
ThreadHelper.runFailableAsync(() -> {
|
||||
ShellProcessControl pc = model.getFileSystem().getShell().orElseThrow();
|
||||
var cmd = "\"" + entry.getPath() + "\"";
|
||||
pc.executeBooleanSimpleCommand(cmd);
|
||||
} else {
|
||||
var open = new MenuItem("Open default");
|
||||
open.setOnAction(event -> {
|
||||
ThreadHelper.runFailableAsync(() -> {
|
||||
FileOpener.openInDefaultApplication(entry);
|
||||
});
|
||||
event.consume();
|
||||
});
|
||||
event.consume();
|
||||
});
|
||||
getItems().add(open);
|
||||
getItems().add(open);
|
||||
}
|
||||
|
||||
var edit = new MenuItem("Edit");
|
||||
edit.setOnAction(event -> {
|
||||
FileOpener.openInTextEditor(entry);
|
||||
event.consume();
|
||||
ExternalEditor.get().openInEditor(model.getFileSystem(), entry.getPath());
|
||||
});
|
||||
getItems().add(edit);
|
||||
}
|
||||
|
|
|
@ -7,7 +7,6 @@ import atlantafx.base.theme.Tweaks;
|
|||
import io.xpipe.app.comp.base.LazyTextFieldComp;
|
||||
import io.xpipe.app.core.AppResources;
|
||||
import io.xpipe.app.fxcomps.impl.PrettyImageComp;
|
||||
import io.xpipe.app.fxcomps.util.BindingsHelper;
|
||||
import io.xpipe.app.fxcomps.util.SimpleChangeListener;
|
||||
import io.xpipe.app.util.Containers;
|
||||
import io.xpipe.app.util.HumanReadableFormat;
|
||||
|
@ -235,7 +234,11 @@ final class FileListComp extends AnchorPane {
|
|||
});
|
||||
|
||||
fileList.getShown().addListener((observable, oldValue, newValue) -> {
|
||||
BindingsHelper.setContent(table.getItems(), newValue);
|
||||
table.getItems().setAll(newValue);
|
||||
|
||||
if (newValue.size() > 0) {
|
||||
table.scrollTo(0);
|
||||
}
|
||||
});
|
||||
|
||||
return table;
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
package io.xpipe.app.browser;
|
||||
|
||||
import io.xpipe.app.issue.ErrorEvent;
|
||||
import io.xpipe.app.util.ExternalEditor;
|
||||
import io.xpipe.app.util.FileOpener;
|
||||
import io.xpipe.core.impl.FileNames;
|
||||
import io.xpipe.core.store.FileSystem;
|
||||
import javafx.beans.property.ObjectProperty;
|
||||
|
@ -73,7 +73,7 @@ final class FileListModel {
|
|||
if (entry.isDirectory()) {
|
||||
model.navigate(entry.getPath(), true);
|
||||
} else {
|
||||
ExternalEditor.get().openInEditor(entry.getFileSystem(), entry.getPath());
|
||||
FileOpener.openInTextEditor(entry);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -54,6 +54,7 @@ public class FileSystemHelper {
|
|||
Files.getLastModifiedTime(file).toInstant(),
|
||||
Files.isDirectory(file),
|
||||
Files.isHidden(file),
|
||||
Files.isExecutable(file),
|
||||
Files.size(file));
|
||||
}
|
||||
|
||||
|
|
|
@ -45,7 +45,7 @@ final class OpenFileSystemModel {
|
|||
}
|
||||
|
||||
public FileSystem.FileEntry getCurrentDirectory() {
|
||||
return new FileSystem.FileEntry(fileSystem, currentPath.get(), Instant.now(), true, false, 0);
|
||||
return new FileSystem.FileEntry(fileSystem, currentPath.get(), Instant.now(), true, false, false, 0);
|
||||
}
|
||||
|
||||
public void cd(String path) {
|
||||
|
@ -75,7 +75,7 @@ final class OpenFileSystemModel {
|
|||
newList = getFileSystem().listFiles(dir).collect(Collectors.toCollection(ArrayList::new));
|
||||
} else {
|
||||
newList = getFileSystem().listRoots().stream()
|
||||
.map(s -> new FileSystem.FileEntry(getFileSystem(), s, Instant.now(), true, false, 0))
|
||||
.map(s -> new FileSystem.FileEntry(getFileSystem(), s, Instant.now(), true, false, false, 0))
|
||||
.collect(Collectors.toCollection(ArrayList::new));
|
||||
}
|
||||
fileList.setAll(newList);
|
||||
|
@ -180,7 +180,9 @@ final class OpenFileSystemModel {
|
|||
|
||||
public void switchAsync(FileSystemStore fileSystem) {
|
||||
ThreadHelper.runFailableAsync(() -> {
|
||||
switchSync(fileSystem);
|
||||
BusyProperty.execute(busy, () -> {
|
||||
switchSync(fileSystem);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -8,7 +8,7 @@ import io.xpipe.app.issue.ErrorEvent;
|
|||
import io.xpipe.app.issue.UserReportComp;
|
||||
import io.xpipe.app.util.DesktopHelper;
|
||||
import io.xpipe.app.util.DynamicOptionsBuilder;
|
||||
import io.xpipe.app.util.ExternalEditor;
|
||||
import io.xpipe.app.util.FileOpener;
|
||||
import io.xpipe.core.util.XPipeInstallation;
|
||||
import javafx.scene.layout.Region;
|
||||
|
||||
|
@ -30,8 +30,7 @@ public class BrowseDirectoryComp extends SimpleComp {
|
|||
.addComp(
|
||||
"logFile",
|
||||
new ButtonComp(AppI18n.observable("openCurrentLogFile"), () -> {
|
||||
ExternalEditor.get()
|
||||
.openInEditor(AppLogs.get()
|
||||
FileOpener.openInTextEditor(AppLogs.get()
|
||||
.getSessionLogsDirectory()
|
||||
.resolve("xpipe.log")
|
||||
.toString());
|
||||
|
|
|
@ -4,7 +4,7 @@ import io.xpipe.app.fxcomps.Comp;
|
|||
import io.xpipe.app.fxcomps.SimpleComp;
|
||||
import io.xpipe.app.fxcomps.impl.IconButtonComp;
|
||||
import io.xpipe.app.fxcomps.impl.TextAreaComp;
|
||||
import io.xpipe.app.util.ExternalEditor;
|
||||
import io.xpipe.app.util.FileOpener;
|
||||
import javafx.application.Platform;
|
||||
import javafx.beans.property.Property;
|
||||
import javafx.scene.layout.AnchorPane;
|
||||
|
@ -47,8 +47,8 @@ public class IntegratedTextAreaComp extends SimpleComp {
|
|||
}
|
||||
|
||||
private Region createOpenButton(Region container) {
|
||||
var button = new IconButtonComp("mdal-edit", () -> ExternalEditor.get()
|
||||
.startEditing(identifier, fileType, this, value.getValue(), (s) -> {
|
||||
var button = new IconButtonComp("mdal-edit", () -> FileOpener
|
||||
.openString(identifier, fileType, this, value.getValue(), (s) -> {
|
||||
Platform.runLater(() -> value.setValue(s));
|
||||
}))
|
||||
.createRegion();
|
||||
|
|
|
@ -9,7 +9,7 @@ import io.xpipe.app.issue.TrackEvent;
|
|||
import io.xpipe.app.prefs.AppPrefs;
|
||||
import io.xpipe.app.storage.DataStorage;
|
||||
import io.xpipe.app.update.AppUpdater;
|
||||
import io.xpipe.app.util.ExternalEditor;
|
||||
import io.xpipe.app.util.FileBridge;
|
||||
import io.xpipe.core.util.JacksonMapper;
|
||||
|
||||
public class BaseMode extends OperationMode {
|
||||
|
@ -40,7 +40,7 @@ public class BaseMode extends OperationMode {
|
|||
AppCharsetter.init();
|
||||
DataStorage.init();
|
||||
FileWatchManager.init();
|
||||
ExternalEditor.init();
|
||||
FileBridge.init();
|
||||
AppSocketServer.init();
|
||||
AppUpdater.init();
|
||||
TrackEvent.info("mode", "Finished base components initialization");
|
||||
|
|
|
@ -4,11 +4,8 @@ import io.xpipe.app.core.FileWatchManager;
|
|||
import io.xpipe.app.issue.ErrorEvent;
|
||||
import io.xpipe.app.issue.TrackEvent;
|
||||
import io.xpipe.app.prefs.AppPrefs;
|
||||
import io.xpipe.core.impl.FileNames;
|
||||
import io.xpipe.core.store.FileSystem;
|
||||
import lombok.Getter;
|
||||
import org.apache.commons.io.FileUtils;
|
||||
import org.apache.commons.io.FilenameUtils;
|
||||
import org.apache.commons.lang3.function.FailableSupplier;
|
||||
|
||||
import java.io.*;
|
||||
|
@ -24,14 +21,14 @@ import java.util.UUID;
|
|||
import java.util.concurrent.CopyOnWriteArraySet;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
public class ExternalEditor {
|
||||
public class FileBridge {
|
||||
|
||||
private static final Path TEMP =
|
||||
FileUtils.getTempDirectory().toPath().resolve("xpipe").resolve("editor");
|
||||
private static ExternalEditor INSTANCE;
|
||||
FileUtils.getTempDirectory().toPath().resolve("xpipe").resolve("bridge");
|
||||
private static FileBridge INSTANCE;
|
||||
private final Set<Entry> openEntries = new CopyOnWriteArraySet<>();
|
||||
|
||||
public static ExternalEditor get() {
|
||||
public static FileBridge get() {
|
||||
return INSTANCE;
|
||||
}
|
||||
|
||||
|
@ -44,7 +41,7 @@ public class ExternalEditor {
|
|||
}
|
||||
|
||||
public static void init() {
|
||||
INSTANCE = new ExternalEditor();
|
||||
INSTANCE = new FileBridge();
|
||||
try {
|
||||
FileUtils.forceMkdir(TEMP.toFile());
|
||||
|
||||
|
@ -124,13 +121,13 @@ public class ExternalEditor {
|
|||
return Optional.empty();
|
||||
}
|
||||
|
||||
public void startEditing(String keyName, String fileType, Object key, String input, Consumer<String> output) {
|
||||
public void openString(String keyName, String fileType, Object key, String input, Consumer<String> output, Consumer<String> consumer) {
|
||||
if (input == null) {
|
||||
input = "";
|
||||
}
|
||||
|
||||
String s = input;
|
||||
startEditing(
|
||||
openIO(
|
||||
keyName,
|
||||
fileType,
|
||||
key,
|
||||
|
@ -141,18 +138,20 @@ public class ExternalEditor {
|
|||
super.close();
|
||||
output.accept(new String(toByteArray(), StandardCharsets.UTF_8));
|
||||
}
|
||||
});
|
||||
},
|
||||
consumer);
|
||||
}
|
||||
|
||||
public void startEditing(
|
||||
public void openIO(
|
||||
String keyName,
|
||||
String fileType,
|
||||
Object key,
|
||||
FailableSupplier<InputStream, Exception> input,
|
||||
FailableSupplier<OutputStream, Exception> output) {
|
||||
FailableSupplier<OutputStream, Exception> output,
|
||||
Consumer<String> consumer) {
|
||||
var ext = getForKey(key);
|
||||
if (ext.isPresent()) {
|
||||
openInEditor(ext.get().file.toString());
|
||||
consumer.accept(ext.get().file.toString());
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -181,31 +180,7 @@ public class ExternalEditor {
|
|||
openEntries.add(entry);
|
||||
|
||||
ext = getForKey(key);
|
||||
openInEditor(ext.orElseThrow().file.toString());
|
||||
}
|
||||
|
||||
public void openInEditor(FileSystem fileSystem, String file) {
|
||||
var editor = AppPrefs.get().externalEditor().getValue();
|
||||
if (editor == null || !editor.isSelectable()) {
|
||||
return;
|
||||
}
|
||||
|
||||
startEditing(FileNames.getFileName(file), FilenameUtils.getExtension(file), file, () -> {
|
||||
return fileSystem.openInput(file);
|
||||
}, () -> fileSystem.openOutput(file));
|
||||
}
|
||||
|
||||
public void openInEditor(String file) {
|
||||
var editor = AppPrefs.get().externalEditor().getValue();
|
||||
if (editor == null || !editor.isSelectable()) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
editor.launch(Path.of(file).toRealPath());
|
||||
} catch (Exception e) {
|
||||
ErrorEvent.fromThrowable(e).handle();
|
||||
}
|
||||
consumer.accept(ext.orElseThrow().file.toString());
|
||||
}
|
||||
|
||||
@Getter
|
84
app/src/main/java/io/xpipe/app/util/FileOpener.java
Normal file
84
app/src/main/java/io/xpipe/app/util/FileOpener.java
Normal file
|
@ -0,0 +1,84 @@
|
|||
package io.xpipe.app.util;
|
||||
|
||||
import io.xpipe.app.issue.ErrorEvent;
|
||||
import io.xpipe.app.prefs.AppPrefs;
|
||||
import io.xpipe.core.impl.FileNames;
|
||||
import io.xpipe.core.process.OsType;
|
||||
import io.xpipe.core.store.FileSystem;
|
||||
import io.xpipe.core.store.ShellStore;
|
||||
import org.apache.commons.io.FilenameUtils;
|
||||
|
||||
import java.nio.file.Path;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
public class FileOpener {
|
||||
|
||||
public static void openInDefaultApplication(FileSystem.FileEntry entry) {
|
||||
var editor = AppPrefs.get().externalEditor().getValue();
|
||||
if (editor == null || !editor.isSelectable()) {
|
||||
return;
|
||||
}
|
||||
|
||||
var file = entry.getPath();
|
||||
FileBridge.get()
|
||||
.openIO(
|
||||
FileNames.getFileName(file),
|
||||
FilenameUtils.getExtension(file),
|
||||
file,
|
||||
() -> {
|
||||
return entry.getFileSystem().openInput(file);
|
||||
},
|
||||
() -> entry.getFileSystem().openOutput(file),
|
||||
s -> openInDefaultApplication(s));
|
||||
}
|
||||
|
||||
public static void openInTextEditor(FileSystem.FileEntry entry) {
|
||||
var editor = AppPrefs.get().externalEditor().getValue();
|
||||
if (editor == null || !editor.isSelectable()) {
|
||||
return;
|
||||
}
|
||||
|
||||
var file = entry.getPath();
|
||||
FileBridge.get()
|
||||
.openIO(
|
||||
FileNames.getFileName(file),
|
||||
FilenameUtils.getExtension(file),
|
||||
file,
|
||||
() -> {
|
||||
return entry.getFileSystem().openInput(file);
|
||||
},
|
||||
() -> entry.getFileSystem().openOutput(file),
|
||||
FileOpener::openInTextEditor);
|
||||
}
|
||||
|
||||
public static void openInTextEditor(String file) {
|
||||
var editor = AppPrefs.get().externalEditor().getValue();
|
||||
if (editor == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
editor.launch(Path.of(file).toRealPath());
|
||||
} catch (Exception e) {
|
||||
ErrorEvent.fromThrowable(e).handle();
|
||||
}
|
||||
}
|
||||
|
||||
public static void openInDefaultApplication(String file) {
|
||||
try (var pc = ShellStore.local().create().start()) {
|
||||
if (pc.getOsType().equals(OsType.WINDOWS)) {
|
||||
pc.executeSimpleCommand("\"" + file + "\"");
|
||||
} else if (pc.getOsType().equals(OsType.LINUX)) {
|
||||
pc.executeSimpleCommand("xdg-open \"" + file + "\"");
|
||||
} else {
|
||||
pc.executeSimpleCommand("open \"" + file + "\"");
|
||||
}
|
||||
} catch (Exception e) {
|
||||
ErrorEvent.fromThrowable(e).handle();
|
||||
}
|
||||
}
|
||||
|
||||
public static void openString(String keyName, String fileType, Object key, String input, Consumer<String> output) {
|
||||
FileBridge.get().openString(keyName, fileType, key, input, output, file -> openInTextEditor(file));
|
||||
}
|
||||
}
|
|
@ -15,6 +15,16 @@ import java.util.Random;
|
|||
|
||||
public class ScriptHelper {
|
||||
|
||||
public static String createDefaultOpenCommand(ShellProcessControl pc, String file) {
|
||||
if (pc.getOsType().equals(OsType.WINDOWS)) {
|
||||
return "\"" + file + "\"";
|
||||
} else if (pc.getOsType().equals(OsType.LINUX)){
|
||||
return "xdg-open \"" + file + "\"";
|
||||
} else {
|
||||
return "open \"" + file + "\"";
|
||||
}
|
||||
}
|
||||
|
||||
public static String createDetachCommand(ShellProcessControl pc, String command) {
|
||||
if (pc.getOsType().equals(OsType.WINDOWS)) {
|
||||
return "start \"\" " + command;
|
||||
|
|
|
@ -24,6 +24,7 @@ public interface FileSystem extends Closeable, AutoCloseable {
|
|||
Instant date;
|
||||
boolean directory;
|
||||
boolean hidden;
|
||||
Boolean executable;
|
||||
long size;
|
||||
}
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@ package io.xpipe.ext.base.actions;
|
|||
|
||||
import io.xpipe.app.core.AppI18n;
|
||||
import io.xpipe.app.ext.ActionProvider;
|
||||
import io.xpipe.app.util.ExternalEditor;
|
||||
import io.xpipe.app.util.FileOpener;
|
||||
import io.xpipe.core.impl.FileStore;
|
||||
import io.xpipe.core.impl.LocalStore;
|
||||
import io.xpipe.core.store.DataFlow;
|
||||
|
@ -24,15 +24,7 @@ public class FileEditAction implements ActionProvider {
|
|||
@Override
|
||||
public void execute() throws Exception {
|
||||
if (store.getFileSystem().equals(new LocalStore())) {
|
||||
ExternalEditor.get().openInEditor(store.getFile());
|
||||
} else {
|
||||
ExternalEditor.get()
|
||||
.startEditing(
|
||||
store.getFileName(),
|
||||
store.getFileExtension(),
|
||||
store,
|
||||
() -> store.openInput(),
|
||||
() -> store.openOutput());
|
||||
FileOpener.openInTextEditor(store.getFile());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue