More browser fixes

This commit is contained in:
crschnick 2023-02-22 14:14:01 +00:00
parent 7ca4d64e2d
commit 305f8d69e8
14 changed files with 150 additions and 100 deletions

View file

@ -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());

View file

@ -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);
}

View file

@ -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;

View file

@ -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);
}
}

View file

@ -54,6 +54,7 @@ public class FileSystemHelper {
Files.getLastModifiedTime(file).toInstant(),
Files.isDirectory(file),
Files.isHidden(file),
Files.isExecutable(file),
Files.size(file));
}

View 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);
});
});
}

View file

@ -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());

View file

@ -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();

View file

@ -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");

View file

@ -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

View 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));
}
}

View 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;

View file

@ -24,6 +24,7 @@ public interface FileSystem extends Closeable, AutoCloseable {
Instant date;
boolean directory;
boolean hidden;
Boolean executable;
long size;
}

View file

@ -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());
}
}
}