mirror of
https://github.com/xpipe-io/xpipe.git
synced 2024-11-25 09:00:26 +00:00
Various fixes [stage]
This commit is contained in:
parent
52cdcfa0aa
commit
daa011ffe6
24 changed files with 380 additions and 92 deletions
|
@ -2,6 +2,7 @@ package io.xpipe.app.browser;
|
|||
|
||||
import io.xpipe.app.browser.icon.BrowserIcons;
|
||||
import io.xpipe.app.comp.base.ListBoxViewComp;
|
||||
import io.xpipe.app.comp.base.VBoxViewComp;
|
||||
import io.xpipe.app.fxcomps.Comp;
|
||||
import io.xpipe.app.fxcomps.SimpleComp;
|
||||
import io.xpipe.app.fxcomps.augment.GrowAugment;
|
||||
|
@ -13,16 +14,19 @@ import javafx.scene.layout.Region;
|
|||
import lombok.EqualsAndHashCode;
|
||||
import lombok.Value;
|
||||
|
||||
import java.util.function.Function;
|
||||
|
||||
@Value
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
public class BrowserFileOverviewComp extends SimpleComp {
|
||||
|
||||
OpenFileSystemModel model;
|
||||
ObservableList<FileSystem.FileEntry> list;
|
||||
boolean grow;
|
||||
|
||||
@Override
|
||||
protected Region createSimple() {
|
||||
var c = new ListBoxViewComp<>(list, list, entry -> {
|
||||
Function<FileSystem.FileEntry, Comp<?>> factory = entry -> {
|
||||
return Comp.of(() -> {
|
||||
var icon = BrowserIcons.createIcon(entry);
|
||||
var l = new Button(entry.getPath(), icon.createRegion());
|
||||
|
@ -34,8 +38,14 @@ public class BrowserFileOverviewComp extends SimpleComp {
|
|||
GrowAugment.create(true,false).augment(l);
|
||||
return l;
|
||||
});
|
||||
})
|
||||
.styleClass("overview-file-list");
|
||||
return c.createRegion();
|
||||
};
|
||||
|
||||
if (grow) {
|
||||
var c = new ListBoxViewComp<>(list, list, factory).styleClass("overview-file-list");
|
||||
return c.createRegion();
|
||||
} else {
|
||||
var c = new VBoxViewComp<>(list, list, factory).styleClass("overview-file-list");
|
||||
return c.createRegion();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,6 +18,9 @@ import javafx.css.PseudoClass;
|
|||
import javafx.geometry.Insets;
|
||||
import javafx.geometry.Pos;
|
||||
import javafx.scene.control.Button;
|
||||
import javafx.scene.input.KeyCode;
|
||||
import javafx.scene.input.KeyCodeCombination;
|
||||
import javafx.scene.input.KeyCombination;
|
||||
import javafx.scene.input.MouseButton;
|
||||
import javafx.scene.layout.Region;
|
||||
|
||||
|
@ -67,6 +70,8 @@ public class BrowserNavBar extends SimpleComp {
|
|||
});
|
||||
|
||||
struc.get().setPromptText("Overview of " + model.getName());
|
||||
}).shortcut(new KeyCodeCombination(KeyCode.F, KeyCombination.SHORTCUT_DOWN), s -> {
|
||||
s.get().requestFocus();
|
||||
});
|
||||
|
||||
var graphic = Bindings.createStringBinding(
|
||||
|
|
|
@ -5,10 +5,13 @@ import io.xpipe.app.core.AppI18n;
|
|||
import io.xpipe.app.fxcomps.SimpleComp;
|
||||
import io.xpipe.app.fxcomps.impl.VerticalComp;
|
||||
import io.xpipe.app.fxcomps.util.BindingsHelper;
|
||||
import io.xpipe.app.issue.ErrorEvent;
|
||||
import io.xpipe.core.process.ShellControl;
|
||||
import io.xpipe.core.store.FileSystem;
|
||||
import javafx.collections.FXCollections;
|
||||
import javafx.scene.layout.Priority;
|
||||
import javafx.scene.layout.Region;
|
||||
import javafx.scene.layout.VBox;
|
||||
import lombok.SneakyThrows;
|
||||
|
||||
import java.util.List;
|
||||
|
@ -25,18 +28,34 @@ public class BrowserOverviewComp extends SimpleComp {
|
|||
@SneakyThrows
|
||||
protected Region createSimple() {
|
||||
ShellControl sc = model.getFileSystem().getShell().orElseThrow();
|
||||
var common = sc.getOsType().determineInterestingPaths(sc).stream().map(s -> FileSystem.FileEntry.ofDirectory(model.getFileSystem(), s)).toList();
|
||||
var commonOverview = new BrowserFileOverviewComp(model, FXCollections.observableArrayList(common));
|
||||
var commonPane = new SimpleTitledPaneComp(AppI18n.observable("common"), commonOverview);
|
||||
// TODO: May be move this into another thread
|
||||
var common = sc.getOsType().determineInterestingPaths(sc).stream()
|
||||
.map(s -> FileSystem.FileEntry.ofDirectory(model.getFileSystem(), s))
|
||||
.filter(entry -> {
|
||||
try {
|
||||
var b = sc.getShellDialect().directoryExists(sc, entry.getPath()).executeAndCheck();
|
||||
return b;
|
||||
} catch (Exception e) {
|
||||
ErrorEvent.fromThrowable(e).handle();
|
||||
return false;
|
||||
}
|
||||
})
|
||||
.toList();
|
||||
var commonOverview = new BrowserFileOverviewComp(model, FXCollections.observableArrayList(common), false);
|
||||
var commonPane = new SimpleTitledPaneComp(AppI18n.observable("common"), commonOverview).apply(struc -> VBox.setVgrow(struc.get(), Priority.NEVER));
|
||||
|
||||
var roots = sc.getShellDialect().listRoots(sc).map(s -> FileSystem.FileEntry.ofDirectory(model.getFileSystem(), s)).toList();
|
||||
var rootsOverview = new BrowserFileOverviewComp(model, FXCollections.observableArrayList(roots));
|
||||
var roots = sc.getShellDialect()
|
||||
.listRoots(sc)
|
||||
.map(s -> FileSystem.FileEntry.ofDirectory(model.getFileSystem(), s))
|
||||
.toList();
|
||||
var rootsOverview = new BrowserFileOverviewComp(model, FXCollections.observableArrayList(roots), false);
|
||||
var rootsPane = new SimpleTitledPaneComp(AppI18n.observable("roots"), rootsOverview);
|
||||
|
||||
|
||||
var recent = BindingsHelper.mappedContentBinding(model.getSavedState().getRecentDirectories(), s -> FileSystem.FileEntry.ofDirectory(model.getFileSystem(), s.getDirectory()));
|
||||
var recentOverview = new BrowserFileOverviewComp(model, recent);
|
||||
var recentPane = new SimpleTitledPaneComp(AppI18n.observable("recent"), recentOverview).vgrow();
|
||||
var recent = BindingsHelper.mappedContentBinding(
|
||||
model.getSavedState().getRecentDirectories(),
|
||||
s -> FileSystem.FileEntry.ofDirectory(model.getFileSystem(), s.getDirectory()));
|
||||
var recentOverview = new BrowserFileOverviewComp(model, recent, true);
|
||||
var recentPane = new SimpleTitledPaneComp(AppI18n.observable("recent"), recentOverview);
|
||||
|
||||
var vbox = new VerticalComp(List.of(commonPane, rootsPane, recentPane)).styleClass("overview");
|
||||
return vbox.createRegion();
|
||||
|
|
|
@ -46,23 +46,10 @@ public class OpenFileSystemComp extends SimpleComp {
|
|||
overview.setOnAction(e -> model.cd(null));
|
||||
overview.disableProperty().bind(model.getInOverview());
|
||||
|
||||
var backBtn = new Button(null, new FontIcon("fth-arrow-left"));
|
||||
backBtn.setOnAction(e -> model.back());
|
||||
backBtn.disableProperty().bind(model.getHistory().canGoBackProperty().not());
|
||||
|
||||
var forthBtn = new Button(null, new FontIcon("fth-arrow-right"));
|
||||
forthBtn.setOnAction(e -> model.forth());
|
||||
forthBtn.disableProperty().bind(model.getHistory().canGoForthProperty().not());
|
||||
|
||||
var refreshBtn = new Button(null, new FontIcon("mdmz-refresh"));
|
||||
refreshBtn.setOnAction(e -> model.refresh());
|
||||
Shortcuts.addShortcut(refreshBtn, new KeyCodeCombination(KeyCode.F5));
|
||||
refreshBtn.disableProperty().bind(model.getInOverview());
|
||||
|
||||
var backBtn = BrowserAction.byId("back").toButton(model, List.of());
|
||||
var forthBtn = BrowserAction.byId("forward").toButton(model, List.of());
|
||||
var refreshBtn = BrowserAction.byId("refresh").toButton(model, List.of());
|
||||
var terminalBtn = BrowserAction.byId("openTerminal").toButton(model, List.of());
|
||||
terminalBtn.setOnAction(
|
||||
e -> model.openTerminalAsync(model.getCurrentPath().get()));
|
||||
terminalBtn.disableProperty().bind(model.getInOverview());
|
||||
|
||||
var menuButton = new MenuButton(null, new FontIcon("mdral-folder_open"));
|
||||
new ContextMenuAugment<>(
|
||||
|
|
|
@ -9,7 +9,7 @@ import java.util.ArrayList;
|
|||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
final class OpenFileSystemHistory {
|
||||
public final class OpenFileSystemHistory {
|
||||
|
||||
private final IntegerProperty cursor = new SimpleIntegerProperty(-1);
|
||||
private final List<String> history = new ArrayList<>();
|
||||
|
|
|
@ -22,7 +22,6 @@ import org.apache.commons.lang3.function.FailableConsumer;
|
|||
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Path;
|
||||
import java.time.Instant;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
|
@ -54,7 +53,6 @@ public final class OpenFileSystemModel {
|
|||
return currentPath.get() == null;
|
||||
}, currentPath));
|
||||
fileList = new BrowserFileListModel(this);
|
||||
addListeners();
|
||||
}
|
||||
|
||||
public void withShell(FailableConsumer<ShellControl, Exception> c, boolean refresh) {
|
||||
|
@ -74,17 +72,6 @@ public final class OpenFileSystemModel {
|
|||
});
|
||||
}
|
||||
|
||||
private void addListeners() {
|
||||
// savedState.addListener((observable, oldValue, newValue) -> {
|
||||
// if (store == null) {
|
||||
// return;
|
||||
// }
|
||||
//
|
||||
// var storageEntry = DataStorage.get().getStoreEntryIfPresent(store);
|
||||
// storageEntry.ifPresent(entry -> AppCache.update("browser-state-" + entry.getUuid(), newValue));
|
||||
// });
|
||||
}
|
||||
|
||||
@SneakyThrows
|
||||
public void refresh() {
|
||||
BusyProperty.execute(busy, () -> {
|
||||
|
@ -194,9 +181,9 @@ public final class OpenFileSystemModel {
|
|||
// path = FileSystemHelper.normalizeDirectoryPath(this, path);
|
||||
|
||||
filter.setValue(null);
|
||||
currentPath.set(path);
|
||||
savedState.cd(path);
|
||||
history.updateCurrent(path);
|
||||
currentPath.set(path);
|
||||
loadFilesSync(path);
|
||||
}
|
||||
|
||||
|
@ -206,10 +193,7 @@ public final class OpenFileSystemModel {
|
|||
var stream = getFileSystem().listFiles(dir);
|
||||
fileList.setAll(stream);
|
||||
} else {
|
||||
var stream = getFileSystem().listRoots().stream()
|
||||
.map(s -> new FileSystem.FileEntry(
|
||||
getFileSystem(), s, Instant.now(), true, false, false, 0, null));
|
||||
fileList.setAll(stream);
|
||||
fileList.setAll(Stream.of());
|
||||
}
|
||||
return true;
|
||||
} catch (Exception e) {
|
||||
|
@ -314,6 +298,10 @@ public final class OpenFileSystemModel {
|
|||
fileSystem = null;
|
||||
}
|
||||
|
||||
public boolean isClosed() {
|
||||
return fileSystem == null;
|
||||
}
|
||||
|
||||
public void initFileSystem() throws Exception {
|
||||
BusyProperty.execute(busy, () -> {
|
||||
var fs = store.createFileSystem();
|
||||
|
@ -337,7 +325,7 @@ public final class OpenFileSystemModel {
|
|||
}
|
||||
|
||||
private void initState() {
|
||||
this.savedState = OpenFileSystemSavedState.loadForStore(store);
|
||||
this.savedState = OpenFileSystemSavedState.loadForStore(this);
|
||||
}
|
||||
|
||||
public void openTerminalAsync(String directory) {
|
||||
|
@ -365,15 +353,11 @@ public final class OpenFileSystemModel {
|
|||
return history;
|
||||
}
|
||||
|
||||
public void back() {
|
||||
try (var ignored = new BusyProperty(busy)) {
|
||||
cd(history.back());
|
||||
}
|
||||
public void backSync() throws Exception {
|
||||
cdSyncWithoutCheck(history.back());
|
||||
}
|
||||
|
||||
public void forth() {
|
||||
try (var ignored = new BusyProperty(busy)) {
|
||||
cd(history.forth());
|
||||
}
|
||||
public void forthSync() throws Exception {
|
||||
cdSyncWithoutCheck(history.forth());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -14,7 +14,6 @@ import com.fasterxml.jackson.databind.node.ObjectNode;
|
|||
import com.fasterxml.jackson.databind.ser.std.StdSerializer;
|
||||
import io.xpipe.app.core.AppCache;
|
||||
import io.xpipe.app.storage.DataStorage;
|
||||
import io.xpipe.core.store.FileSystemStore;
|
||||
import io.xpipe.core.util.JacksonMapper;
|
||||
import javafx.application.Platform;
|
||||
import javafx.collections.FXCollections;
|
||||
|
@ -63,15 +62,15 @@ public class OpenFileSystemSavedState {
|
|||
}
|
||||
}
|
||||
|
||||
static OpenFileSystemSavedState loadForStore(FileSystemStore store) {
|
||||
static OpenFileSystemSavedState loadForStore(OpenFileSystemModel model) {
|
||||
var storageEntry = DataStorage.get()
|
||||
.getStoreEntryIfPresent(store)
|
||||
.getStoreEntryIfPresent(model.getStore())
|
||||
.map(entry -> entry.getUuid())
|
||||
.orElse(UUID.randomUUID());
|
||||
var state = AppCache.get("fs-state-" + storageEntry, OpenFileSystemSavedState.class, () -> {
|
||||
return new OpenFileSystemSavedState();
|
||||
});
|
||||
state.store = store;
|
||||
state.setModel(model);
|
||||
return state;
|
||||
}
|
||||
|
||||
|
@ -84,7 +83,8 @@ public class OpenFileSystemSavedState {
|
|||
Instant time;
|
||||
}
|
||||
|
||||
private FileSystemStore store;
|
||||
@Setter
|
||||
private OpenFileSystemModel model;
|
||||
private String lastDirectory;
|
||||
@NonNull
|
||||
private ObservableList<RecentEntry> recentDirectories;
|
||||
|
@ -103,11 +103,11 @@ public class OpenFileSystemSavedState {
|
|||
}
|
||||
|
||||
public void save() {
|
||||
if (store == null) {
|
||||
if (model == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
var storageEntry = DataStorage.get().getStoreEntryIfPresent(store);
|
||||
var storageEntry = DataStorage.get().getStoreEntryIfPresent(model.getStore());
|
||||
storageEntry.ifPresent(entry -> AppCache.update("fs-state-" + entry.getUuid(), this));
|
||||
}
|
||||
|
||||
|
@ -123,6 +123,10 @@ public class OpenFileSystemSavedState {
|
|||
public void run() {
|
||||
// Synchronize with platform thread
|
||||
Platform.runLater(() -> {
|
||||
if (model.isClosed()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (Objects.equals(lastDirectory, dir)) {
|
||||
updateRecent(dir);
|
||||
save();
|
||||
|
@ -130,7 +134,7 @@ public class OpenFileSystemSavedState {
|
|||
});
|
||||
}
|
||||
},
|
||||
20000);
|
||||
200);
|
||||
}
|
||||
|
||||
private void updateRecent(String dir) {
|
||||
|
|
|
@ -36,7 +36,12 @@ public interface LeafAction extends BrowserAction {
|
|||
b.setGraphic(graphic);
|
||||
}
|
||||
b.setMnemonicParsing(false);
|
||||
|
||||
b.setDisable(!isActive(model, selected));
|
||||
model.getCurrentPath().addListener((observable, oldValue, newValue) -> {
|
||||
b.setDisable(!isActive(model, selected));
|
||||
});
|
||||
|
||||
return b;
|
||||
}
|
||||
|
||||
|
|
|
@ -5,10 +5,7 @@ import io.xpipe.app.browser.BrowserModel;
|
|||
import io.xpipe.app.comp.about.AboutTabComp;
|
||||
import io.xpipe.app.comp.base.SideMenuBarComp;
|
||||
import io.xpipe.app.comp.storage.store.StoreLayoutComp;
|
||||
import io.xpipe.app.core.AppActionLinkDetector;
|
||||
import io.xpipe.app.core.AppFont;
|
||||
import io.xpipe.app.core.AppI18n;
|
||||
import io.xpipe.app.core.AppProperties;
|
||||
import io.xpipe.app.core.*;
|
||||
import io.xpipe.app.fxcomps.Comp;
|
||||
import io.xpipe.app.fxcomps.CompStructure;
|
||||
import io.xpipe.app.fxcomps.SimpleCompStructure;
|
||||
|
@ -33,7 +30,7 @@ public class AppLayoutComp extends Comp<CompStructure<BorderPane>> {
|
|||
|
||||
public AppLayoutComp() {
|
||||
entries = createEntryList();
|
||||
selected = new SimpleObjectProperty<>(entries.get(0));
|
||||
selected = new SimpleObjectProperty<>(AppState.get().isInitialLaunch() ? entries.get(1) : entries.get(0));
|
||||
|
||||
shortcut(new KeyCodeCombination(KeyCode.V, KeyCombination.SHORTCUT_DOWN), structure -> {
|
||||
AppActionLinkDetector.detectOnPaste();
|
||||
|
@ -43,11 +40,11 @@ public class AppLayoutComp extends Comp<CompStructure<BorderPane>> {
|
|||
@SneakyThrows
|
||||
private List<SideMenuBarComp.Entry> createEntryList() {
|
||||
var l = new ArrayList<>(List.of(
|
||||
new SideMenuBarComp.Entry(AppI18n.observable("connections"), "mdi2c-connection", new StoreLayoutComp()),
|
||||
new SideMenuBarComp.Entry(
|
||||
AppI18n.observable("browser"),
|
||||
"mdi2f-file-cabinet",
|
||||
new BrowserComp(BrowserModel.DEFAULT)),
|
||||
new SideMenuBarComp.Entry(AppI18n.observable("connections"), "mdi2c-connection", new StoreLayoutComp()),
|
||||
// new SideMenuBarComp.Entry(AppI18n.observable("data"), "mdsal-dvr", new SourceCollectionLayoutComp()),
|
||||
new SideMenuBarComp.Entry(
|
||||
AppI18n.observable("settings"), "mdsmz-miscellaneous_services", new PrefsComp(this)),
|
||||
|
|
75
app/src/main/java/io/xpipe/app/comp/base/VBoxViewComp.java
Normal file
75
app/src/main/java/io/xpipe/app/comp/base/VBoxViewComp.java
Normal file
|
@ -0,0 +1,75 @@
|
|||
package io.xpipe.app.comp.base;
|
||||
|
||||
import io.xpipe.app.fxcomps.Comp;
|
||||
import io.xpipe.app.fxcomps.CompStructure;
|
||||
import io.xpipe.app.fxcomps.SimpleCompStructure;
|
||||
import io.xpipe.app.fxcomps.util.PlatformThread;
|
||||
import javafx.application.Platform;
|
||||
import javafx.collections.ListChangeListener;
|
||||
import javafx.collections.ObservableList;
|
||||
import javafx.scene.layout.Region;
|
||||
import javafx.scene.layout.VBox;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.function.Function;
|
||||
|
||||
public class VBoxViewComp<T> extends Comp<CompStructure<VBox>> {
|
||||
|
||||
private final ObservableList<T> shown;
|
||||
private final ObservableList<T> all;
|
||||
private final Function<T, Comp<?>> compFunction;
|
||||
|
||||
public VBoxViewComp(ObservableList<T> shown, ObservableList<T> all, Function<T, Comp<?>> compFunction) {
|
||||
this.shown = PlatformThread.sync(shown);
|
||||
this.all = PlatformThread.sync(all);
|
||||
this.compFunction = compFunction;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompStructure<VBox> createBase() {
|
||||
Map<T, Region> cache = new HashMap<>();
|
||||
|
||||
VBox vbox = new VBox();
|
||||
vbox.setFocusTraversable(false);
|
||||
|
||||
refresh(vbox, shown, cache, false);
|
||||
vbox.requestLayout();
|
||||
|
||||
shown.addListener((ListChangeListener<? super T>) (c) -> {
|
||||
refresh(vbox, c.getList(), cache, true);
|
||||
});
|
||||
|
||||
all.addListener((ListChangeListener<? super T>) c -> {
|
||||
cache.keySet().retainAll(c.getList());
|
||||
});
|
||||
|
||||
return new SimpleCompStructure<>(vbox);
|
||||
}
|
||||
|
||||
private void refresh(VBox listView, List<? extends T> c, Map<T, Region> cache, boolean asynchronous) {
|
||||
Runnable update = () -> {
|
||||
var newShown = c.stream()
|
||||
.map(v -> {
|
||||
if (!cache.containsKey(v)) {
|
||||
cache.put(v, compFunction.apply(v).createRegion());
|
||||
}
|
||||
|
||||
return cache.get(v);
|
||||
})
|
||||
.toList();
|
||||
|
||||
if (!listView.getChildren().equals(newShown)) {
|
||||
listView.getChildren().setAll(newShown);
|
||||
listView.layout();
|
||||
}
|
||||
};
|
||||
|
||||
if (asynchronous) {
|
||||
Platform.runLater(update);
|
||||
} else {
|
||||
PlatformThread.runLaterIfNeeded(update);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -32,8 +32,8 @@ public class StoreEntryListHeaderComp extends SimpleComp {
|
|||
}
|
||||
|
||||
private Region createGroupListFilter() {
|
||||
var filledHerProperty = new SimpleStringProperty();
|
||||
filledHerProperty.addListener((observable, oldValue, newValue) -> {
|
||||
var filterProperty = new SimpleStringProperty();
|
||||
filterProperty.addListener((observable, oldValue, newValue) -> {
|
||||
ThreadHelper.runAsync(() -> {
|
||||
StoreViewState.get().getFilter().filterProperty().setValue(newValue);
|
||||
});
|
||||
|
|
|
@ -22,6 +22,7 @@ import java.nio.file.Path;
|
|||
import java.time.Instant;
|
||||
import java.time.ZoneId;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.time.temporal.ChronoField;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
@ -84,7 +85,15 @@ public class AppLogs {
|
|||
var logDir = AppProperties.get().getDataDir().resolve("logs");
|
||||
var shouldLogToFile = shouldWriteLogs();
|
||||
|
||||
Path usedLogsDir = logDir.resolve(FORMATTER.format(Instant.now()));
|
||||
var now = Instant.now();
|
||||
var name = FORMATTER.format(now);
|
||||
Path usedLogsDir = logDir.resolve(name);
|
||||
|
||||
// When two instances are being launched within the same second, add milliseconds
|
||||
if (Files.exists(usedLogsDir)) {
|
||||
usedLogsDir = logDir.resolve(name + "_" + now.get(ChronoField.MILLI_OF_SECOND));
|
||||
}
|
||||
|
||||
if (shouldLogToFile) {
|
||||
try {
|
||||
Files.createDirectories(usedLogsDir);
|
||||
|
|
|
@ -28,6 +28,7 @@ public class FilterComp extends Comp<FilterComp.Structure> {
|
|||
var bgLabel = new Label("Search ...", fi);
|
||||
bgLabel.getStyleClass().add("background");
|
||||
var filter = new TextField();
|
||||
filter.setAccessibleText("Filter");
|
||||
|
||||
SimpleChangeListener.apply(filterText, val -> {
|
||||
PlatformThread.runLaterIfNeeded(() -> filter.setText(val));
|
||||
|
|
|
@ -46,7 +46,7 @@ public class Shortcuts {
|
|||
|
||||
if (s != null) {
|
||||
scene.set(s);
|
||||
SHORTCUTS.put(region, comb);
|
||||
s.addEventHandler(KeyEvent.KEY_PRESSED, filter);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
|
@ -105,9 +105,6 @@
|
|||
.browser .path-text:invisible {
|
||||
-fx-text-fill: transparent;
|
||||
}
|
||||
.browser .path-graphic-button {
|
||||
-fx-padding: 0 5px 0 5px;
|
||||
}
|
||||
|
||||
.browser .overview-file-list {
|
||||
-fx-border-width: 1px;
|
||||
|
|
|
@ -53,7 +53,11 @@ public sealed interface OsType permits OsType.Windows, OsType.Linux, OsType.MacO
|
|||
@Override
|
||||
public List<String> determineInterestingPaths(ShellControl pc) throws Exception {
|
||||
var home = getHomeDirectory(pc);
|
||||
return List.of(home, FileNames.join(home, "Documents"), FileNames.join(home, "Downloads"), FileNames.join(home, "Desktop"));
|
||||
return List.of(
|
||||
home,
|
||||
FileNames.join(home, "Documents"),
|
||||
FileNames.join(home, "Downloads"),
|
||||
FileNames.join(home, "Desktop"));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -111,7 +115,8 @@ public sealed interface OsType permits OsType.Windows, OsType.Linux, OsType.MacO
|
|||
@Override
|
||||
public List<String> determineInterestingPaths(ShellControl pc) throws Exception {
|
||||
var home = getHomeDirectory(pc);
|
||||
return List.of(FileNames.join(home, "Desktop"));
|
||||
return List.of(
|
||||
home, FileNames.join(home, "Downloads"), FileNames.join(home, "Documents"), "/etc", "/tmp", "/var");
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -180,7 +185,16 @@ public sealed interface OsType permits OsType.Windows, OsType.Linux, OsType.MacO
|
|||
@Override
|
||||
public List<String> determineInterestingPaths(ShellControl pc) throws Exception {
|
||||
var home = getHomeDirectory(pc);
|
||||
return List.of(FileNames.join(home, "Desktop"));
|
||||
return List.of(
|
||||
home,
|
||||
FileNames.join(home, "Downloads"),
|
||||
FileNames.join(home, "Documents"),
|
||||
FileNames.join(home, "Desktop"),
|
||||
"/Applications",
|
||||
"/Library",
|
||||
"/System",
|
||||
"/etc"
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -6,35 +6,40 @@ import lombok.Getter;
|
|||
public class ProcessOutputException extends Exception {
|
||||
|
||||
public static ProcessOutputException of(String customPrefix, ProcessOutputException ex) {
|
||||
var messageSuffix = ex.getOutput() != null && ! ex.getOutput().isBlank()?": " + ex.getOutput() : "";
|
||||
var messageSuffix = ex.getOutput() != null && !ex.getOutput().isBlank() ? ": " + ex.getOutput() : "";
|
||||
var message = customPrefix + messageSuffix;
|
||||
return new ProcessOutputException(message, ex.getExitCode(), ex.getOutput());
|
||||
}
|
||||
|
||||
public static ProcessOutputException of(int exitCode, String output, String accumulatedError) {
|
||||
var combinedError = (accumulatedError != null ? accumulatedError.trim() + "\n" : "") + (output != null ? output.trim() : "");
|
||||
var message = switch (exitCode) {
|
||||
case CommandControl.KILLED_EXIT_CODE -> "Process timed out (exit code " + exitCode + ") " + combinedError;
|
||||
case CommandControl.TIMEOUT_EXIT_CODE -> "Process timed out (exit code " + exitCode + ") " + combinedError;
|
||||
default -> "Process returned with exit code " + exitCode + ": " + combinedError;
|
||||
};
|
||||
var combinedError = (accumulatedError != null ? accumulatedError.trim() + "\n" : "")
|
||||
+ (output != null ? output.trim() : "");
|
||||
var hasMessage = !combinedError.trim().isEmpty();
|
||||
var errorSuffix = hasMessage ? ": " + combinedError : "";
|
||||
var message =
|
||||
switch (exitCode) {
|
||||
case CommandControl.KILLED_EXIT_CODE -> "Process timed out and had to be killed" + errorSuffix;
|
||||
case CommandControl.TIMEOUT_EXIT_CODE -> "Wait for process exit timed out"
|
||||
+ errorSuffix;
|
||||
default -> "Process returned exit code " + exitCode + errorSuffix;
|
||||
};
|
||||
return new ProcessOutputException(message, exitCode, combinedError);
|
||||
}
|
||||
|
||||
private final int exitCode;
|
||||
private final String output;
|
||||
|
||||
private ProcessOutputException(String message, int exitCode, String output) {
|
||||
private ProcessOutputException(String message, int exitCode, String output) {
|
||||
super(message);
|
||||
this.exitCode = exitCode;
|
||||
this.output = output;
|
||||
}
|
||||
|
||||
public boolean isTimeOut() {
|
||||
return exitCode == CommandControl.TIMEOUT_EXIT_CODE;
|
||||
return exitCode == CommandControl.TIMEOUT_EXIT_CODE;
|
||||
}
|
||||
|
||||
public boolean isKill() {
|
||||
return exitCode == CommandControl.KILLED_EXIT_CODE;
|
||||
return exitCode == CommandControl.KILLED_EXIT_CODE;
|
||||
}
|
||||
}
|
||||
|
|
5
dist/changelogs/1.0.2.md
vendored
Normal file
5
dist/changelogs/1.0.2.md
vendored
Normal file
|
@ -0,0 +1,5 @@
|
|||
## Changes in 1.0.2
|
||||
|
||||
- Add new overview page for file browser sessions
|
||||
- Fix file IO being corrupted and freezing on Windows systems with global UTF8 enabled
|
||||
- Many small miscellaneous fixes and improvements
|
|
@ -0,0 +1,54 @@
|
|||
package io.xpipe.ext.base.browser;
|
||||
|
||||
import io.xpipe.app.browser.BrowserEntry;
|
||||
import io.xpipe.app.browser.OpenFileSystemModel;
|
||||
import io.xpipe.app.browser.action.LeafAction;
|
||||
import javafx.scene.Node;
|
||||
import javafx.scene.input.KeyCode;
|
||||
import javafx.scene.input.KeyCodeCombination;
|
||||
import javafx.scene.input.KeyCombination;
|
||||
import org.kordamp.ikonli.javafx.FontIcon;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class BackAction implements LeafAction {
|
||||
|
||||
public String getId() {
|
||||
return "back";
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute(OpenFileSystemModel model, List<BrowserEntry> entries) throws Exception {
|
||||
model.backSync();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Category getCategory() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Node getIcon(OpenFileSystemModel model, List<BrowserEntry> entries) {
|
||||
return new FontIcon("fth-arrow-left");
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isApplicable(OpenFileSystemModel model, List<BrowserEntry> entries) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isActive(OpenFileSystemModel model, List<BrowserEntry> entries) {
|
||||
return model.getHistory().canGoBackProperty().get();
|
||||
}
|
||||
|
||||
@Override
|
||||
public KeyCombination getShortcut() {
|
||||
return new KeyCodeCombination(KeyCode.LEFT, KeyCombination.ALT_DOWN);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName(OpenFileSystemModel model, List<BrowserEntry> entries) {
|
||||
return "Back";
|
||||
}
|
||||
}
|
|
@ -0,0 +1,54 @@
|
|||
package io.xpipe.ext.base.browser;
|
||||
|
||||
import io.xpipe.app.browser.BrowserEntry;
|
||||
import io.xpipe.app.browser.OpenFileSystemModel;
|
||||
import io.xpipe.app.browser.action.LeafAction;
|
||||
import javafx.scene.Node;
|
||||
import javafx.scene.input.KeyCode;
|
||||
import javafx.scene.input.KeyCodeCombination;
|
||||
import javafx.scene.input.KeyCombination;
|
||||
import org.kordamp.ikonli.javafx.FontIcon;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class ForwardAction implements LeafAction {
|
||||
|
||||
public String getId() {
|
||||
return "forward";
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute(OpenFileSystemModel model, List<BrowserEntry> entries) throws Exception {
|
||||
model.forthSync();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Category getCategory() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Node getIcon(OpenFileSystemModel model, List<BrowserEntry> entries) {
|
||||
return new FontIcon("fth-arrow-right");
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isApplicable(OpenFileSystemModel model, List<BrowserEntry> entries) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isActive(OpenFileSystemModel model, List<BrowserEntry> entries) {
|
||||
return model.getHistory().canGoForthProperty().get();
|
||||
}
|
||||
|
||||
@Override
|
||||
public KeyCombination getShortcut() {
|
||||
return new KeyCodeCombination(KeyCode.RIGHT, KeyCombination.ALT_DOWN);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName(OpenFileSystemModel model, List<BrowserEntry> entries) {
|
||||
return "Forward";
|
||||
}
|
||||
}
|
|
@ -29,6 +29,11 @@ public class OpenTerminalAction implements LeafAction {
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isActive(OpenFileSystemModel model, List<BrowserEntry> entries) {
|
||||
return !model.getInOverview().get();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Category getCategory() {
|
||||
return Category.OPEN;
|
||||
|
|
|
@ -0,0 +1,55 @@
|
|||
package io.xpipe.ext.base.browser;
|
||||
|
||||
import io.xpipe.app.browser.BrowserEntry;
|
||||
import io.xpipe.app.browser.OpenFileSystemModel;
|
||||
import io.xpipe.app.browser.action.BrowserAction;
|
||||
import io.xpipe.app.browser.action.LeafAction;
|
||||
import javafx.scene.Node;
|
||||
import javafx.scene.input.KeyCode;
|
||||
import javafx.scene.input.KeyCodeCombination;
|
||||
import javafx.scene.input.KeyCombination;
|
||||
import org.kordamp.ikonli.javafx.FontIcon;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class RefreshAction implements LeafAction {
|
||||
|
||||
public String getId() {
|
||||
return "refresh";
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute(OpenFileSystemModel model, List<BrowserEntry> entries) throws Exception {
|
||||
model.refreshSync();
|
||||
}
|
||||
|
||||
@Override
|
||||
public BrowserAction.Category getCategory() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isActive(OpenFileSystemModel model, List<BrowserEntry> entries) {
|
||||
return !model.getInOverview().get();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Node getIcon(OpenFileSystemModel model, List<BrowserEntry> entries) {
|
||||
return new FontIcon("mdmz-refresh");
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isApplicable(OpenFileSystemModel model, List<BrowserEntry> entries) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public KeyCombination getShortcut() {
|
||||
return new KeyCodeCombination(KeyCode.F5);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName(OpenFileSystemModel model, List<BrowserEntry> entries) {
|
||||
return "Refresh";
|
||||
}
|
||||
}
|
|
@ -27,6 +27,9 @@ open module io.xpipe.ext.base {
|
|||
requires com.sun.jna.platform;
|
||||
|
||||
provides BrowserAction with
|
||||
BackAction,
|
||||
ForwardAction,
|
||||
RefreshAction,
|
||||
OpenFileDefaultAction,
|
||||
OpenFileWithAction,
|
||||
OpenDirectoryAction,
|
||||
|
|
2
version
2
version
|
@ -1 +1 @@
|
|||
1.0.1
|
||||
1.0.2
|
Loading…
Reference in a new issue