mirror of
https://github.com/xpipe-io/xpipe.git
synced 2024-11-25 09:00:26 +00:00
Browser fixes
This commit is contained in:
parent
ef5427f046
commit
b5471e52d1
23 changed files with 215 additions and 154 deletions
|
@ -81,6 +81,7 @@ public final class BrowserFileListComp extends SimpleComp {
|
||||||
filenameCol.setSortType(ASCENDING);
|
filenameCol.setSortType(ASCENDING);
|
||||||
filenameCol.setCellFactory(col -> new FilenameCell(fileList.getEditing(), col.getTableView()));
|
filenameCol.setCellFactory(col -> new FilenameCell(fileList.getEditing(), col.getTableView()));
|
||||||
filenameCol.setReorderable(false);
|
filenameCol.setReorderable(false);
|
||||||
|
filenameCol.setResizable(false);
|
||||||
|
|
||||||
var sizeCol = new TableColumn<BrowserEntry, Number>();
|
var sizeCol = new TableColumn<BrowserEntry, Number>();
|
||||||
sizeCol.textProperty().bind(AppI18n.observable("size"));
|
sizeCol.textProperty().bind(AppI18n.observable("size"));
|
||||||
|
@ -118,36 +119,53 @@ public final class BrowserFileListComp extends SimpleComp {
|
||||||
ownerCol.setCellFactory(col -> new FileOwnerCell());
|
ownerCol.setCellFactory(col -> new FileOwnerCell());
|
||||||
ownerCol.setSortable(false);
|
ownerCol.setSortable(false);
|
||||||
ownerCol.setReorderable(false);
|
ownerCol.setReorderable(false);
|
||||||
ownerCol.prefWidthProperty().bind(ownerWidth);
|
|
||||||
ownerCol.setResizable(false);
|
ownerCol.setResizable(false);
|
||||||
|
|
||||||
var table = new TableView<BrowserEntry>();
|
var table = new TableView<BrowserEntry>();
|
||||||
|
table.setSkin(new TableViewSkin<>(table));
|
||||||
table.setAccessibleText("Directory contents");
|
table.setAccessibleText("Directory contents");
|
||||||
table.setPlaceholder(new Region());
|
table.setPlaceholder(new Region());
|
||||||
table.getStyleClass().add(Styles.STRIPED);
|
table.getStyleClass().add(Styles.STRIPED);
|
||||||
table.getColumns().setAll(filenameCol, sizeCol, modeCol, mtimeCol);
|
table.getColumns().setAll(filenameCol, sizeCol, modeCol, ownerCol, mtimeCol);
|
||||||
table.getSortOrder().add(filenameCol);
|
table.getSortOrder().add(filenameCol);
|
||||||
table.setFocusTraversable(true);
|
table.setFocusTraversable(true);
|
||||||
table.setSortPolicy(param -> {
|
table.setSortPolicy(param -> {
|
||||||
fileList.setComparator(table.getComparator());
|
fileList.setComparator(table.getComparator());
|
||||||
return true;
|
return true;
|
||||||
});
|
});
|
||||||
table.setColumnResizePolicy(TableView.CONSTRAINED_RESIZE_POLICY_FLEX_NEXT_COLUMN);
|
|
||||||
table.setFixedCellSize(32.0);
|
table.setFixedCellSize(32.0);
|
||||||
|
var os = fileList.getFileSystemModel().getFileSystem().getShell().orElseThrow().getOsType();
|
||||||
table.widthProperty().subscribe((newValue) -> {
|
table.widthProperty().subscribe((newValue) -> {
|
||||||
|
if (os != OsType.WINDOWS) {
|
||||||
ownerCol.setVisible(newValue.doubleValue() > 1000);
|
ownerCol.setVisible(newValue.doubleValue() > 1000);
|
||||||
|
}
|
||||||
|
var width = getFilenameWidth(table);
|
||||||
|
filenameCol.setPrefWidth(width);
|
||||||
|
});
|
||||||
|
|
||||||
|
table.lookupAll(".scroll-bar").stream().filter(node -> node.getPseudoClassStates().contains(PseudoClass.getPseudoClass("horizontal"))).findFirst().ifPresent(node -> {
|
||||||
|
Region region = (Region) node;
|
||||||
|
region.setMinHeight(0);
|
||||||
|
region.setPrefHeight(0);
|
||||||
|
region.setMaxHeight(0);
|
||||||
});
|
});
|
||||||
|
|
||||||
prepareTableSelectionModel(table);
|
prepareTableSelectionModel(table);
|
||||||
prepareTableShortcuts(table);
|
prepareTableShortcuts(table);
|
||||||
prepareTableEntries(table);
|
prepareTableEntries(table);
|
||||||
prepareTableChanges(table, mtimeCol, modeCol, ownerCol);
|
prepareTableChanges(table, filenameCol, mtimeCol, modeCol, ownerCol);
|
||||||
prepareTypedSelectionModel(table);
|
prepareTypedSelectionModel(table);
|
||||||
|
|
||||||
return table;
|
return table;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private double getFilenameWidth(TableView<?> tableView) {
|
||||||
|
var sum = tableView.getColumns().stream().filter(tableColumn -> tableColumn.isVisible() &&
|
||||||
|
tableView.getColumns().indexOf(tableColumn) != 0)
|
||||||
|
.mapToDouble(value -> value.getPrefWidth()).sum() + 7;
|
||||||
|
return tableView.getWidth() - sum;
|
||||||
|
}
|
||||||
|
|
||||||
private String formatOwner(BrowserEntry param) {
|
private String formatOwner(BrowserEntry param) {
|
||||||
FileInfo.Unix unix = param.getRawFileEntry().resolved().getInfo() instanceof FileInfo.Unix u ? u : null;
|
FileInfo.Unix unix = param.getRawFileEntry().resolved().getInfo() instanceof FileInfo.Unix u ? u : null;
|
||||||
if (unix == null) {
|
if (unix == null) {
|
||||||
|
@ -400,72 +418,60 @@ public final class BrowserFileListComp extends SimpleComp {
|
||||||
|
|
||||||
private void prepareTableChanges(
|
private void prepareTableChanges(
|
||||||
TableView<BrowserEntry> table,
|
TableView<BrowserEntry> table,
|
||||||
|
TableColumn<BrowserEntry, String> filenameCol,
|
||||||
TableColumn<BrowserEntry, Instant> mtimeCol,
|
TableColumn<BrowserEntry, Instant> mtimeCol,
|
||||||
TableColumn<BrowserEntry, String> modeCol,
|
TableColumn<BrowserEntry, String> modeCol,
|
||||||
TableColumn<BrowserEntry, String> ownerCol) {
|
TableColumn<BrowserEntry, String> ownerCol) {
|
||||||
var lastDir = new SimpleObjectProperty<FileEntry>();
|
var lastDir = new SimpleObjectProperty<FileEntry>();
|
||||||
Runnable updateHandler = () -> {
|
Runnable updateHandler = () -> {
|
||||||
Platform.runLater(() -> {
|
PlatformThread.runLaterIfNeeded(() -> {
|
||||||
var newItems = new ArrayList<>(fileList.getShown().getValue());
|
var newItems = new ArrayList<>(fileList.getShown().getValue());
|
||||||
|
table.getItems().clear();
|
||||||
|
|
||||||
var hasModifiedDate = newItems.size() == 0
|
var hasModifiedDate = newItems.size() == 0 || newItems.stream().anyMatch(entry -> entry.getRawFileEntry().getDate() != null);
|
||||||
|| newItems.stream()
|
|
||||||
.anyMatch(entry -> entry.getRawFileEntry().getDate() != null);
|
|
||||||
if (!hasModifiedDate) {
|
if (!hasModifiedDate) {
|
||||||
table.getColumns().remove(mtimeCol);
|
mtimeCol.setVisible(false);
|
||||||
} else {
|
} else {
|
||||||
if (!table.getColumns().contains(mtimeCol)) {
|
mtimeCol.setVisible(true);
|
||||||
table.getColumns().add(mtimeCol);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ownerWidth.set(fileList.getAll().getValue().stream()
|
ownerWidth.set(fileList.getAll().getValue().stream().map(browserEntry -> formatOwner(browserEntry)).map(
|
||||||
.map(browserEntry -> formatOwner(browserEntry))
|
s -> s != null ? s.length() * 9 : 0).max(Comparator.naturalOrder()).orElse(150));
|
||||||
.map(s -> s != null ? s.length() * 10 : 0)
|
ownerCol.setPrefWidth(ownerWidth.get());
|
||||||
.max(Comparator.naturalOrder()).orElse(150));
|
|
||||||
if (fileList.getFileSystemModel().getFileSystem() != null) {
|
if (fileList.getFileSystemModel().getFileSystem() != null) {
|
||||||
var shell = fileList.getFileSystemModel()
|
var shell = fileList.getFileSystemModel().getFileSystem().getShell().orElseThrow();
|
||||||
.getFileSystem()
|
if (OsType.WINDOWS.equals(shell.getOsType())) {
|
||||||
.getShell()
|
modeCol.setVisible(false);
|
||||||
.orElseThrow();
|
ownerCol.setVisible(false);
|
||||||
var notWindows = !OsType.WINDOWS.equals(shell.getOsType());
|
|
||||||
if (!notWindows) {
|
|
||||||
table.getColumns().remove(modeCol);
|
|
||||||
table.getColumns().remove(ownerCol);
|
|
||||||
} else {
|
} else {
|
||||||
if (!table.getColumns().contains(modeCol)) {
|
modeCol.setVisible(true);
|
||||||
table.getColumns().add(modeCol);
|
if (table.getWidth() > 1000) {
|
||||||
}
|
ownerCol.setVisible(true);
|
||||||
if (!table.getColumns().contains(ownerCol)) {
|
|
||||||
table.getColumns().add(table.getColumns().size() - 1, ownerCol);
|
|
||||||
} else {
|
|
||||||
table.getColumns().remove(ownerCol);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!table.getItems().equals(newItems)) {
|
|
||||||
// Sort the list ourselves as sorting the table would incur a lot of cell updates
|
// Sort the list ourselves as sorting the table would incur a lot of cell updates
|
||||||
var obs = FXCollections.observableList(newItems);
|
var obs = FXCollections.observableList(newItems);
|
||||||
table.getItems().setAll(obs);
|
table.getItems().setAll(obs);
|
||||||
}
|
|
||||||
|
|
||||||
var currentDirectory = fileList.getFileSystemModel().getCurrentDirectory();
|
var width = getFilenameWidth(table);
|
||||||
if (!Objects.equals(lastDir.get(), currentDirectory)) {
|
filenameCol.setPrefWidth(width);
|
||||||
|
|
||||||
TableViewSkin<?> skin = (TableViewSkin<?>) table.getSkin();
|
TableViewSkin<?> skin = (TableViewSkin<?>) table.getSkin();
|
||||||
if (skin != null) {
|
var currentDirectory = fileList.getFileSystemModel().getCurrentDirectory();
|
||||||
VirtualFlow<?> flow =
|
if (skin != null && !Objects.equals(lastDir.get(), currentDirectory)) {
|
||||||
(VirtualFlow<?>) skin.getChildren().get(1);
|
VirtualFlow<?> flow = (VirtualFlow<?>) skin.getChildren().get(1);
|
||||||
ScrollBar vbar =
|
ScrollBar vbar = (ScrollBar) flow.getChildrenUnmodifiable().get(2);
|
||||||
(ScrollBar) flow.getChildrenUnmodifiable().get(2);
|
|
||||||
if (vbar.getValue() != 0.0) {
|
if (vbar.getValue() != 0.0) {
|
||||||
table.scrollTo(0);
|
table.scrollTo(0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
lastDir.setValue(currentDirectory);
|
lastDir.setValue(currentDirectory);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
updateHandler.run();
|
updateHandler.run();
|
||||||
fileList.getShown().addListener((observable, oldValue, newValue) -> {
|
fileList.getShown().addListener((observable, oldValue, newValue) -> {
|
||||||
updateHandler.run();
|
updateHandler.run();
|
||||||
|
@ -606,9 +612,7 @@ public final class BrowserFileListComp extends SimpleComp {
|
||||||
.getCurrentParentDirectory());
|
.getCurrentParentDirectory());
|
||||||
return notDir || isParentLink;
|
return notDir || isParentLink;
|
||||||
},
|
},
|
||||||
itemProperty())
|
itemProperty()))
|
||||||
.not()
|
|
||||||
.not())
|
|
||||||
.focusTraversable(false)
|
.focusTraversable(false)
|
||||||
.createRegion();
|
.createRegion();
|
||||||
|
|
||||||
|
|
|
@ -5,10 +5,9 @@ import io.xpipe.core.process.CommandBuilder;
|
||||||
import io.xpipe.core.process.OsType;
|
import io.xpipe.core.process.OsType;
|
||||||
import io.xpipe.core.process.ShellControl;
|
import io.xpipe.core.process.ShellControl;
|
||||||
import io.xpipe.core.process.ShellDialect;
|
import io.xpipe.core.process.ShellDialect;
|
||||||
|
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
|
|
||||||
import java.util.HashMap;
|
import java.util.LinkedHashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
@Getter
|
@Getter
|
||||||
|
@ -16,8 +15,8 @@ public class OpenFileSystemCache extends ShellControlCache {
|
||||||
|
|
||||||
private final OpenFileSystemModel model;
|
private final OpenFileSystemModel model;
|
||||||
private final String username;
|
private final String username;
|
||||||
private final Map<Integer, String> users = new HashMap<>();
|
private final Map<Integer, String> users = new LinkedHashMap<>();
|
||||||
private final Map<Integer, String> groups = new HashMap<>();
|
private final Map<Integer, String> groups = new LinkedHashMap<>();
|
||||||
|
|
||||||
public OpenFileSystemCache(OpenFileSystemModel model) throws Exception {
|
public OpenFileSystemCache(OpenFileSystemModel model) throws Exception {
|
||||||
super(model.getFileSystem().getShell().orElseThrow());
|
super(model.getFileSystem().getShell().orElseThrow());
|
||||||
|
|
|
@ -1,46 +0,0 @@
|
||||||
package io.xpipe.app.browser.session;
|
|
||||||
|
|
||||||
import io.xpipe.app.comp.base.MultiContentComp;
|
|
||||||
import io.xpipe.app.fxcomps.Comp;
|
|
||||||
import io.xpipe.app.fxcomps.util.BindingsHelper;
|
|
||||||
import io.xpipe.app.storage.DataStoreEntryRef;
|
|
||||||
import io.xpipe.core.store.DataStore;
|
|
||||||
|
|
||||||
import javafx.beans.property.Property;
|
|
||||||
import javafx.beans.property.SimpleObjectProperty;
|
|
||||||
import javafx.beans.value.ObservableValue;
|
|
||||||
import javafx.collections.FXCollections;
|
|
||||||
import javafx.collections.ListChangeListener;
|
|
||||||
import javafx.collections.ObservableList;
|
|
||||||
|
|
||||||
import lombok.Getter;
|
|
||||||
|
|
||||||
@Getter
|
|
||||||
public class BrowserSessionMultiTab extends BrowserSessionTab<DataStore> {
|
|
||||||
|
|
||||||
protected final Property<BrowserSessionTab<?>> currentTab = new SimpleObjectProperty<>();
|
|
||||||
private final ObservableList<BrowserSessionTab<?>> allTabs = FXCollections.observableArrayList();
|
|
||||||
|
|
||||||
public BrowserSessionMultiTab(BrowserAbstractSessionModel<?> browserModel, DataStoreEntryRef<?> entry) {
|
|
||||||
super(browserModel, entry);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Comp<?> comp() {
|
|
||||||
var map = FXCollections.<Comp<?>, ObservableValue<Boolean>>observableHashMap();
|
|
||||||
allTabs.addListener((ListChangeListener<? super BrowserSessionTab<?>>) c -> {
|
|
||||||
for (BrowserSessionTab<?> a : c.getAddedSubList()) {
|
|
||||||
map.put(a.comp(), BindingsHelper.map(currentTab, browserSessionTab -> a.equals(browserSessionTab)));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
var mt = new MultiContentComp(map);
|
|
||||||
return mt;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean canImmediatelyClose() {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void init() {}
|
|
||||||
|
|
||||||
public void close() {}
|
|
||||||
}
|
|
|
@ -3,11 +3,8 @@ package io.xpipe.app.comp.base;
|
||||||
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.util.PlatformThread;
|
import io.xpipe.app.fxcomps.util.PlatformThread;
|
||||||
|
|
||||||
import javafx.beans.value.ObservableValue;
|
import javafx.beans.value.ObservableValue;
|
||||||
import javafx.collections.FXCollections;
|
import javafx.collections.FXCollections;
|
||||||
import javafx.collections.MapChangeListener;
|
|
||||||
import javafx.collections.ObservableMap;
|
|
||||||
import javafx.scene.layout.Region;
|
import javafx.scene.layout.Region;
|
||||||
import javafx.scene.layout.StackPane;
|
import javafx.scene.layout.StackPane;
|
||||||
|
|
||||||
|
@ -15,52 +12,28 @@ import java.util.Map;
|
||||||
|
|
||||||
public class MultiContentComp extends SimpleComp {
|
public class MultiContentComp extends SimpleComp {
|
||||||
|
|
||||||
private final ObservableMap<Comp<?>, ObservableValue<Boolean>> content;
|
private final Map<Comp<?>, ObservableValue<Boolean>> content;
|
||||||
|
|
||||||
public MultiContentComp(Map<Comp<?>, ObservableValue<Boolean>> content) {
|
public MultiContentComp(Map<Comp<?>, ObservableValue<Boolean>> content) {
|
||||||
this.content = FXCollections.observableMap(content);
|
this.content = FXCollections.observableMap(content);
|
||||||
}
|
}
|
||||||
|
|
||||||
public MultiContentComp(ObservableMap<Comp<?>, ObservableValue<Boolean>> content) {
|
|
||||||
this.content = content;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected Region createSimple() {
|
protected Region createSimple() {
|
||||||
ObservableMap<Comp<?>, Region> m = FXCollections.observableHashMap();
|
|
||||||
content.addListener((MapChangeListener<? super Comp<?>, ? super ObservableValue<Boolean>>) change -> {
|
|
||||||
if (change.wasAdded()) {
|
|
||||||
var r = change.getKey().createRegion();
|
|
||||||
change.getValueAdded().subscribe(val -> {
|
|
||||||
PlatformThread.runLaterIfNeeded(() -> {
|
|
||||||
r.setManaged(val);
|
|
||||||
r.setVisible(val);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
m.put(change.getKey(), r);
|
|
||||||
} else {
|
|
||||||
m.remove(change.getKey());
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
var stack = new StackPane();
|
var stack = new StackPane();
|
||||||
m.addListener((MapChangeListener<? super Comp<?>, Region>) change -> {
|
|
||||||
if (change.wasAdded()) {
|
|
||||||
stack.getChildren().add(change.getValueAdded());
|
|
||||||
} else {
|
|
||||||
stack.getChildren().remove(change.getValueRemoved());
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
for (Map.Entry<Comp<?>, ObservableValue<Boolean>> e : content.entrySet()) {
|
for (Map.Entry<Comp<?>, ObservableValue<Boolean>> e : content.entrySet()) {
|
||||||
var r = e.getKey().createRegion();
|
var r = e.getKey().createRegion();
|
||||||
e.getValue().subscribe(val -> {
|
e.getValue().subscribe(val -> {
|
||||||
PlatformThread.runLaterIfNeeded(() -> {
|
PlatformThread.runLaterIfNeeded(() -> {
|
||||||
r.setManaged(val);
|
r.setManaged(val);
|
||||||
r.setVisible(val);
|
r.setVisible(val);
|
||||||
|
if (val && !stack.getChildren().contains(r)) {
|
||||||
|
stack.getChildren().add(r);
|
||||||
|
} else {
|
||||||
|
stack.getChildren().remove(r);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
m.put(e.getKey(), r);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return stack;
|
return stack;
|
||||||
|
|
|
@ -4,13 +4,11 @@ import io.xpipe.app.core.AppI18n;
|
||||||
import io.xpipe.app.fxcomps.CompStructure;
|
import io.xpipe.app.fxcomps.CompStructure;
|
||||||
import io.xpipe.app.fxcomps.augment.Augment;
|
import io.xpipe.app.fxcomps.augment.Augment;
|
||||||
import io.xpipe.app.fxcomps.util.PlatformThread;
|
import io.xpipe.app.fxcomps.util.PlatformThread;
|
||||||
|
|
||||||
import javafx.beans.binding.Bindings;
|
import javafx.beans.binding.Bindings;
|
||||||
import javafx.beans.value.ObservableValue;
|
import javafx.beans.value.ObservableValue;
|
||||||
import javafx.scene.control.Tooltip;
|
import javafx.scene.control.Tooltip;
|
||||||
import javafx.scene.input.KeyCombination;
|
import javafx.scene.input.KeyCombination;
|
||||||
import javafx.stage.Window;
|
import javafx.stage.Window;
|
||||||
import javafx.util.Duration;
|
|
||||||
|
|
||||||
public class TooltipAugment<S extends CompStructure<?>> implements Augment<S> {
|
public class TooltipAugment<S extends CompStructure<?>> implements Augment<S> {
|
||||||
|
|
||||||
|
@ -46,7 +44,6 @@ public class TooltipAugment<S extends CompStructure<?>> implements Augment<S> {
|
||||||
tt.setWrapText(true);
|
tt.setWrapText(true);
|
||||||
tt.setMaxWidth(400);
|
tt.setMaxWidth(400);
|
||||||
tt.getStyleClass().add("fancy-tooltip");
|
tt.getStyleClass().add("fancy-tooltip");
|
||||||
tt.setHideDelay(Duration.INDEFINITE);
|
|
||||||
Tooltip.install(struc.get(), tt);
|
Tooltip.install(struc.get(), tt);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -289,11 +289,7 @@
|
||||||
-fx-font-size: 0.9em;
|
-fx-font-size: 0.9em;
|
||||||
-fx-font-weight: bolder;
|
-fx-font-weight: bolder;
|
||||||
-fx-opacity: 0.9;
|
-fx-opacity: 0.9;
|
||||||
-fx-padding: 0 0 0 12;
|
-fx-padding: 0 0 0 7;
|
||||||
}
|
|
||||||
|
|
||||||
.browser .table-row-cell {
|
|
||||||
-fx-padding: 0 0 0 5;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.browser .table-row-cell:empty {
|
.browser .table-row-cell:empty {
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
.scroll-bar:vertical {
|
.scroll-bar:vertical {
|
||||||
-fx-min-width: 7px;
|
-fx-min-width: 7px;
|
||||||
-fx-pref-width: 7px;
|
-fx-pref-width: 7px;
|
||||||
|
-fx-max-width: 7px;
|
||||||
-fx-padding: 1;
|
-fx-padding: 1;
|
||||||
-fx-background-color: transparent;
|
-fx-background-color: transparent;
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,72 @@
|
||||||
|
package io.xpipe.ext.base.browser;
|
||||||
|
|
||||||
|
import io.xpipe.app.browser.action.BranchAction;
|
||||||
|
import io.xpipe.app.browser.action.LeafAction;
|
||||||
|
import io.xpipe.app.browser.file.BrowserEntry;
|
||||||
|
import io.xpipe.app.browser.fs.OpenFileSystemModel;
|
||||||
|
import io.xpipe.app.core.AppI18n;
|
||||||
|
import io.xpipe.core.process.CommandBuilder;
|
||||||
|
import io.xpipe.core.process.OsType;
|
||||||
|
import javafx.beans.property.SimpleStringProperty;
|
||||||
|
import javafx.beans.value.ObservableValue;
|
||||||
|
import javafx.scene.Node;
|
||||||
|
import org.kordamp.ikonli.javafx.FontIcon;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class ChgrpAction implements BranchAction {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Node getIcon(OpenFileSystemModel model, List<BrowserEntry> entries) {
|
||||||
|
return new FontIcon("mdi2a-account-group-outline");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Category getCategory() {
|
||||||
|
return Category.MUTATION;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ObservableValue<String> getName(OpenFileSystemModel model, List<BrowserEntry> entries) {
|
||||||
|
return AppI18n.observable("chgrp");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isApplicable(OpenFileSystemModel model, List<BrowserEntry> entries) {
|
||||||
|
return model.getFileSystem().getShell().orElseThrow().getOsType() != OsType.WINDOWS;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<LeafAction> getBranchingActions(OpenFileSystemModel model, List<BrowserEntry> entries) {
|
||||||
|
return model.getCache().getGroups().entrySet().stream()
|
||||||
|
.filter(e -> !e.getValue().equals("nogroup") && (e.getKey().equals(0) || e.getKey() >= 1000))
|
||||||
|
.map(e -> e.getValue()).map(s -> (LeafAction) new Chgrp(s)).toList();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class Chgrp implements LeafAction {
|
||||||
|
|
||||||
|
private final String option;
|
||||||
|
|
||||||
|
private Chgrp(String option) {
|
||||||
|
this.option = option;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ObservableValue<String> getName(OpenFileSystemModel model, List<BrowserEntry> entries) {
|
||||||
|
return new SimpleStringProperty(option);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void execute(OpenFileSystemModel model, List<BrowserEntry> entries) throws Exception {
|
||||||
|
model.getFileSystem()
|
||||||
|
.getShell()
|
||||||
|
.orElseThrow()
|
||||||
|
.executeSimpleCommand(CommandBuilder.of()
|
||||||
|
.add("chgrp", option)
|
||||||
|
.addFiles(entries.stream()
|
||||||
|
.map(browserEntry ->
|
||||||
|
browserEntry.getRawFileEntry().getPath())
|
||||||
|
.toList()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,72 @@
|
||||||
|
package io.xpipe.ext.base.browser;
|
||||||
|
|
||||||
|
import io.xpipe.app.browser.action.BranchAction;
|
||||||
|
import io.xpipe.app.browser.action.LeafAction;
|
||||||
|
import io.xpipe.app.browser.file.BrowserEntry;
|
||||||
|
import io.xpipe.app.browser.fs.OpenFileSystemModel;
|
||||||
|
import io.xpipe.app.core.AppI18n;
|
||||||
|
import io.xpipe.core.process.CommandBuilder;
|
||||||
|
import io.xpipe.core.process.OsType;
|
||||||
|
import javafx.beans.property.SimpleStringProperty;
|
||||||
|
import javafx.beans.value.ObservableValue;
|
||||||
|
import javafx.scene.Node;
|
||||||
|
import org.kordamp.ikonli.javafx.FontIcon;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class ChownAction implements BranchAction {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Node getIcon(OpenFileSystemModel model, List<BrowserEntry> entries) {
|
||||||
|
return new FontIcon("mdi2a-account-edit");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Category getCategory() {
|
||||||
|
return Category.MUTATION;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ObservableValue<String> getName(OpenFileSystemModel model, List<BrowserEntry> entries) {
|
||||||
|
return AppI18n.observable("chown");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isApplicable(OpenFileSystemModel model, List<BrowserEntry> entries) {
|
||||||
|
return model.getFileSystem().getShell().orElseThrow().getOsType() != OsType.WINDOWS;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<LeafAction> getBranchingActions(OpenFileSystemModel model, List<BrowserEntry> entries) {
|
||||||
|
return model.getCache().getUsers().entrySet().stream()
|
||||||
|
.filter(e -> !e.getValue().equals("nobody") && (e.getKey().equals(0) || e.getKey() >= 1000))
|
||||||
|
.map(e -> e.getValue()).map(s -> (LeafAction) new Chown(s)).toList();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class Chown implements LeafAction {
|
||||||
|
|
||||||
|
private final String option;
|
||||||
|
|
||||||
|
private Chown(String option) {
|
||||||
|
this.option = option;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ObservableValue<String> getName(OpenFileSystemModel model, List<BrowserEntry> entries) {
|
||||||
|
return new SimpleStringProperty(option);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void execute(OpenFileSystemModel model, List<BrowserEntry> entries) throws Exception {
|
||||||
|
model.getFileSystem()
|
||||||
|
.getShell()
|
||||||
|
.orElseThrow()
|
||||||
|
.executeSimpleCommand(CommandBuilder.of()
|
||||||
|
.add("chown", option)
|
||||||
|
.addFiles(entries.stream()
|
||||||
|
.map(browserEntry ->
|
||||||
|
browserEntry.getRawFileEntry().getPath())
|
||||||
|
.toList()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -52,6 +52,8 @@ open module io.xpipe.ext.base {
|
||||||
EditFileAction,
|
EditFileAction,
|
||||||
RunAction,
|
RunAction,
|
||||||
ChmodAction,
|
ChmodAction,
|
||||||
|
ChownAction,
|
||||||
|
ChgrpAction,
|
||||||
CopyAction,
|
CopyAction,
|
||||||
CopyPathAction,
|
CopyPathAction,
|
||||||
PasteAction,
|
PasteAction,
|
||||||
|
|
3
lang/base/strings/fixed_en.properties
Normal file
3
lang/base/strings/fixed_en.properties
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
chmod=Chmod
|
||||||
|
chgrp=Chgrp
|
||||||
|
chown=Chown
|
|
@ -87,7 +87,6 @@ back=Gå tilbage
|
||||||
browseInWindowsExplorer=Gennemse i Windows explorer
|
browseInWindowsExplorer=Gennemse i Windows explorer
|
||||||
browseInDefaultFileManager=Gennemse i standard filhåndtering
|
browseInDefaultFileManager=Gennemse i standard filhåndtering
|
||||||
browseInFinder=Gennemse i finder
|
browseInFinder=Gennemse i finder
|
||||||
chmod=Chmod
|
|
||||||
copy=Kopi
|
copy=Kopi
|
||||||
paste=Indsæt
|
paste=Indsæt
|
||||||
copyLocation=Kopiér placering
|
copyLocation=Kopiér placering
|
||||||
|
|
|
@ -82,7 +82,6 @@ back=Zurückgehen
|
||||||
browseInWindowsExplorer=Blättern im Windows-Explorer
|
browseInWindowsExplorer=Blättern im Windows-Explorer
|
||||||
browseInDefaultFileManager=Blättern im Standard-Dateimanager
|
browseInDefaultFileManager=Blättern im Standard-Dateimanager
|
||||||
browseInFinder=Im Finder blättern
|
browseInFinder=Im Finder blättern
|
||||||
chmod=Chmod
|
|
||||||
#custom
|
#custom
|
||||||
copy=Kopieren
|
copy=Kopieren
|
||||||
paste=Einfügen
|
paste=Einfügen
|
||||||
|
|
|
@ -81,7 +81,6 @@ back=Go back
|
||||||
browseInWindowsExplorer=Browse in Windows explorer
|
browseInWindowsExplorer=Browse in Windows explorer
|
||||||
browseInDefaultFileManager=Browse in default file manager
|
browseInDefaultFileManager=Browse in default file manager
|
||||||
browseInFinder=Browse in finder
|
browseInFinder=Browse in finder
|
||||||
chmod=Chmod
|
|
||||||
copy=Copy
|
copy=Copy
|
||||||
paste=Paste
|
paste=Paste
|
||||||
copyLocation=Copy location
|
copyLocation=Copy location
|
||||||
|
|
|
@ -81,7 +81,6 @@ back=Volver atrás
|
||||||
browseInWindowsExplorer=Navegar en el explorador de Windows
|
browseInWindowsExplorer=Navegar en el explorador de Windows
|
||||||
browseInDefaultFileManager=Navegar en el gestor de archivos por defecto
|
browseInDefaultFileManager=Navegar en el gestor de archivos por defecto
|
||||||
browseInFinder=Navegar en el buscador
|
browseInFinder=Navegar en el buscador
|
||||||
chmod=Chmod
|
|
||||||
copy=Copia
|
copy=Copia
|
||||||
paste=Pegar
|
paste=Pegar
|
||||||
copyLocation=Ubicación de la copia
|
copyLocation=Ubicación de la copia
|
||||||
|
|
|
@ -81,7 +81,6 @@ back=Retourner
|
||||||
browseInWindowsExplorer=Naviguer dans l'explorateur Windows
|
browseInWindowsExplorer=Naviguer dans l'explorateur Windows
|
||||||
browseInDefaultFileManager=Parcourir dans le gestionnaire de fichiers par défaut
|
browseInDefaultFileManager=Parcourir dans le gestionnaire de fichiers par défaut
|
||||||
browseInFinder=Parcourir dans finder
|
browseInFinder=Parcourir dans finder
|
||||||
chmod=Chmod
|
|
||||||
copy=Copie
|
copy=Copie
|
||||||
paste=Coller
|
paste=Coller
|
||||||
copyLocation=Emplacement de la copie
|
copyLocation=Emplacement de la copie
|
||||||
|
|
|
@ -81,7 +81,6 @@ back=Torna indietro
|
||||||
browseInWindowsExplorer=Sfogliare in Windows explorer
|
browseInWindowsExplorer=Sfogliare in Windows explorer
|
||||||
browseInDefaultFileManager=Sfoglia nel file manager predefinito
|
browseInDefaultFileManager=Sfoglia nel file manager predefinito
|
||||||
browseInFinder=Sfogliare in finder
|
browseInFinder=Sfogliare in finder
|
||||||
chmod=Chmod
|
|
||||||
copy=Copia
|
copy=Copia
|
||||||
paste=Incolla
|
paste=Incolla
|
||||||
copyLocation=Posizione di copia
|
copyLocation=Posizione di copia
|
||||||
|
|
|
@ -81,7 +81,6 @@ back=戻る
|
||||||
browseInWindowsExplorer=Windowsエクスプローラでブラウズする
|
browseInWindowsExplorer=Windowsエクスプローラでブラウズする
|
||||||
browseInDefaultFileManager=デフォルトのファイルマネージャーでブラウズする
|
browseInDefaultFileManager=デフォルトのファイルマネージャーでブラウズする
|
||||||
browseInFinder=ファインダーでブラウズする
|
browseInFinder=ファインダーでブラウズする
|
||||||
chmod=Chmod
|
|
||||||
copy=コピー
|
copy=コピー
|
||||||
paste=貼り付け
|
paste=貼り付け
|
||||||
copyLocation=コピー場所
|
copyLocation=コピー場所
|
||||||
|
|
|
@ -81,7 +81,6 @@ back=Teruggaan
|
||||||
browseInWindowsExplorer=Bladeren in Windows verkenner
|
browseInWindowsExplorer=Bladeren in Windows verkenner
|
||||||
browseInDefaultFileManager=Bladeren in standaard bestandsbeheer
|
browseInDefaultFileManager=Bladeren in standaard bestandsbeheer
|
||||||
browseInFinder=Bladeren in finder
|
browseInFinder=Bladeren in finder
|
||||||
chmod=Chmod
|
|
||||||
copy=Kopiëren
|
copy=Kopiëren
|
||||||
paste=Plakken
|
paste=Plakken
|
||||||
copyLocation=Locatie kopiëren
|
copyLocation=Locatie kopiëren
|
||||||
|
|
|
@ -81,7 +81,6 @@ back=Volta atrás
|
||||||
browseInWindowsExplorer=Navega no Windows Explorer
|
browseInWindowsExplorer=Navega no Windows Explorer
|
||||||
browseInDefaultFileManager=Navega no gestor de ficheiros predefinido
|
browseInDefaultFileManager=Navega no gestor de ficheiros predefinido
|
||||||
browseInFinder=Navega no localizador
|
browseInFinder=Navega no localizador
|
||||||
chmod=Chmod
|
|
||||||
copy=Copia
|
copy=Copia
|
||||||
paste=Cola
|
paste=Cola
|
||||||
copyLocation=Copia a localização
|
copyLocation=Copia a localização
|
||||||
|
|
|
@ -81,7 +81,6 @@ back=Возвращайся назад
|
||||||
browseInWindowsExplorer=Обзор в проводнике Windows
|
browseInWindowsExplorer=Обзор в проводнике Windows
|
||||||
browseInDefaultFileManager=Обзор в файловом менеджере по умолчанию
|
browseInDefaultFileManager=Обзор в файловом менеджере по умолчанию
|
||||||
browseInFinder=Обзор в программе для поиска
|
browseInFinder=Обзор в программе для поиска
|
||||||
chmod=Chmod
|
|
||||||
copy=Скопируй
|
copy=Скопируй
|
||||||
paste=Paste
|
paste=Paste
|
||||||
copyLocation=Место копирования
|
copyLocation=Место копирования
|
||||||
|
|
|
@ -81,7 +81,6 @@ back=Geri dön
|
||||||
browseInWindowsExplorer=Windows gezgininde göz atın
|
browseInWindowsExplorer=Windows gezgininde göz atın
|
||||||
browseInDefaultFileManager=Varsayılan dosya yöneticisine göz atın
|
browseInDefaultFileManager=Varsayılan dosya yöneticisine göz atın
|
||||||
browseInFinder=Bulucuya göz atın
|
browseInFinder=Bulucuya göz atın
|
||||||
chmod=Chmod
|
|
||||||
copy=Anlaşıldı
|
copy=Anlaşıldı
|
||||||
paste=Yapıştır
|
paste=Yapıştır
|
||||||
copyLocation=Kopyalama konumu
|
copyLocation=Kopyalama konumu
|
||||||
|
|
|
@ -81,7 +81,6 @@ back=返回
|
||||||
browseInWindowsExplorer=在 Windows 资源管理器中浏览
|
browseInWindowsExplorer=在 Windows 资源管理器中浏览
|
||||||
browseInDefaultFileManager=在默认文件管理器中浏览
|
browseInDefaultFileManager=在默认文件管理器中浏览
|
||||||
browseInFinder=在查找器中浏览
|
browseInFinder=在查找器中浏览
|
||||||
chmod=Chmod
|
|
||||||
copy=复制
|
copy=复制
|
||||||
paste=粘贴
|
paste=粘贴
|
||||||
copyLocation=复制位置
|
copyLocation=复制位置
|
||||||
|
|
Loading…
Reference in a new issue