This commit is contained in:
crschnick 2024-08-24 12:42:06 +00:00
parent d6cb3bf2bd
commit 27e6fc10e0
40 changed files with 284 additions and 177 deletions

View file

@ -63,9 +63,7 @@ public class BrowserOverviewComp extends SimpleComp {
var commonPane = new SimpleTitledPaneComp(AppI18n.observable("common"), commonOverview) var commonPane = new SimpleTitledPaneComp(AppI18n.observable("common"), commonOverview)
.apply(struc -> VBox.setVgrow(struc.get(), Priority.NEVER)); .apply(struc -> VBox.setVgrow(struc.get(), Priority.NEVER));
var roots = model.getFileSystem() var roots = model.getFileSystem().listRoots().stream()
.listRoots()
.stream()
.map(s -> FileEntry.ofDirectory(model.getFileSystem(), s)) .map(s -> FileEntry.ofDirectory(model.getFileSystem(), s))
.toList(); .toList();
var rootsOverview = new BrowserFileOverviewComp(model, FXCollections.observableArrayList(roots), false); var rootsOverview = new BrowserFileOverviewComp(model, FXCollections.observableArrayList(roots), false);

View file

@ -5,6 +5,7 @@ import io.xpipe.app.browser.icon.BrowserIconFileType;
import io.xpipe.core.store.FileEntry; import io.xpipe.core.store.FileEntry;
import io.xpipe.core.store.FileKind; import io.xpipe.core.store.FileKind;
import io.xpipe.core.store.FileNames; import io.xpipe.core.store.FileNames;
import lombok.Getter; import lombok.Getter;
@Getter @Getter

View file

@ -1,7 +1,5 @@
package io.xpipe.app.browser.file; package io.xpipe.app.browser.file;
import atlantafx.base.controls.Spacer;
import atlantafx.base.theme.Styles;
import io.xpipe.app.browser.action.BrowserAction; import io.xpipe.app.browser.action.BrowserAction;
import io.xpipe.app.comp.base.LazyTextFieldComp; import io.xpipe.app.comp.base.LazyTextFieldComp;
import io.xpipe.app.core.AppI18n; import io.xpipe.app.core.AppI18n;
@ -14,6 +12,7 @@ import io.xpipe.core.store.FileEntry;
import io.xpipe.core.store.FileInfo; import io.xpipe.core.store.FileInfo;
import io.xpipe.core.store.FileKind; import io.xpipe.core.store.FileKind;
import io.xpipe.core.store.FileNames; import io.xpipe.core.store.FileNames;
import javafx.application.Platform; import javafx.application.Platform;
import javafx.beans.binding.Bindings; import javafx.beans.binding.Bindings;
import javafx.beans.property.*; import javafx.beans.property.*;
@ -34,6 +33,9 @@ import javafx.scene.layout.HBox;
import javafx.scene.layout.Priority; import javafx.scene.layout.Priority;
import javafx.scene.layout.Region; import javafx.scene.layout.Region;
import atlantafx.base.controls.Spacer;
import atlantafx.base.theme.Styles;
import java.time.Duration; import java.time.Duration;
import java.time.Instant; import java.time.Instant;
import java.time.ZoneId; import java.time.ZoneId;
@ -104,7 +106,9 @@ public final class BrowserFileListComp extends SimpleComp {
var modeCol = new TableColumn<BrowserEntry, String>(); var modeCol = new TableColumn<BrowserEntry, String>();
modeCol.textProperty().bind(AppI18n.observable("attributes")); modeCol.textProperty().bind(AppI18n.observable("attributes"));
modeCol.setCellValueFactory(param -> new SimpleObjectProperty<>( modeCol.setCellValueFactory(param -> new SimpleObjectProperty<>(
param.getValue().getRawFileEntry().resolved().getInfo() instanceof FileInfo.Unix u ? u.getPermissions() : null)); param.getValue().getRawFileEntry().resolved().getInfo() instanceof FileInfo.Unix u
? u.getPermissions()
: null));
modeCol.setCellFactory(col -> new FileModeCell()); modeCol.setCellFactory(col -> new FileModeCell());
modeCol.setResizable(false); modeCol.setResizable(false);
modeCol.setPrefWidth(120); modeCol.setPrefWidth(120);
@ -134,7 +138,11 @@ public final class BrowserFileListComp extends SimpleComp {
return true; return true;
}); });
table.setFixedCellSize(32.0); table.setFixedCellSize(32.0);
var os = fileList.getFileSystemModel().getFileSystem().getShell().orElseThrow().getOsType(); var os = fileList.getFileSystemModel()
.getFileSystem()
.getShell()
.orElseThrow()
.getOsType();
table.widthProperty().subscribe((newValue) -> { table.widthProperty().subscribe((newValue) -> {
if (os != OsType.WINDOWS && os != OsType.MACOS) { if (os != OsType.WINDOWS && os != OsType.MACOS) {
ownerCol.setVisible(newValue.doubleValue() > 1000); ownerCol.setVisible(newValue.doubleValue() > 1000);
@ -143,12 +151,15 @@ public final class BrowserFileListComp extends SimpleComp {
filenameCol.setPrefWidth(width); filenameCol.setPrefWidth(width);
}); });
table.lookupAll(".scroll-bar").stream().filter(node -> node.getPseudoClassStates().contains(PseudoClass.getPseudoClass("horizontal"))).findFirst().ifPresent(node -> { table.lookupAll(".scroll-bar").stream()
Region region = (Region) node; .filter(node -> node.getPseudoClassStates().contains(PseudoClass.getPseudoClass("horizontal")))
region.setMinHeight(0); .findFirst()
region.setPrefHeight(0); .ifPresent(node -> {
region.setMaxHeight(0); Region region = (Region) node;
}); region.setMinHeight(0);
region.setPrefHeight(0);
region.setMaxHeight(0);
});
prepareTableSelectionModel(table); prepareTableSelectionModel(table);
prepareTableShortcuts(table); prepareTableShortcuts(table);
@ -160,9 +171,12 @@ public final class BrowserFileListComp extends SimpleComp {
} }
private double getFilenameWidth(TableView<?> tableView) { private double getFilenameWidth(TableView<?> tableView) {
var sum = tableView.getColumns().stream().filter(tableColumn -> tableColumn.isVisible() && var sum = tableView.getColumns().stream()
tableView.getColumns().indexOf(tableColumn) != 0) .filter(tableColumn -> tableColumn.isVisible()
.mapToDouble(value -> value.getPrefWidth()).sum() + 7; && tableView.getColumns().indexOf(tableColumn) != 0)
.mapToDouble(value -> value.getPrefWidth())
.sum()
+ 7;
return tableView.getWidth() - sum; return tableView.getWidth() - sum;
} }
@ -173,10 +187,18 @@ public final class BrowserFileListComp extends SimpleComp {
} }
var m = fileList.getFileSystemModel(); var m = fileList.getFileSystemModel();
var user = unix.getUser() != null ? unix.getUser() : m.getCache().getUsers().get(unix.getUid()); var user = unix.getUser() != null
var group = unix.getGroup() != null ? unix.getGroup() : m.getCache().getGroups().get(unix.getGid()); ? unix.getUser()
var uid = String.valueOf(unix.getUid() != null ? unix.getUid() : m.getCache().getUidForUser(user)).replaceAll("000$", "k"); : m.getCache().getUsers().get(unix.getUid());
var gid = String.valueOf(unix.getGid() != null ? unix.getGid() : m.getCache().getGidForGroup(group)).replaceAll("000$", "k"); var group = unix.getGroup() != null
? unix.getGroup()
: m.getCache().getGroups().get(unix.getGid());
var uid = String.valueOf(
unix.getUid() != null ? unix.getUid() : m.getCache().getUidForUser(user))
.replaceAll("000$", "k");
var gid = String.valueOf(
unix.getGid() != null ? unix.getGid() : m.getCache().getGidForGroup(group))
.replaceAll("000$", "k");
if (uid.equals(gid)) { if (uid.equals(gid)) {
return user + " [" + uid + "]"; return user + " [" + uid + "]";
} }
@ -428,19 +450,27 @@ public final class BrowserFileListComp extends SimpleComp {
var newItems = new ArrayList<>(fileList.getShown().getValue()); var newItems = new ArrayList<>(fileList.getShown().getValue());
table.getItems().clear(); table.getItems().clear();
var hasModifiedDate = newItems.size() == 0 || newItems.stream().anyMatch(entry -> entry.getRawFileEntry().getDate() != null); var hasModifiedDate = newItems.size() == 0
|| newItems.stream()
.anyMatch(entry -> entry.getRawFileEntry().getDate() != null);
if (!hasModifiedDate) { if (!hasModifiedDate) {
mtimeCol.setVisible(false); mtimeCol.setVisible(false);
} else { } else {
mtimeCol.setVisible(true); mtimeCol.setVisible(true);
} }
ownerWidth.set(fileList.getAll().getValue().stream().map(browserEntry -> formatOwner(browserEntry)).map( ownerWidth.set(fileList.getAll().getValue().stream()
s -> s != null ? s.length() * 9 : 0).max(Comparator.naturalOrder()).orElse(150)); .map(browserEntry -> formatOwner(browserEntry))
.map(s -> s != null ? s.length() * 9 : 0)
.max(Comparator.naturalOrder())
.orElse(150));
ownerCol.setPrefWidth(ownerWidth.get()); ownerCol.setPrefWidth(ownerWidth.get());
if (fileList.getFileSystemModel().getFileSystem() != null) { if (fileList.getFileSystemModel().getFileSystem() != null) {
var shell = fileList.getFileSystemModel().getFileSystem().getShell().orElseThrow(); var shell = fileList.getFileSystemModel()
.getFileSystem()
.getShell()
.orElseThrow();
if (OsType.WINDOWS.equals(shell.getOsType()) || OsType.MACOS.equals(shell.getOsType())) { if (OsType.WINDOWS.equals(shell.getOsType()) || OsType.MACOS.equals(shell.getOsType())) {
modeCol.setVisible(false); modeCol.setVisible(false);
ownerCol.setVisible(false); ownerCol.setVisible(false);
@ -601,18 +631,14 @@ public final class BrowserFileListComp extends SimpleComp {
var quickAccess = new BrowserQuickAccessButtonComp( var quickAccess = new BrowserQuickAccessButtonComp(
() -> getTableRow().getItem(), fileList.getFileSystemModel()) () -> getTableRow().getItem(), fileList.getFileSystemModel())
.hide(Bindings.createBooleanBinding( .hide(Bindings.createBooleanBinding(
() -> { () -> {
var item = getTableRow().getItem(); var item = getTableRow().getItem();
var notDir = item.getRawFileEntry() var notDir = item.getRawFileEntry().resolved().getKind() != FileKind.DIRECTORY;
.resolved() var isParentLink = item.getRawFileEntry()
.getKind() .equals(fileList.getFileSystemModel().getCurrentParentDirectory());
!= FileKind.DIRECTORY; return notDir || isParentLink;
var isParentLink = item.getRawFileEntry() },
.equals(fileList.getFileSystemModel() itemProperty()))
.getCurrentParentDirectory());
return notDir || isParentLink;
},
itemProperty()))
.focusTraversable(false) .focusTraversable(false)
.createRegion(); .createRegion();
@ -719,7 +745,9 @@ public final class BrowserFileListComp extends SimpleComp {
.getPath() .getPath()
: getTableRow().getItem().getFileName(); : getTableRow().getItem().getFileName();
var fileName = normalName; var fileName = normalName;
var hidden = getTableRow().getItem().getRawFileEntry().getInfo().explicitlyHidden() || fileName.startsWith("."); var hidden =
getTableRow().getItem().getRawFileEntry().getInfo().explicitlyHidden()
|| fileName.startsWith(".");
getTableRow().pseudoClassStateChanged(HIDDEN, hidden); getTableRow().pseudoClassStateChanged(HIDDEN, hidden);
text.set(fileName); text.set(fileName);
// Visibility seems to be bugged, so use opacity // Visibility seems to be bugged, so use opacity

View file

@ -99,7 +99,8 @@ public final class BrowserFileListModel {
} }
public BrowserEntry rename(BrowserEntry old, String newName) { public BrowserEntry rename(BrowserEntry old, String newName) {
if (old == null || newName == null if (old == null
|| newName == null
|| fileSystemModel == null || fileSystemModel == null
|| fileSystemModel.isClosed() || fileSystemModel.isClosed()
|| fileSystemModel.getCurrentPath().get() == null) { || fileSystemModel.getCurrentPath().get() == null) {

View file

@ -222,11 +222,7 @@ public class BrowserFileTransferOperation {
} }
private void transfer( private void transfer(
FileEntry sourceFile, FileEntry sourceFile, String targetFile, AtomicLong transferred, AtomicLong totalSize, Instant start)
String targetFile,
AtomicLong transferred,
AtomicLong totalSize,
Instant start)
throws Exception { throws Exception {
InputStream inputStream = null; InputStream inputStream = null;
OutputStream outputStream = null; OutputStream outputStream = null;

View file

@ -5,6 +5,7 @@ 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.LinkedHashMap; import java.util.LinkedHashMap;
@ -31,11 +32,19 @@ public class OpenFileSystemCache extends ShellControlCache {
} }
public int getUidForUser(String name) { public int getUidForUser(String name) {
return users.entrySet().stream().filter(e -> e.getValue().equals(name)).findFirst().map(e -> e.getKey()).orElse(0); return users.entrySet().stream()
.filter(e -> e.getValue().equals(name))
.findFirst()
.map(e -> e.getKey())
.orElse(0);
} }
public int getGidForGroup(String name) { public int getGidForGroup(String name) {
return groups.entrySet().stream().filter(e -> e.getValue().equals(name)).findFirst().map(e -> e.getKey()).orElse(0); return groups.entrySet().stream()
.filter(e -> e.getValue().equals(name))
.findFirst()
.map(e -> e.getKey())
.orElse(0);
} }
private void loadUsers() throws Exception { private void loadUsers() throws Exception {
@ -44,7 +53,9 @@ public class OpenFileSystemCache extends ShellControlCache {
return; return;
} }
var lines = sc.command(CommandBuilder.of().add("cat").addFile("/etc/passwd")).readStdoutIfPossible().orElse(""); var lines = sc.command(CommandBuilder.of().add("cat").addFile("/etc/passwd"))
.readStdoutIfPossible()
.orElse("");
lines.lines().forEach(s -> { lines.lines().forEach(s -> {
var split = s.split(":"); var split = s.split(":");
users.putIfAbsent(Integer.parseInt(split[2]), split[0]); users.putIfAbsent(Integer.parseInt(split[2]), split[0]);
@ -61,7 +72,9 @@ public class OpenFileSystemCache extends ShellControlCache {
return; return;
} }
var lines = sc.command(CommandBuilder.of().add("cat").addFile("/etc/group")).readStdoutIfPossible().orElse(""); var lines = sc.command(CommandBuilder.of().add("cat").addFile("/etc/group"))
.readStdoutIfPossible()
.orElse("");
lines.lines().forEach(s -> { lines.lines().forEach(s -> {
var split = s.split(":"); var split = s.split(":");
groups.putIfAbsent(Integer.parseInt(split[2]), split[0]); groups.putIfAbsent(Integer.parseInt(split[2]), split[0]);

View file

@ -305,8 +305,7 @@ public final class OpenFileSystemModel extends BrowserSessionTab<FileSystemStore
loadFilesSync(path); loadFilesSync(path);
} }
public void withFiles(String dir, FailableConsumer<Stream<FileEntry>, Exception> consumer) public void withFiles(String dir, FailableConsumer<Stream<FileEntry>, Exception> consumer) throws Exception {
throws Exception {
BooleanScope.executeExclusive(busy, () -> { BooleanScope.executeExclusive(busy, () -> {
if (dir != null) { if (dir != null) {
startIfNeeded(); startIfNeeded();
@ -357,8 +356,7 @@ public final class OpenFileSystemModel extends BrowserSessionTab<FileSystemStore
}); });
} }
public void dropFilesIntoAsync( public void dropFilesIntoAsync(FileEntry target, List<FileEntry> files, BrowserFileTransferMode mode) {
FileEntry target, List<FileEntry> files, BrowserFileTransferMode mode) {
// We don't have to do anything in this case // We don't have to do anything in this case
if (files.isEmpty()) { if (files.isEmpty()) {
return; return;

View file

@ -3,8 +3,8 @@ package io.xpipe.app.browser.icon;
import io.xpipe.app.core.AppResources; import io.xpipe.app.core.AppResources;
import io.xpipe.core.store.FileEntry; import io.xpipe.core.store.FileEntry;
import io.xpipe.core.store.FileKind; import io.xpipe.core.store.FileKind;
import io.xpipe.core.store.FileNames; import io.xpipe.core.store.FileNames;
import lombok.Getter; import lombok.Getter;
import java.io.BufferedReader; import java.io.BufferedReader;

View file

@ -3,8 +3,8 @@ package io.xpipe.app.browser.icon;
import io.xpipe.app.core.AppResources; import io.xpipe.app.core.AppResources;
import io.xpipe.core.store.FileEntry; import io.xpipe.core.store.FileEntry;
import io.xpipe.core.store.FileKind; import io.xpipe.core.store.FileKind;
import io.xpipe.core.store.FileNames; import io.xpipe.core.store.FileNames;
import lombok.Getter; import lombok.Getter;
import java.io.BufferedReader; import java.io.BufferedReader;
@ -86,9 +86,7 @@ public abstract class BrowserIconFileType {
var name = FileNames.getFileName(entry.getPath()); var name = FileNames.getFileName(entry.getPath());
var ext = FileNames.getExtension(entry.getPath()); var ext = FileNames.getExtension(entry.getPath());
return (ext != null return (ext != null && endings.contains("." + ext.toLowerCase(Locale.ROOT))) || endings.contains(name);
&& endings.contains("." + ext.toLowerCase(Locale.ROOT)))
|| endings.contains(name);
} }
@Override @Override

View file

@ -364,7 +364,8 @@ public class BrowserSessionTabsComp extends SimpleComp {
StackPane c = (StackPane) tabs.lookup("#" + id + " .tab-container"); StackPane c = (StackPane) tabs.lookup("#" + id + " .tab-container");
c.getStyleClass().add("color-box"); c.getStyleClass().add("color-box");
var color = DataStorage.get().getEffectiveColor(model.getEntry().get()); var color =
DataStorage.get().getEffectiveColor(model.getEntry().get());
if (color != null) { if (color != null) {
c.getStyleClass().add(color.getId()); c.getStyleClass().add(color.getId());
} }

View file

@ -47,25 +47,25 @@ public class MultiContentComp extends SimpleComp {
return stack; return stack;
} }
// Lazy impl // Lazy impl
// @Override // @Override
// protected Region createSimple() { // protected Region createSimple() {
// var stack = new StackPane(); // var stack = new StackPane();
// 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)) { // if (val && !stack.getChildren().contains(r)) {
// stack.getChildren().add(r); // stack.getChildren().add(r);
// } else { // } else {
// stack.getChildren().remove(r); // stack.getChildren().remove(r);
// } // }
// }); // });
// }); // });
// } // }
// //
// return stack; // return stack;
// } // }
} }

View file

@ -83,21 +83,30 @@ public class SideMenuBarComp extends Comp<CompStructure<VBox>> {
b.accessibleText(e.name()); b.accessibleText(e.name());
var indicator = Comp.empty().styleClass("indicator"); var indicator = Comp.empty().styleClass("indicator");
var stack = new StackComp(List.of(indicator, b)).apply(struc -> struc.get().setAlignment(Pos.CENTER_RIGHT)); var stack = new StackComp(List.of(indicator, b))
.apply(struc -> struc.get().setAlignment(Pos.CENTER_RIGHT));
stack.apply(struc -> { stack.apply(struc -> {
var indicatorRegion = (Region) struc.get().getChildren().getFirst(); var indicatorRegion = (Region) struc.get().getChildren().getFirst();
indicatorRegion.setMaxWidth(7); indicatorRegion.setMaxWidth(7);
indicatorRegion.backgroundProperty().bind(Bindings.createObjectBinding(() -> { indicatorRegion
if (value.getValue().equals(e)) { .backgroundProperty()
return selectedBorder.get(); .bind(Bindings.createObjectBinding(
} () -> {
if (value.getValue().equals(e)) {
return selectedBorder.get();
}
if (struc.get().isHover()) { if (struc.get().isHover()) {
return hoverBorder.get(); return hoverBorder.get();
} }
return noneBorder.get(); return noneBorder.get();
}, struc.get().hoverProperty(), value, hoverBorder, selectedBorder, noneBorder)); },
struc.get().hoverProperty(),
value,
hoverBorder,
selectedBorder,
noneBorder));
}); });
if (shortcut != null) { if (shortcut != null) {
stack.apply(struc -> struc.get().getProperties().put("shortcut", shortcut)); stack.apply(struc -> struc.get().getProperties().put("shortcut", shortcut));

View file

@ -58,14 +58,9 @@ public class StoreToggleComp extends SimpleComp {
ObservableValue<LabelGraphic> g = val.map(aBoolean -> aBoolean ObservableValue<LabelGraphic> g = val.map(aBoolean -> aBoolean
? new LabelGraphic.IconGraphic("mdi2c-circle-slice-8") ? new LabelGraphic.IconGraphic("mdi2c-circle-slice-8")
: new LabelGraphic.IconGraphic("mdi2p-power")); : new LabelGraphic.IconGraphic("mdi2p-power"));
var t = new StoreToggleComp( var t = new StoreToggleComp(nameKey, g, section, value, v -> {
nameKey, setter.accept(section.getWrapper().getEntry().getStore().asNeeded(), v);
g, });
section,
value,
v -> {
setter.accept(section.getWrapper().getEntry().getStore().asNeeded(), v);
});
t.tooltipKey("enabled"); t.tooltipKey("enabled");
t.value.subscribe((newValue) -> { t.value.subscribe((newValue) -> {
val.set(newValue); val.set(newValue);

View file

@ -3,10 +3,10 @@ package io.xpipe.app.comp.store;
import io.xpipe.app.core.AppI18n; import io.xpipe.app.core.AppI18n;
import io.xpipe.app.fxcomps.util.PlatformThread; import io.xpipe.app.fxcomps.util.PlatformThread;
import io.xpipe.app.prefs.AppPrefs; import io.xpipe.app.prefs.AppPrefs;
import io.xpipe.app.storage.DataColor;
import io.xpipe.app.storage.DataStorage; import io.xpipe.app.storage.DataStorage;
import io.xpipe.app.storage.DataStoreCategory; import io.xpipe.app.storage.DataStoreCategory;
import io.xpipe.app.storage.DataColor;
import javafx.beans.property.*; import javafx.beans.property.*;
import javafx.collections.FXCollections; import javafx.collections.FXCollections;
import javafx.collections.ObservableList; import javafx.collections.ObservableList;

View file

@ -16,8 +16,8 @@ import io.xpipe.app.fxcomps.util.BindingsHelper;
import io.xpipe.app.fxcomps.util.DerivedObservableList; import io.xpipe.app.fxcomps.util.DerivedObservableList;
import io.xpipe.app.fxcomps.util.PlatformThread; import io.xpipe.app.fxcomps.util.PlatformThread;
import io.xpipe.app.prefs.AppPrefs; import io.xpipe.app.prefs.AppPrefs;
import io.xpipe.app.storage.DataStorage;
import io.xpipe.app.storage.DataColor; import io.xpipe.app.storage.DataColor;
import io.xpipe.app.storage.DataStorage;
import io.xpipe.app.storage.DataStoreEntry; import io.xpipe.app.storage.DataStoreEntry;
import io.xpipe.app.update.XPipeDistributionType; import io.xpipe.app.update.XPipeDistributionType;
import io.xpipe.app.util.*; import io.xpipe.app.util.*;

View file

@ -4,9 +4,9 @@ import io.xpipe.app.ext.ActionProvider;
import io.xpipe.app.fxcomps.util.PlatformThread; import io.xpipe.app.fxcomps.util.PlatformThread;
import io.xpipe.app.issue.ErrorEvent; import io.xpipe.app.issue.ErrorEvent;
import io.xpipe.app.prefs.AppPrefs; import io.xpipe.app.prefs.AppPrefs;
import io.xpipe.app.storage.DataColor;
import io.xpipe.app.storage.DataStorage; import io.xpipe.app.storage.DataStorage;
import io.xpipe.app.storage.DataStoreCategory; import io.xpipe.app.storage.DataStoreCategory;
import io.xpipe.app.storage.DataColor;
import io.xpipe.app.storage.DataStoreEntry; import io.xpipe.app.storage.DataStoreEntry;
import io.xpipe.app.util.ThreadHelper; import io.xpipe.app.util.ThreadHelper;

View file

@ -9,10 +9,10 @@ import io.xpipe.app.util.PlatformState;
import io.xpipe.app.util.ThreadHelper; import io.xpipe.app.util.ThreadHelper;
import io.xpipe.core.process.OsType; import io.xpipe.core.process.OsType;
import javax.imageio.ImageIO;
import java.awt.*; import java.awt.*;
import java.awt.desktop.*; import java.awt.desktop.*;
import java.util.List; import java.util.List;
import javax.imageio.ImageIO;
public class AppDesktopIntegration { public class AppDesktopIntegration {

View file

@ -2,8 +2,10 @@ package io.xpipe.app.core;
import io.xpipe.app.issue.ErrorEvent; import io.xpipe.app.issue.ErrorEvent;
import io.xpipe.app.issue.TrackEvent; import io.xpipe.app.issue.TrackEvent;
import javafx.scene.image.Image; import javafx.scene.image.Image;
import javafx.scene.image.WritableImage; import javafx.scene.image.WritableImage;
import org.apache.commons.io.FilenameUtils; import org.apache.commons.io.FilenameUtils;
import java.awt.image.BufferedImage; import java.awt.image.BufferedImage;

View file

@ -10,6 +10,7 @@ import io.xpipe.app.storage.DataStoreEntry;
import io.xpipe.app.util.ThreadHelper; import io.xpipe.app.util.ThreadHelper;
import io.xpipe.core.store.EnabledStoreState; import io.xpipe.core.store.EnabledStoreState;
import io.xpipe.core.store.StatefulDataStore; import io.xpipe.core.store.StatefulDataStore;
import javafx.beans.property.SimpleBooleanProperty; import javafx.beans.property.SimpleBooleanProperty;
public interface EnabledParentStoreProvider extends DataStoreProvider { public interface EnabledParentStoreProvider extends DataStoreProvider {
@ -32,11 +33,14 @@ public interface EnabledParentStoreProvider extends DataStoreProvider {
var state = s.getState().toBuilder().enabled(aBoolean).build(); var state = s.getState().toBuilder().enabled(aBoolean).build();
s.setState(state); s.setState(state);
var children = DataStorage.get().getStoreChildren(sec.getWrapper().getEntry()); var children =
DataStorage.get().getStoreChildren(sec.getWrapper().getEntry());
ThreadHelper.runFailableAsync(() -> { ThreadHelper.runFailableAsync(() -> {
for (DataStoreEntry child : children) { for (DataStoreEntry child : children) {
if (child.getStorePersistentState() instanceof EnabledStoreState enabledStoreState) { if (child.getStorePersistentState() instanceof EnabledStoreState enabledStoreState) {
child.setStorePersistentState(enabledStoreState.toBuilder().enabled(aBoolean).build()); child.setStorePersistentState(enabledStoreState.toBuilder()
.enabled(aBoolean)
.build());
} }
} }
}); });

View file

@ -17,6 +17,7 @@ import io.xpipe.app.storage.DataStorage;
import io.xpipe.app.storage.DataStoreCategory; import io.xpipe.app.storage.DataStoreCategory;
import io.xpipe.app.util.ContextMenuHelper; import io.xpipe.app.util.ContextMenuHelper;
import io.xpipe.app.util.DataStoreFormatter; import io.xpipe.app.util.DataStoreFormatter;
import javafx.beans.binding.Bindings; import javafx.beans.binding.Bindings;
import javafx.beans.property.SimpleBooleanProperty; import javafx.beans.property.SimpleBooleanProperty;
import javafx.css.PseudoClass; import javafx.css.PseudoClass;
@ -31,6 +32,7 @@ import javafx.scene.input.KeyCodeCombination;
import javafx.scene.input.KeyEvent; import javafx.scene.input.KeyEvent;
import javafx.scene.input.MouseButton; import javafx.scene.input.MouseButton;
import javafx.scene.layout.Region; import javafx.scene.layout.Region;
import lombok.EqualsAndHashCode; import lombok.EqualsAndHashCode;
import lombok.Value; import lombok.Value;
import org.kordamp.ikonli.javafx.FontIcon; import org.kordamp.ikonli.javafx.FontIcon;
@ -57,13 +59,15 @@ public class StoreCategoryComp extends SimpleComp {
var expandIcon = Bindings.createStringBinding( var expandIcon = Bindings.createStringBinding(
() -> { () -> {
var exp = category.getExpanded().get() && category.getChildren().size() > 0; var exp = category.getExpanded().get()
&& category.getChildren().size() > 0;
return exp ? "mdal-keyboard_arrow_down" : "mdal-keyboard_arrow_right"; return exp ? "mdal-keyboard_arrow_down" : "mdal-keyboard_arrow_right";
}, },
category.getExpanded(), category.getChildren()); category.getExpanded(),
category.getChildren());
var expandButton = new IconButtonComp(expandIcon, () -> { var expandButton = new IconButtonComp(expandIcon, () -> {
category.toggleExpanded(); category.toggleExpanded();
}) })
.apply(struc -> AppFont.medium(struc.get())) .apply(struc -> AppFont.medium(struc.get()))
.apply(struc -> { .apply(struc -> {
struc.get().setAlignment(Pos.CENTER); struc.get().setAlignment(Pos.CENTER);
@ -87,7 +91,8 @@ public class StoreCategoryComp extends SimpleComp {
return category.getShare().getValue() ? "mdi2g-git" : "mdi2a-account-cancel"; return category.getShare().getValue() ? "mdi2g-git" : "mdi2a-account-cancel";
}, },
category.getShare(), hover); category.getShare(),
hover);
var statusButton = new IconButtonComp(statusIcon) var statusButton = new IconButtonComp(statusIcon)
.apply(struc -> AppFont.small(struc.get())) .apply(struc -> AppFont.small(struc.get()))
.apply(struc -> { .apply(struc -> {
@ -98,10 +103,10 @@ public class StoreCategoryComp extends SimpleComp {
}) })
.apply(new ContextMenuAugment<>( .apply(new ContextMenuAugment<>(
mouseEvent -> mouseEvent.getButton() == MouseButton.PRIMARY, null, () -> { mouseEvent -> mouseEvent.getButton() == MouseButton.PRIMARY, null, () -> {
var cm = createContextMenu(name); var cm = createContextMenu(name);
showing.bind(cm.showingProperty()); showing.bind(cm.showingProperty());
return cm; return cm;
})) }))
.styleClass("status-button"); .styleClass("status-button");
var shownList = new DerivedObservableList<>(category.getContainedEntries(), true) var shownList = new DerivedObservableList<>(category.getContainedEntries(), true)
@ -114,7 +119,8 @@ public class StoreCategoryComp extends SimpleComp {
.getList(); .getList();
var count = new CountComp<>(shownList, category.getContainedEntries(), string -> "(" + string + ")"); var count = new CountComp<>(shownList, category.getContainedEntries(), string -> "(" + string + ")");
var showStatus = hover.or(new SimpleBooleanProperty(DataStorage.get().supportsSharing())).or(showing); var showStatus = hover.or(new SimpleBooleanProperty(DataStorage.get().supportsSharing()))
.or(showing);
var focus = new SimpleBooleanProperty(); var focus = new SimpleBooleanProperty();
var h = new HorizontalComp(List.of( var h = new HorizontalComp(List.of(
expandButton, expandButton,
@ -153,9 +159,13 @@ public class StoreCategoryComp extends SimpleComp {
new ListBoxViewComp<>(l, l, storeCategoryWrapper -> new StoreCategoryComp(storeCategoryWrapper), false); new ListBoxViewComp<>(l, l, storeCategoryWrapper -> new StoreCategoryComp(storeCategoryWrapper), false);
children.styleClass("children"); children.styleClass("children");
var hide = Bindings.createBooleanBinding(() -> { var hide = Bindings.createBooleanBinding(
return !category.getExpanded().get() || category.getChildren().isEmpty(); () -> {
}, category.getChildren(), category.getExpanded()); return !category.getExpanded().get()
|| category.getChildren().isEmpty();
},
category.getChildren(),
category.getExpanded());
var v = new VerticalComp(List.of(categoryButton, children.hide(hide))); var v = new VerticalComp(List.of(categoryButton, children.hide(hide)));
v.styleClass("category"); v.styleClass("category");
v.apply(struc -> { v.apply(struc -> {

View file

@ -4,6 +4,7 @@ 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;

View file

@ -46,7 +46,9 @@ public abstract class LabelGraphic {
@Override @Override
public Node createGraphicNode() { public Node createGraphicNode() {
return PrettyImageHelper.ofFixedSizeSquare(file, size).styleClass("graphic").createRegion(); return PrettyImageHelper.ofFixedSizeSquare(file, size)
.styleClass("graphic")
.createRegion();
} }
} }

View file

@ -1,8 +1,5 @@
package io.xpipe.app.issue; package io.xpipe.app.issue;
import io.sentry.*;
import io.sentry.protocol.SentryId;
import io.sentry.protocol.User;
import io.xpipe.app.core.AppLogs; import io.xpipe.app.core.AppLogs;
import io.xpipe.app.core.AppProperties; import io.xpipe.app.core.AppProperties;
import io.xpipe.app.core.AppState; import io.xpipe.app.core.AppState;
@ -10,6 +7,10 @@ import io.xpipe.app.core.mode.OperationMode;
import io.xpipe.app.prefs.AppPrefs; import io.xpipe.app.prefs.AppPrefs;
import io.xpipe.app.update.XPipeDistributionType; import io.xpipe.app.update.XPipeDistributionType;
import io.xpipe.app.util.LicenseProvider; import io.xpipe.app.util.LicenseProvider;
import io.sentry.*;
import io.sentry.protocol.SentryId;
import io.sentry.protocol.User;
import org.apache.commons.io.FileUtils; import org.apache.commons.io.FileUtils;
import java.io.ByteArrayInputStream; import java.io.ByteArrayInputStream;
@ -163,7 +164,9 @@ public class SentryErrorHandler implements ErrorHandler {
s.setTag("licenseRequired", Boolean.toString(ee.isLicenseRequired())); s.setTag("licenseRequired", Boolean.toString(ee.isLicenseRequired()));
var exMessage = ee.getThrowable() != null ? ee.getThrowable().getMessage() : null; var exMessage = ee.getThrowable() != null ? ee.getThrowable().getMessage() : null;
if (ee.getDescription() != null && !ee.getDescription().equals(exMessage) && (ee.isShouldSendDiagnostics() || ee.isLicenseRequired())) { if (ee.getDescription() != null
&& !ee.getDescription().equals(exMessage)
&& (ee.isShouldSendDiagnostics() || ee.isLicenseRequired())) {
s.setTag("message", ee.getDescription().lines().collect(Collectors.joining(" "))); s.setTag("message", ee.getDescription().lines().collect(Collectors.joining(" ")));
} }

View file

@ -16,11 +16,17 @@ public class WorkspacesCategory extends AppPrefsCategory {
@Override @Override
protected Comp<?> create() { protected Comp<?> create() {
return new OptionsBuilder() return new OptionsBuilder()
.addTitle(AppI18n.observable("manageWorkspaces").map(s -> s + (LicenseProvider.get().getFeature("workspaces").isSupported() ? "" : " (Pro)"))) .addTitle(AppI18n.observable("manageWorkspaces")
.map(s -> s
+ (LicenseProvider.get()
.getFeature("workspaces")
.isSupported()
? ""
: " (Pro)")))
.sub(new OptionsBuilder() .sub(new OptionsBuilder()
.nameAndDescription("workspaceAdd") .nameAndDescription("workspaceAdd")
.addComp(new ButtonComp(AppI18n.observable("addWorkspace"), WorkspaceCreationAlert::showAsync))) .addComp(new ButtonComp(AppI18n.observable("addWorkspace"), WorkspaceCreationAlert::showAsync)))
.disable(!LicenseProvider.get().getFeature("workspaces").isSupported()) .disable(!LicenseProvider.get().getFeature("workspaces").isSupported())
.buildComp(); .buildComp();
} }
} }

View file

@ -1,8 +1,9 @@
package io.xpipe.app.storage; package io.xpipe.app.storage;
import com.fasterxml.jackson.annotation.JsonProperty;
import javafx.scene.Node; import javafx.scene.Node;
import javafx.scene.paint.Color; import javafx.scene.paint.Color;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Getter; import lombok.Getter;
import java.util.ArrayList; import java.util.ArrayList;
@ -45,8 +46,7 @@ public enum DataColor {
public static void applyStyleClasses(DataColor color, Node node) { public static void applyStyleClasses(DataColor color, Node node) {
var newList = new ArrayList<>(node.getStyleClass()); var newList = new ArrayList<>(node.getStyleClass());
newList.removeIf(s -> Arrays.stream(DataColor.values()) newList.removeIf(s -> Arrays.stream(DataColor.values())
.anyMatch( .anyMatch(dataStoreColor -> dataStoreColor.getId().equals(s)));
dataStoreColor -> dataStoreColor.getId().equals(s)));
newList.remove("gray"); newList.remove("gray");
if (color != null) { if (color != null) {
newList.add(color.getId()); newList.add(color.getId());

View file

@ -700,7 +700,8 @@ public abstract class DataStorage {
return root.getColor(); return root.getColor();
} }
var cats = getCategoryParentHierarchy(getStoreCategoryIfPresent(entry.getCategoryUuid()).orElseThrow()); var cats = getCategoryParentHierarchy(
getStoreCategoryIfPresent(entry.getCategoryUuid()).orElseThrow());
for (DataStoreCategory cat : cats.reversed()) { for (DataStoreCategory cat : cats.reversed()) {
if (cat.getColor() != null) { if (cat.getColor() != null) {
return cat.getColor(); return cat.getColor();

View file

@ -1,9 +1,9 @@
package io.xpipe.app.storage; package io.xpipe.app.storage;
import com.fasterxml.jackson.core.JsonProcessingException;
import io.xpipe.app.comp.store.StoreSortMode; import io.xpipe.app.comp.store.StoreSortMode;
import io.xpipe.core.util.JacksonMapper; import io.xpipe.core.util.JacksonMapper;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.JsonNodeFactory; import com.fasterxml.jackson.databind.node.JsonNodeFactory;
@ -128,8 +128,8 @@ public class DataStoreCategory extends StorageElement {
.map(jsonNode -> jsonNode.booleanValue()) .map(jsonNode -> jsonNode.booleanValue())
.orElse(true); .orElse(true);
return Optional.of( return Optional.of(new DataStoreCategory(
new DataStoreCategory(dir, uuid, name, lastUsed, lastModified, color, false, parentUuid, sortMode, share, expanded)); dir, uuid, name, lastUsed, lastModified, color, false, parentUuid, sortMode, share, expanded));
} }
public void setSortMode(StoreSortMode sortMode) { public void setSortMode(StoreSortMode sortMode) {

View file

@ -107,7 +107,7 @@ public class DataStoreEntry extends StorageElement {
Instant lastModified, Instant lastModified,
DataStore store, DataStore store,
Order explicitOrder) { Order explicitOrder) {
super(directory, uuid, name, lastUsed, lastModified, null, false,false); super(directory, uuid, name, lastUsed, lastModified, null, false, false);
this.categoryUuid = categoryUuid; this.categoryUuid = categoryUuid;
this.store = store; this.store = store;
this.explicitOrder = explicitOrder; this.explicitOrder = explicitOrder;
@ -228,13 +228,15 @@ public class DataStoreEntry extends StorageElement {
.orElse(true); .orElse(true);
if (color == null) { if (color == null) {
color = Optional.ofNullable(stateJson.get("color")).map(node -> { color = Optional.ofNullable(stateJson.get("color"))
try { .map(node -> {
return mapper.treeToValue(node, DataColor.class); try {
} catch (JsonProcessingException e) { return mapper.treeToValue(node, DataColor.class);
return null; } catch (JsonProcessingException e) {
} return null;
}).orElse(null); }
})
.orElse(null);
} }
String notes = null; String notes = null;

View file

@ -43,12 +43,17 @@ public abstract class StorageElement {
@Getter @Getter
protected boolean expanded; protected boolean expanded;
protected @NonFinal protected @NonFinal @Getter DataColor color;
@Getter DataColor color;
public StorageElement( public StorageElement(
Path directory, UUID uuid, String name, Instant lastUsed, Instant lastModified, DataColor color, boolean expanded, boolean dirty) { Path directory,
UUID uuid,
String name,
Instant lastUsed,
Instant lastModified,
DataColor color,
boolean expanded,
boolean dirty) {
this.directory = directory; this.directory = directory;
this.uuid = uuid; this.uuid = uuid;
this.name = name; this.name = name;

View file

@ -13,8 +13,8 @@ import io.xpipe.app.util.*;
import io.xpipe.core.process.*; import io.xpipe.core.process.*;
import io.xpipe.core.store.FilePath; import io.xpipe.core.store.FilePath;
import io.xpipe.core.util.FailableFunction; import io.xpipe.core.util.FailableFunction;
import io.xpipe.core.util.XPipeInstallation; import io.xpipe.core.util.XPipeInstallation;
import javafx.scene.control.Alert; import javafx.scene.control.Alert;
import javafx.scene.control.ButtonBar; import javafx.scene.control.ButtonBar;
import javafx.scene.control.ButtonType; import javafx.scene.control.ButtonType;
@ -240,12 +240,17 @@ public interface ExternalTerminalType extends PrefsChoiceValue {
@Override @Override
protected void execute(Path file, LaunchConfiguration configuration) throws Exception { protected void execute(Path file, LaunchConfiguration configuration) throws Exception {
try (var sc = LocalShell.getShell()) { try (var sc = LocalShell.getShell()) {
// Since mobaxterm uses its own cygwin environment, we have to provide the beacon auth secret to the tmp there as well // Since mobaxterm uses its own cygwin environment, we have to provide the beacon auth secret to the tmp
// there as well
// Otherwise it can't connect // Otherwise it can't connect
var slashTemp = Path.of(System.getenv("APPDATA"), "MobaXterm", "slash", "tmp"); var slashTemp = Path.of(System.getenv("APPDATA"), "MobaXterm", "slash", "tmp");
if (Files.exists(slashTemp)) { if (Files.exists(slashTemp)) {
var authFileName = XPipeInstallation.getLocalBeaconAuthFile().getFileName().toString(); var authFileName = XPipeInstallation.getLocalBeaconAuthFile()
Files.writeString(Path.of(slashTemp.toString(), authFileName),AppBeaconServer.get().getLocalAuthSecret()); .getFileName()
.toString();
Files.writeString(
Path.of(slashTemp.toString(), authFileName),
AppBeaconServer.get().getLocalAuthSecret());
} }
var fixedFile = configuration var fixedFile = configuration

View file

@ -12,7 +12,7 @@ public class DesktopShortcuts {
var icon = XPipeInstallation.getLocalDefaultInstallationIcon(); var icon = XPipeInstallation.getLocalDefaultInstallationIcon();
var shortcutPath = DesktopHelper.getDesktopDirectory().resolve(name + ".lnk"); var shortcutPath = DesktopHelper.getDesktopDirectory().resolve(name + ".lnk");
var content = String.format( var content = String.format(
""" """
$TARGET="%s" $TARGET="%s"
$SHORTCUT="%s" $SHORTCUT="%s"
$ws = New-Object -ComObject WScript.Shell $ws = New-Object -ComObject WScript.Shell
@ -23,7 +23,8 @@ public class DesktopShortcuts {
$S.Arguments = '%s' $S.Arguments = '%s'
$S.Save() $S.Save()
""", """,
executable, shortcutPath, icon, args).replaceAll("\n", ";"); executable, shortcutPath, icon, args)
.replaceAll("\n", ";");
LocalShell.getLocalPowershell().executeSimpleCommand(content); LocalShell.getLocalPowershell().executeSimpleCommand(content);
return shortcutPath; return shortcutPath;
} }

View file

@ -25,18 +25,23 @@ public class FileEntry {
String path; String path;
public FileEntry( public FileEntry(
FileSystem fileSystem, @NonNull String path, Instant date, long size, FileInfo info, @NonNull FileKind kind FileSystem fileSystem,
) { @NonNull String path,
Instant date,
long size,
FileInfo info,
@NonNull FileKind kind) {
this.fileSystem = fileSystem; this.fileSystem = fileSystem;
this.kind = kind; this.kind = kind;
this.path = kind == FileKind.DIRECTORY ? new FilePath(path).toDirectory().toString() : path; this.path =
kind == FileKind.DIRECTORY ? new FilePath(path).toDirectory().toString() : path;
this.date = date; this.date = date;
this.info = info; this.info = info;
this.size = size; this.size = size;
} }
public static FileEntry ofDirectory(FileSystem fileSystem, String path) { public static FileEntry ofDirectory(FileSystem fileSystem, String path) {
return new FileEntry(fileSystem, path, Instant.now(), 0, null, FileKind.DIRECTORY); return new FileEntry(fileSystem, path, Instant.now(), 0, null, FileKind.DIRECTORY);
} }
public FileEntry resolved() { public FileEntry resolved() {

View file

@ -66,5 +66,4 @@ public interface FileSystem extends Closeable, AutoCloseable {
} }
List<String> listRoots() throws Exception; List<String> listRoots() throws Exception;
} }

View file

@ -14,10 +14,13 @@ public class LinkFileEntry extends FileEntry {
FileEntry target; FileEntry target;
public LinkFileEntry( public LinkFileEntry(
FileSystem fileSystem, @NonNull String path, Instant date, long size, @NonNull FileInfo info, FileSystem fileSystem,
@NonNull FileEntry target @NonNull String path,
) { Instant date,
super(fileSystem, path, date, size, info, FileKind.LINK); long size,
@NonNull FileInfo info,
@NonNull FileEntry target) {
super(fileSystem, path, date, size, info, FileKind.LINK);
this.target = target; this.target = target;
} }

View file

@ -7,9 +7,11 @@ import io.xpipe.app.browser.fs.OpenFileSystemModel;
import io.xpipe.app.core.AppI18n; import io.xpipe.app.core.AppI18n;
import io.xpipe.core.process.CommandBuilder; import io.xpipe.core.process.CommandBuilder;
import io.xpipe.core.process.OsType; import io.xpipe.core.process.OsType;
import javafx.beans.property.SimpleStringProperty; import javafx.beans.property.SimpleStringProperty;
import javafx.beans.value.ObservableValue; import javafx.beans.value.ObservableValue;
import javafx.scene.Node; import javafx.scene.Node;
import org.kordamp.ikonli.javafx.FontIcon; import org.kordamp.ikonli.javafx.FontIcon;
import java.util.List; import java.util.List;
@ -40,8 +42,13 @@ public class ChgrpAction implements BranchAction {
@Override @Override
public List<LeafAction> getBranchingActions(OpenFileSystemModel model, List<BrowserEntry> entries) { public List<LeafAction> getBranchingActions(OpenFileSystemModel model, List<BrowserEntry> entries) {
return model.getCache().getGroups().entrySet().stream() return model.getCache().getGroups().entrySet().stream()
.filter(e -> !e.getValue().equals("nohome") && !e.getValue().equals("nogroup") && !e.getValue().equals("nobody") && (e.getKey().equals(0) || e.getKey() >= 1000)) .filter(e -> !e.getValue().equals("nohome")
.map(e -> e.getValue()).map(s -> (LeafAction) new Chgrp(s)).toList(); && !e.getValue().equals("nogroup")
&& !e.getValue().equals("nobody")
&& (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 static class Chgrp implements LeafAction {

View file

@ -7,9 +7,11 @@ import io.xpipe.app.browser.fs.OpenFileSystemModel;
import io.xpipe.app.core.AppI18n; import io.xpipe.app.core.AppI18n;
import io.xpipe.core.process.CommandBuilder; import io.xpipe.core.process.CommandBuilder;
import io.xpipe.core.process.OsType; import io.xpipe.core.process.OsType;
import javafx.beans.property.SimpleStringProperty; import javafx.beans.property.SimpleStringProperty;
import javafx.beans.value.ObservableValue; import javafx.beans.value.ObservableValue;
import javafx.scene.Node; import javafx.scene.Node;
import org.kordamp.ikonli.javafx.FontIcon; import org.kordamp.ikonli.javafx.FontIcon;
import java.util.List; import java.util.List;
@ -40,8 +42,12 @@ public class ChownAction implements BranchAction {
@Override @Override
public List<LeafAction> getBranchingActions(OpenFileSystemModel model, List<BrowserEntry> entries) { public List<LeafAction> getBranchingActions(OpenFileSystemModel model, List<BrowserEntry> entries) {
return model.getCache().getUsers().entrySet().stream() return model.getCache().getUsers().entrySet().stream()
.filter(e -> !e.getValue().equals("nohome") && !e.getValue().equals("nobody") && (e.getKey().equals(0) || e.getKey() >= 1000)) .filter(e -> !e.getValue().equals("nohome")
.map(e -> e.getValue()).map(s -> (LeafAction) new Chown(s)).toList(); && !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 static class Chown implements LeafAction {

View file

@ -4,8 +4,8 @@ import io.xpipe.app.browser.action.BrowserActionFormatter;
import io.xpipe.app.browser.file.BrowserEntry; import io.xpipe.app.browser.file.BrowserEntry;
import io.xpipe.app.browser.fs.OpenFileSystemModel; import io.xpipe.app.browser.fs.OpenFileSystemModel;
import io.xpipe.app.browser.icon.BrowserIconFileType; import io.xpipe.app.browser.icon.BrowserIconFileType;
import io.xpipe.core.store.FileNames; import io.xpipe.core.store.FileNames;
import javafx.beans.property.SimpleStringProperty; import javafx.beans.property.SimpleStringProperty;
import javafx.beans.value.ObservableValue; import javafx.beans.value.ObservableValue;
@ -35,6 +35,7 @@ public class JavapAction extends ToFileCommandAction implements FileTypeAction,
@Override @Override
protected String createCommand(OpenFileSystemModel model, BrowserEntry entry) { protected String createCommand(OpenFileSystemModel model, BrowserEntry entry) {
return "javap -c -p " + FileNames.quoteIfNecessary(entry.getRawFileEntry().getPath()); return "javap -c -p "
+ FileNames.quoteIfNecessary(entry.getRawFileEntry().getPath());
} }
} }

View file

@ -71,7 +71,8 @@ public abstract class MultiExecuteSelectionAction implements BranchAction {
long exitCode; long exitCode;
try (var command = pc.command(cmd) try (var command = pc.command(cmd)
.withWorkingDirectory( .withWorkingDirectory(
model.getCurrentDirectory().getPath()).start()) { model.getCurrentDirectory().getPath())
.start()) {
var r = command.readStdoutAndStderr(); var r = command.readStdoutAndStderr();
out.set(r[0]); out.set(r[0]);
err.set(r[1]); err.set(r[1]);
@ -79,7 +80,8 @@ public abstract class MultiExecuteSelectionAction implements BranchAction {
} }
// Only throw actual error output // Only throw actual error output
if (exitCode != 0) { if (exitCode != 0) {
throw ErrorEvent.expected(ProcessOutputException.of(exitCode, out.get(), err.get())); throw ErrorEvent.expected(
ProcessOutputException.of(exitCode, out.get(), err.get()));
} }
}, },
false); false);

View file

@ -10,10 +10,12 @@ import io.xpipe.app.fxcomps.impl.DataStoreChoiceComp;
import io.xpipe.app.storage.DataStoreEntry; import io.xpipe.app.storage.DataStoreEntry;
import io.xpipe.app.util.OptionsBuilder; import io.xpipe.app.util.OptionsBuilder;
import io.xpipe.core.store.DataStore; import io.xpipe.core.store.DataStore;
import javafx.beans.property.Property; import javafx.beans.property.Property;
import javafx.beans.property.SimpleObjectProperty; import javafx.beans.property.SimpleObjectProperty;
import javafx.beans.property.SimpleStringProperty; import javafx.beans.property.SimpleStringProperty;
import javafx.beans.value.ObservableValue; import javafx.beans.value.ObservableValue;
import lombok.SneakyThrows; import lombok.SneakyThrows;
import java.util.List; import java.util.List;

View file

@ -35,20 +35,22 @@ public abstract class AbstractServiceGroupStoreProvider implements DataStoreProv
} }
private StoreToggleComp createToggleComp(StoreSection sec) { private StoreToggleComp createToggleComp(StoreSection sec) {
var t = StoreToggleComp.<AbstractServiceGroupStore<?>>enableToggle(null, sec, new SimpleBooleanProperty(false), (g, aBoolean) -> { var t = StoreToggleComp.<AbstractServiceGroupStore<?>>enableToggle(
var children = DataStorage.get().getStoreChildren(sec.getWrapper().getEntry()); null, sec, new SimpleBooleanProperty(false), (g, aBoolean) -> {
ThreadHelper.runFailableAsync(() -> { var children =
for (DataStoreEntry child : children) { DataStorage.get().getStoreChildren(sec.getWrapper().getEntry());
if (child.getStore() instanceof AbstractServiceStore serviceStore) { ThreadHelper.runFailableAsync(() -> {
if (aBoolean) { for (DataStoreEntry child : children) {
serviceStore.startSessionIfNeeded(); if (child.getStore() instanceof AbstractServiceStore serviceStore) {
} else { if (aBoolean) {
serviceStore.stopSessionIfNeeded(); serviceStore.startSessionIfNeeded();
} else {
serviceStore.stopSessionIfNeeded();
}
}
} }
} });
} });
});
});
t.setCustomVisibility(Bindings.createBooleanBinding( t.setCustomVisibility(Bindings.createBooleanBinding(
() -> { () -> {
var children = var children =