mirror of
https://github.com/xpipe-io/xpipe.git
synced 2024-11-22 07:30:24 +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.browser.icon.BrowserIcons;
|
||||||
import io.xpipe.app.comp.base.ListBoxViewComp;
|
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.Comp;
|
||||||
import io.xpipe.app.fxcomps.SimpleComp;
|
import io.xpipe.app.fxcomps.SimpleComp;
|
||||||
import io.xpipe.app.fxcomps.augment.GrowAugment;
|
import io.xpipe.app.fxcomps.augment.GrowAugment;
|
||||||
|
@ -13,16 +14,19 @@ import javafx.scene.layout.Region;
|
||||||
import lombok.EqualsAndHashCode;
|
import lombok.EqualsAndHashCode;
|
||||||
import lombok.Value;
|
import lombok.Value;
|
||||||
|
|
||||||
|
import java.util.function.Function;
|
||||||
|
|
||||||
@Value
|
@Value
|
||||||
@EqualsAndHashCode(callSuper = true)
|
@EqualsAndHashCode(callSuper = true)
|
||||||
public class BrowserFileOverviewComp extends SimpleComp {
|
public class BrowserFileOverviewComp extends SimpleComp {
|
||||||
|
|
||||||
OpenFileSystemModel model;
|
OpenFileSystemModel model;
|
||||||
ObservableList<FileSystem.FileEntry> list;
|
ObservableList<FileSystem.FileEntry> list;
|
||||||
|
boolean grow;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected Region createSimple() {
|
protected Region createSimple() {
|
||||||
var c = new ListBoxViewComp<>(list, list, entry -> {
|
Function<FileSystem.FileEntry, Comp<?>> factory = entry -> {
|
||||||
return Comp.of(() -> {
|
return Comp.of(() -> {
|
||||||
var icon = BrowserIcons.createIcon(entry);
|
var icon = BrowserIcons.createIcon(entry);
|
||||||
var l = new Button(entry.getPath(), icon.createRegion());
|
var l = new Button(entry.getPath(), icon.createRegion());
|
||||||
|
@ -34,8 +38,14 @@ public class BrowserFileOverviewComp extends SimpleComp {
|
||||||
GrowAugment.create(true,false).augment(l);
|
GrowAugment.create(true,false).augment(l);
|
||||||
return 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.Insets;
|
||||||
import javafx.geometry.Pos;
|
import javafx.geometry.Pos;
|
||||||
import javafx.scene.control.Button;
|
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.input.MouseButton;
|
||||||
import javafx.scene.layout.Region;
|
import javafx.scene.layout.Region;
|
||||||
|
|
||||||
|
@ -67,6 +70,8 @@ public class BrowserNavBar extends SimpleComp {
|
||||||
});
|
});
|
||||||
|
|
||||||
struc.get().setPromptText("Overview of " + model.getName());
|
struc.get().setPromptText("Overview of " + model.getName());
|
||||||
|
}).shortcut(new KeyCodeCombination(KeyCode.F, KeyCombination.SHORTCUT_DOWN), s -> {
|
||||||
|
s.get().requestFocus();
|
||||||
});
|
});
|
||||||
|
|
||||||
var graphic = Bindings.createStringBinding(
|
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.SimpleComp;
|
||||||
import io.xpipe.app.fxcomps.impl.VerticalComp;
|
import io.xpipe.app.fxcomps.impl.VerticalComp;
|
||||||
import io.xpipe.app.fxcomps.util.BindingsHelper;
|
import io.xpipe.app.fxcomps.util.BindingsHelper;
|
||||||
|
import io.xpipe.app.issue.ErrorEvent;
|
||||||
import io.xpipe.core.process.ShellControl;
|
import io.xpipe.core.process.ShellControl;
|
||||||
import io.xpipe.core.store.FileSystem;
|
import io.xpipe.core.store.FileSystem;
|
||||||
import javafx.collections.FXCollections;
|
import javafx.collections.FXCollections;
|
||||||
|
import javafx.scene.layout.Priority;
|
||||||
import javafx.scene.layout.Region;
|
import javafx.scene.layout.Region;
|
||||||
|
import javafx.scene.layout.VBox;
|
||||||
import lombok.SneakyThrows;
|
import lombok.SneakyThrows;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
@ -25,18 +28,34 @@ public class BrowserOverviewComp extends SimpleComp {
|
||||||
@SneakyThrows
|
@SneakyThrows
|
||||||
protected Region createSimple() {
|
protected Region createSimple() {
|
||||||
ShellControl sc = model.getFileSystem().getShell().orElseThrow();
|
ShellControl sc = model.getFileSystem().getShell().orElseThrow();
|
||||||
var common = sc.getOsType().determineInterestingPaths(sc).stream().map(s -> FileSystem.FileEntry.ofDirectory(model.getFileSystem(), s)).toList();
|
// TODO: May be move this into another thread
|
||||||
var commonOverview = new BrowserFileOverviewComp(model, FXCollections.observableArrayList(common));
|
var common = sc.getOsType().determineInterestingPaths(sc).stream()
|
||||||
var commonPane = new SimpleTitledPaneComp(AppI18n.observable("common"), commonOverview);
|
.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 roots = sc.getShellDialect()
|
||||||
var rootsOverview = new BrowserFileOverviewComp(model, FXCollections.observableArrayList(roots));
|
.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 rootsPane = new SimpleTitledPaneComp(AppI18n.observable("roots"), rootsOverview);
|
||||||
|
|
||||||
|
var recent = BindingsHelper.mappedContentBinding(
|
||||||
var recent = BindingsHelper.mappedContentBinding(model.getSavedState().getRecentDirectories(), s -> FileSystem.FileEntry.ofDirectory(model.getFileSystem(), s.getDirectory()));
|
model.getSavedState().getRecentDirectories(),
|
||||||
var recentOverview = new BrowserFileOverviewComp(model, recent);
|
s -> FileSystem.FileEntry.ofDirectory(model.getFileSystem(), s.getDirectory()));
|
||||||
var recentPane = new SimpleTitledPaneComp(AppI18n.observable("recent"), recentOverview).vgrow();
|
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");
|
var vbox = new VerticalComp(List.of(commonPane, rootsPane, recentPane)).styleClass("overview");
|
||||||
return vbox.createRegion();
|
return vbox.createRegion();
|
||||||
|
|
|
@ -46,23 +46,10 @@ public class OpenFileSystemComp extends SimpleComp {
|
||||||
overview.setOnAction(e -> model.cd(null));
|
overview.setOnAction(e -> model.cd(null));
|
||||||
overview.disableProperty().bind(model.getInOverview());
|
overview.disableProperty().bind(model.getInOverview());
|
||||||
|
|
||||||
var backBtn = new Button(null, new FontIcon("fth-arrow-left"));
|
var backBtn = BrowserAction.byId("back").toButton(model, List.of());
|
||||||
backBtn.setOnAction(e -> model.back());
|
var forthBtn = BrowserAction.byId("forward").toButton(model, List.of());
|
||||||
backBtn.disableProperty().bind(model.getHistory().canGoBackProperty().not());
|
var refreshBtn = BrowserAction.byId("refresh").toButton(model, List.of());
|
||||||
|
|
||||||
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 terminalBtn = BrowserAction.byId("openTerminal").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"));
|
var menuButton = new MenuButton(null, new FontIcon("mdral-folder_open"));
|
||||||
new ContextMenuAugment<>(
|
new ContextMenuAugment<>(
|
||||||
|
|
|
@ -9,7 +9,7 @@ import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
|
||||||
final class OpenFileSystemHistory {
|
public final class OpenFileSystemHistory {
|
||||||
|
|
||||||
private final IntegerProperty cursor = new SimpleIntegerProperty(-1);
|
private final IntegerProperty cursor = new SimpleIntegerProperty(-1);
|
||||||
private final List<String> history = new ArrayList<>();
|
private final List<String> history = new ArrayList<>();
|
||||||
|
|
|
@ -22,7 +22,6 @@ import org.apache.commons.lang3.function.FailableConsumer;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
import java.time.Instant;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
@ -54,7 +53,6 @@ public final class OpenFileSystemModel {
|
||||||
return currentPath.get() == null;
|
return currentPath.get() == null;
|
||||||
}, currentPath));
|
}, currentPath));
|
||||||
fileList = new BrowserFileListModel(this);
|
fileList = new BrowserFileListModel(this);
|
||||||
addListeners();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void withShell(FailableConsumer<ShellControl, Exception> c, boolean refresh) {
|
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
|
@SneakyThrows
|
||||||
public void refresh() {
|
public void refresh() {
|
||||||
BusyProperty.execute(busy, () -> {
|
BusyProperty.execute(busy, () -> {
|
||||||
|
@ -194,9 +181,9 @@ public final class OpenFileSystemModel {
|
||||||
// path = FileSystemHelper.normalizeDirectoryPath(this, path);
|
// path = FileSystemHelper.normalizeDirectoryPath(this, path);
|
||||||
|
|
||||||
filter.setValue(null);
|
filter.setValue(null);
|
||||||
currentPath.set(path);
|
|
||||||
savedState.cd(path);
|
savedState.cd(path);
|
||||||
history.updateCurrent(path);
|
history.updateCurrent(path);
|
||||||
|
currentPath.set(path);
|
||||||
loadFilesSync(path);
|
loadFilesSync(path);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -206,10 +193,7 @@ public final class OpenFileSystemModel {
|
||||||
var stream = getFileSystem().listFiles(dir);
|
var stream = getFileSystem().listFiles(dir);
|
||||||
fileList.setAll(stream);
|
fileList.setAll(stream);
|
||||||
} else {
|
} else {
|
||||||
var stream = getFileSystem().listRoots().stream()
|
fileList.setAll(Stream.of());
|
||||||
.map(s -> new FileSystem.FileEntry(
|
|
||||||
getFileSystem(), s, Instant.now(), true, false, false, 0, null));
|
|
||||||
fileList.setAll(stream);
|
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
|
@ -314,6 +298,10 @@ public final class OpenFileSystemModel {
|
||||||
fileSystem = null;
|
fileSystem = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean isClosed() {
|
||||||
|
return fileSystem == null;
|
||||||
|
}
|
||||||
|
|
||||||
public void initFileSystem() throws Exception {
|
public void initFileSystem() throws Exception {
|
||||||
BusyProperty.execute(busy, () -> {
|
BusyProperty.execute(busy, () -> {
|
||||||
var fs = store.createFileSystem();
|
var fs = store.createFileSystem();
|
||||||
|
@ -337,7 +325,7 @@ public final class OpenFileSystemModel {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void initState() {
|
private void initState() {
|
||||||
this.savedState = OpenFileSystemSavedState.loadForStore(store);
|
this.savedState = OpenFileSystemSavedState.loadForStore(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void openTerminalAsync(String directory) {
|
public void openTerminalAsync(String directory) {
|
||||||
|
@ -365,15 +353,11 @@ public final class OpenFileSystemModel {
|
||||||
return history;
|
return history;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void back() {
|
public void backSync() throws Exception {
|
||||||
try (var ignored = new BusyProperty(busy)) {
|
cdSyncWithoutCheck(history.back());
|
||||||
cd(history.back());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void forth() {
|
public void forthSync() throws Exception {
|
||||||
try (var ignored = new BusyProperty(busy)) {
|
cdSyncWithoutCheck(history.forth());
|
||||||
cd(history.forth());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,7 +14,6 @@ import com.fasterxml.jackson.databind.node.ObjectNode;
|
||||||
import com.fasterxml.jackson.databind.ser.std.StdSerializer;
|
import com.fasterxml.jackson.databind.ser.std.StdSerializer;
|
||||||
import io.xpipe.app.core.AppCache;
|
import io.xpipe.app.core.AppCache;
|
||||||
import io.xpipe.app.storage.DataStorage;
|
import io.xpipe.app.storage.DataStorage;
|
||||||
import io.xpipe.core.store.FileSystemStore;
|
|
||||||
import io.xpipe.core.util.JacksonMapper;
|
import io.xpipe.core.util.JacksonMapper;
|
||||||
import javafx.application.Platform;
|
import javafx.application.Platform;
|
||||||
import javafx.collections.FXCollections;
|
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()
|
var storageEntry = DataStorage.get()
|
||||||
.getStoreEntryIfPresent(store)
|
.getStoreEntryIfPresent(model.getStore())
|
||||||
.map(entry -> entry.getUuid())
|
.map(entry -> entry.getUuid())
|
||||||
.orElse(UUID.randomUUID());
|
.orElse(UUID.randomUUID());
|
||||||
var state = AppCache.get("fs-state-" + storageEntry, OpenFileSystemSavedState.class, () -> {
|
var state = AppCache.get("fs-state-" + storageEntry, OpenFileSystemSavedState.class, () -> {
|
||||||
return new OpenFileSystemSavedState();
|
return new OpenFileSystemSavedState();
|
||||||
});
|
});
|
||||||
state.store = store;
|
state.setModel(model);
|
||||||
return state;
|
return state;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -84,7 +83,8 @@ public class OpenFileSystemSavedState {
|
||||||
Instant time;
|
Instant time;
|
||||||
}
|
}
|
||||||
|
|
||||||
private FileSystemStore store;
|
@Setter
|
||||||
|
private OpenFileSystemModel model;
|
||||||
private String lastDirectory;
|
private String lastDirectory;
|
||||||
@NonNull
|
@NonNull
|
||||||
private ObservableList<RecentEntry> recentDirectories;
|
private ObservableList<RecentEntry> recentDirectories;
|
||||||
|
@ -103,11 +103,11 @@ public class OpenFileSystemSavedState {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void save() {
|
public void save() {
|
||||||
if (store == null) {
|
if (model == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var storageEntry = DataStorage.get().getStoreEntryIfPresent(store);
|
var storageEntry = DataStorage.get().getStoreEntryIfPresent(model.getStore());
|
||||||
storageEntry.ifPresent(entry -> AppCache.update("fs-state-" + entry.getUuid(), this));
|
storageEntry.ifPresent(entry -> AppCache.update("fs-state-" + entry.getUuid(), this));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -123,6 +123,10 @@ public class OpenFileSystemSavedState {
|
||||||
public void run() {
|
public void run() {
|
||||||
// Synchronize with platform thread
|
// Synchronize with platform thread
|
||||||
Platform.runLater(() -> {
|
Platform.runLater(() -> {
|
||||||
|
if (model.isClosed()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (Objects.equals(lastDirectory, dir)) {
|
if (Objects.equals(lastDirectory, dir)) {
|
||||||
updateRecent(dir);
|
updateRecent(dir);
|
||||||
save();
|
save();
|
||||||
|
@ -130,7 +134,7 @@ public class OpenFileSystemSavedState {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
20000);
|
200);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updateRecent(String dir) {
|
private void updateRecent(String dir) {
|
||||||
|
|
|
@ -36,7 +36,12 @@ public interface LeafAction extends BrowserAction {
|
||||||
b.setGraphic(graphic);
|
b.setGraphic(graphic);
|
||||||
}
|
}
|
||||||
b.setMnemonicParsing(false);
|
b.setMnemonicParsing(false);
|
||||||
|
|
||||||
b.setDisable(!isActive(model, selected));
|
b.setDisable(!isActive(model, selected));
|
||||||
|
model.getCurrentPath().addListener((observable, oldValue, newValue) -> {
|
||||||
|
b.setDisable(!isActive(model, selected));
|
||||||
|
});
|
||||||
|
|
||||||
return b;
|
return b;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -5,10 +5,7 @@ import io.xpipe.app.browser.BrowserModel;
|
||||||
import io.xpipe.app.comp.about.AboutTabComp;
|
import io.xpipe.app.comp.about.AboutTabComp;
|
||||||
import io.xpipe.app.comp.base.SideMenuBarComp;
|
import io.xpipe.app.comp.base.SideMenuBarComp;
|
||||||
import io.xpipe.app.comp.storage.store.StoreLayoutComp;
|
import io.xpipe.app.comp.storage.store.StoreLayoutComp;
|
||||||
import io.xpipe.app.core.AppActionLinkDetector;
|
import io.xpipe.app.core.*;
|
||||||
import io.xpipe.app.core.AppFont;
|
|
||||||
import io.xpipe.app.core.AppI18n;
|
|
||||||
import io.xpipe.app.core.AppProperties;
|
|
||||||
import io.xpipe.app.fxcomps.Comp;
|
import io.xpipe.app.fxcomps.Comp;
|
||||||
import io.xpipe.app.fxcomps.CompStructure;
|
import io.xpipe.app.fxcomps.CompStructure;
|
||||||
import io.xpipe.app.fxcomps.SimpleCompStructure;
|
import io.xpipe.app.fxcomps.SimpleCompStructure;
|
||||||
|
@ -33,7 +30,7 @@ public class AppLayoutComp extends Comp<CompStructure<BorderPane>> {
|
||||||
|
|
||||||
public AppLayoutComp() {
|
public AppLayoutComp() {
|
||||||
entries = createEntryList();
|
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 -> {
|
shortcut(new KeyCodeCombination(KeyCode.V, KeyCombination.SHORTCUT_DOWN), structure -> {
|
||||||
AppActionLinkDetector.detectOnPaste();
|
AppActionLinkDetector.detectOnPaste();
|
||||||
|
@ -43,11 +40,11 @@ public class AppLayoutComp extends Comp<CompStructure<BorderPane>> {
|
||||||
@SneakyThrows
|
@SneakyThrows
|
||||||
private List<SideMenuBarComp.Entry> createEntryList() {
|
private List<SideMenuBarComp.Entry> createEntryList() {
|
||||||
var l = new ArrayList<>(List.of(
|
var l = new ArrayList<>(List.of(
|
||||||
new SideMenuBarComp.Entry(AppI18n.observable("connections"), "mdi2c-connection", new StoreLayoutComp()),
|
|
||||||
new SideMenuBarComp.Entry(
|
new SideMenuBarComp.Entry(
|
||||||
AppI18n.observable("browser"),
|
AppI18n.observable("browser"),
|
||||||
"mdi2f-file-cabinet",
|
"mdi2f-file-cabinet",
|
||||||
new BrowserComp(BrowserModel.DEFAULT)),
|
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("data"), "mdsal-dvr", new SourceCollectionLayoutComp()),
|
||||||
new SideMenuBarComp.Entry(
|
new SideMenuBarComp.Entry(
|
||||||
AppI18n.observable("settings"), "mdsmz-miscellaneous_services", new PrefsComp(this)),
|
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() {
|
private Region createGroupListFilter() {
|
||||||
var filledHerProperty = new SimpleStringProperty();
|
var filterProperty = new SimpleStringProperty();
|
||||||
filledHerProperty.addListener((observable, oldValue, newValue) -> {
|
filterProperty.addListener((observable, oldValue, newValue) -> {
|
||||||
ThreadHelper.runAsync(() -> {
|
ThreadHelper.runAsync(() -> {
|
||||||
StoreViewState.get().getFilter().filterProperty().setValue(newValue);
|
StoreViewState.get().getFilter().filterProperty().setValue(newValue);
|
||||||
});
|
});
|
||||||
|
|
|
@ -22,6 +22,7 @@ import java.nio.file.Path;
|
||||||
import java.time.Instant;
|
import java.time.Instant;
|
||||||
import java.time.ZoneId;
|
import java.time.ZoneId;
|
||||||
import java.time.format.DateTimeFormatter;
|
import java.time.format.DateTimeFormatter;
|
||||||
|
import java.time.temporal.ChronoField;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
@ -84,7 +85,15 @@ public class AppLogs {
|
||||||
var logDir = AppProperties.get().getDataDir().resolve("logs");
|
var logDir = AppProperties.get().getDataDir().resolve("logs");
|
||||||
var shouldLogToFile = shouldWriteLogs();
|
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) {
|
if (shouldLogToFile) {
|
||||||
try {
|
try {
|
||||||
Files.createDirectories(usedLogsDir);
|
Files.createDirectories(usedLogsDir);
|
||||||
|
|
|
@ -28,6 +28,7 @@ public class FilterComp extends Comp<FilterComp.Structure> {
|
||||||
var bgLabel = new Label("Search ...", fi);
|
var bgLabel = new Label("Search ...", fi);
|
||||||
bgLabel.getStyleClass().add("background");
|
bgLabel.getStyleClass().add("background");
|
||||||
var filter = new TextField();
|
var filter = new TextField();
|
||||||
|
filter.setAccessibleText("Filter");
|
||||||
|
|
||||||
SimpleChangeListener.apply(filterText, val -> {
|
SimpleChangeListener.apply(filterText, val -> {
|
||||||
PlatformThread.runLaterIfNeeded(() -> filter.setText(val));
|
PlatformThread.runLaterIfNeeded(() -> filter.setText(val));
|
||||||
|
|
|
@ -46,7 +46,7 @@ public class Shortcuts {
|
||||||
|
|
||||||
if (s != null) {
|
if (s != null) {
|
||||||
scene.set(s);
|
scene.set(s);
|
||||||
SHORTCUTS.put(region, comb);
|
s.addEventHandler(KeyEvent.KEY_PRESSED, filter);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -105,9 +105,6 @@
|
||||||
.browser .path-text:invisible {
|
.browser .path-text:invisible {
|
||||||
-fx-text-fill: transparent;
|
-fx-text-fill: transparent;
|
||||||
}
|
}
|
||||||
.browser .path-graphic-button {
|
|
||||||
-fx-padding: 0 5px 0 5px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.browser .overview-file-list {
|
.browser .overview-file-list {
|
||||||
-fx-border-width: 1px;
|
-fx-border-width: 1px;
|
||||||
|
|
|
@ -53,7 +53,11 @@ public sealed interface OsType permits OsType.Windows, OsType.Linux, OsType.MacO
|
||||||
@Override
|
@Override
|
||||||
public List<String> determineInterestingPaths(ShellControl pc) throws Exception {
|
public List<String> determineInterestingPaths(ShellControl pc) throws Exception {
|
||||||
var home = getHomeDirectory(pc);
|
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
|
@Override
|
||||||
|
@ -111,7 +115,8 @@ public sealed interface OsType permits OsType.Windows, OsType.Linux, OsType.MacO
|
||||||
@Override
|
@Override
|
||||||
public List<String> determineInterestingPaths(ShellControl pc) throws Exception {
|
public List<String> determineInterestingPaths(ShellControl pc) throws Exception {
|
||||||
var home = getHomeDirectory(pc);
|
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
|
@Override
|
||||||
|
@ -180,7 +185,16 @@ public sealed interface OsType permits OsType.Windows, OsType.Linux, OsType.MacO
|
||||||
@Override
|
@Override
|
||||||
public List<String> determineInterestingPaths(ShellControl pc) throws Exception {
|
public List<String> determineInterestingPaths(ShellControl pc) throws Exception {
|
||||||
var home = getHomeDirectory(pc);
|
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
|
@Override
|
||||||
|
|
|
@ -6,35 +6,40 @@ import lombok.Getter;
|
||||||
public class ProcessOutputException extends Exception {
|
public class ProcessOutputException extends Exception {
|
||||||
|
|
||||||
public static ProcessOutputException of(String customPrefix, ProcessOutputException ex) {
|
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;
|
var message = customPrefix + messageSuffix;
|
||||||
return new ProcessOutputException(message, ex.getExitCode(), ex.getOutput());
|
return new ProcessOutputException(message, ex.getExitCode(), ex.getOutput());
|
||||||
}
|
}
|
||||||
|
|
||||||
public static ProcessOutputException of(int exitCode, String output, String accumulatedError) {
|
public static ProcessOutputException of(int exitCode, String output, String accumulatedError) {
|
||||||
var combinedError = (accumulatedError != null ? accumulatedError.trim() + "\n" : "") + (output != null ? output.trim() : "");
|
var combinedError = (accumulatedError != null ? accumulatedError.trim() + "\n" : "")
|
||||||
var message = switch (exitCode) {
|
+ (output != null ? output.trim() : "");
|
||||||
case CommandControl.KILLED_EXIT_CODE -> "Process timed out (exit code " + exitCode + ") " + combinedError;
|
var hasMessage = !combinedError.trim().isEmpty();
|
||||||
case CommandControl.TIMEOUT_EXIT_CODE -> "Process timed out (exit code " + exitCode + ") " + combinedError;
|
var errorSuffix = hasMessage ? ": " + combinedError : "";
|
||||||
default -> "Process returned with exit code " + exitCode + ": " + 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);
|
return new ProcessOutputException(message, exitCode, combinedError);
|
||||||
}
|
}
|
||||||
|
|
||||||
private final int exitCode;
|
private final int exitCode;
|
||||||
private final String output;
|
private final String output;
|
||||||
|
|
||||||
private ProcessOutputException(String message, int exitCode, String output) {
|
private ProcessOutputException(String message, int exitCode, String output) {
|
||||||
super(message);
|
super(message);
|
||||||
this.exitCode = exitCode;
|
this.exitCode = exitCode;
|
||||||
this.output = output;
|
this.output = output;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isTimeOut() {
|
public boolean isTimeOut() {
|
||||||
return exitCode == CommandControl.TIMEOUT_EXIT_CODE;
|
return exitCode == CommandControl.TIMEOUT_EXIT_CODE;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isKill() {
|
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
|
@Override
|
||||||
public Category getCategory() {
|
public Category getCategory() {
|
||||||
return Category.OPEN;
|
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;
|
requires com.sun.jna.platform;
|
||||||
|
|
||||||
provides BrowserAction with
|
provides BrowserAction with
|
||||||
|
BackAction,
|
||||||
|
ForwardAction,
|
||||||
|
RefreshAction,
|
||||||
OpenFileDefaultAction,
|
OpenFileDefaultAction,
|
||||||
OpenFileWithAction,
|
OpenFileWithAction,
|
||||||
OpenDirectoryAction,
|
OpenDirectoryAction,
|
||||||
|
|
2
version
2
version
|
@ -1 +1 @@
|
||||||
1.0.1
|
1.0.2
|
Loading…
Reference in a new issue