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)
.apply(struc -> VBox.setVgrow(struc.get(), Priority.NEVER));
var roots = model.getFileSystem()
.listRoots()
.stream()
var roots = model.getFileSystem().listRoots().stream()
.map(s -> FileEntry.ofDirectory(model.getFileSystem(), s))
.toList();
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.FileKind;
import io.xpipe.core.store.FileNames;
import lombok.Getter;
@Getter

View file

@ -1,7 +1,5 @@
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.comp.base.LazyTextFieldComp;
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.FileKind;
import io.xpipe.core.store.FileNames;
import javafx.application.Platform;
import javafx.beans.binding.Bindings;
import javafx.beans.property.*;
@ -34,6 +33,9 @@ import javafx.scene.layout.HBox;
import javafx.scene.layout.Priority;
import javafx.scene.layout.Region;
import atlantafx.base.controls.Spacer;
import atlantafx.base.theme.Styles;
import java.time.Duration;
import java.time.Instant;
import java.time.ZoneId;
@ -104,7 +106,9 @@ public final class BrowserFileListComp extends SimpleComp {
var modeCol = new TableColumn<BrowserEntry, String>();
modeCol.textProperty().bind(AppI18n.observable("attributes"));
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.setResizable(false);
modeCol.setPrefWidth(120);
@ -134,7 +138,11 @@ public final class BrowserFileListComp extends SimpleComp {
return true;
});
table.setFixedCellSize(32.0);
var os = fileList.getFileSystemModel().getFileSystem().getShell().orElseThrow().getOsType();
var os = fileList.getFileSystemModel()
.getFileSystem()
.getShell()
.orElseThrow()
.getOsType();
table.widthProperty().subscribe((newValue) -> {
if (os != OsType.WINDOWS && os != OsType.MACOS) {
ownerCol.setVisible(newValue.doubleValue() > 1000);
@ -143,12 +151,15 @@ public final class BrowserFileListComp extends SimpleComp {
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);
});
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);
prepareTableShortcuts(table);
@ -160,9 +171,12 @@ public final class BrowserFileListComp extends SimpleComp {
}
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;
var sum = tableView.getColumns().stream()
.filter(tableColumn -> tableColumn.isVisible()
&& tableView.getColumns().indexOf(tableColumn) != 0)
.mapToDouble(value -> value.getPrefWidth())
.sum()
+ 7;
return tableView.getWidth() - sum;
}
@ -173,10 +187,18 @@ public final class BrowserFileListComp extends SimpleComp {
}
var m = fileList.getFileSystemModel();
var user = unix.getUser() != null ? unix.getUser() : m.getCache().getUsers().get(unix.getUid());
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");
var user = unix.getUser() != null
? unix.getUser()
: m.getCache().getUsers().get(unix.getUid());
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)) {
return user + " [" + uid + "]";
}
@ -428,19 +450,27 @@ public final class BrowserFileListComp extends SimpleComp {
var newItems = new ArrayList<>(fileList.getShown().getValue());
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) {
mtimeCol.setVisible(false);
} else {
mtimeCol.setVisible(true);
}
ownerWidth.set(fileList.getAll().getValue().stream().map(browserEntry -> formatOwner(browserEntry)).map(
s -> s != null ? s.length() * 9 : 0).max(Comparator.naturalOrder()).orElse(150));
ownerWidth.set(fileList.getAll().getValue().stream()
.map(browserEntry -> formatOwner(browserEntry))
.map(s -> s != null ? s.length() * 9 : 0)
.max(Comparator.naturalOrder())
.orElse(150));
ownerCol.setPrefWidth(ownerWidth.get());
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())) {
modeCol.setVisible(false);
ownerCol.setVisible(false);
@ -601,18 +631,14 @@ public final class BrowserFileListComp extends SimpleComp {
var quickAccess = new BrowserQuickAccessButtonComp(
() -> getTableRow().getItem(), fileList.getFileSystemModel())
.hide(Bindings.createBooleanBinding(
() -> {
var item = getTableRow().getItem();
var notDir = item.getRawFileEntry()
.resolved()
.getKind()
!= FileKind.DIRECTORY;
var isParentLink = item.getRawFileEntry()
.equals(fileList.getFileSystemModel()
.getCurrentParentDirectory());
return notDir || isParentLink;
},
itemProperty()))
() -> {
var item = getTableRow().getItem();
var notDir = item.getRawFileEntry().resolved().getKind() != FileKind.DIRECTORY;
var isParentLink = item.getRawFileEntry()
.equals(fileList.getFileSystemModel().getCurrentParentDirectory());
return notDir || isParentLink;
},
itemProperty()))
.focusTraversable(false)
.createRegion();
@ -719,7 +745,9 @@ public final class BrowserFileListComp extends SimpleComp {
.getPath()
: getTableRow().getItem().getFileName();
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);
text.set(fileName);
// 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) {
if (old == null || newName == null
if (old == null
|| newName == null
|| fileSystemModel == null
|| fileSystemModel.isClosed()
|| fileSystemModel.getCurrentPath().get() == null) {

View file

@ -222,11 +222,7 @@ public class BrowserFileTransferOperation {
}
private void transfer(
FileEntry sourceFile,
String targetFile,
AtomicLong transferred,
AtomicLong totalSize,
Instant start)
FileEntry sourceFile, String targetFile, AtomicLong transferred, AtomicLong totalSize, Instant start)
throws Exception {
InputStream inputStream = 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.ShellControl;
import io.xpipe.core.process.ShellDialect;
import lombok.Getter;
import java.util.LinkedHashMap;
@ -31,11 +32,19 @@ public class OpenFileSystemCache extends ShellControlCache {
}
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) {
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 {
@ -44,7 +53,9 @@ public class OpenFileSystemCache extends ShellControlCache {
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 -> {
var split = s.split(":");
users.putIfAbsent(Integer.parseInt(split[2]), split[0]);
@ -61,7 +72,9 @@ public class OpenFileSystemCache extends ShellControlCache {
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 -> {
var split = s.split(":");
groups.putIfAbsent(Integer.parseInt(split[2]), split[0]);

View file

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

View file

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

View file

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

View file

@ -47,25 +47,25 @@ public class MultiContentComp extends SimpleComp {
return stack;
}
// Lazy impl
// @Override
// protected Region createSimple() {
// var stack = new StackPane();
// for (Map.Entry<Comp<?>, ObservableValue<Boolean>> e : content.entrySet()) {
// var r = e.getKey().createRegion();
// e.getValue().subscribe(val -> {
// PlatformThread.runLaterIfNeeded(() -> {
// r.setManaged(val);
// r.setVisible(val);
// if (val && !stack.getChildren().contains(r)) {
// stack.getChildren().add(r);
// } else {
// stack.getChildren().remove(r);
// }
// });
// });
// }
//
// return stack;
// }
// Lazy impl
// @Override
// protected Region createSimple() {
// var stack = new StackPane();
// for (Map.Entry<Comp<?>, ObservableValue<Boolean>> e : content.entrySet()) {
// var r = e.getKey().createRegion();
// e.getValue().subscribe(val -> {
// PlatformThread.runLaterIfNeeded(() -> {
// r.setManaged(val);
// r.setVisible(val);
// if (val && !stack.getChildren().contains(r)) {
// stack.getChildren().add(r);
// } else {
// stack.getChildren().remove(r);
// }
// });
// });
// }
//
// return stack;
// }
}

View file

@ -83,21 +83,30 @@ public class SideMenuBarComp extends Comp<CompStructure<VBox>> {
b.accessibleText(e.name());
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 -> {
var indicatorRegion = (Region) struc.get().getChildren().getFirst();
indicatorRegion.setMaxWidth(7);
indicatorRegion.backgroundProperty().bind(Bindings.createObjectBinding(() -> {
if (value.getValue().equals(e)) {
return selectedBorder.get();
}
indicatorRegion
.backgroundProperty()
.bind(Bindings.createObjectBinding(
() -> {
if (value.getValue().equals(e)) {
return selectedBorder.get();
}
if (struc.get().isHover()) {
return hoverBorder.get();
}
if (struc.get().isHover()) {
return hoverBorder.get();
}
return noneBorder.get();
}, struc.get().hoverProperty(), value, hoverBorder, selectedBorder, noneBorder));
return noneBorder.get();
},
struc.get().hoverProperty(),
value,
hoverBorder,
selectedBorder,
noneBorder));
});
if (shortcut != null) {
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
? new LabelGraphic.IconGraphic("mdi2c-circle-slice-8")
: new LabelGraphic.IconGraphic("mdi2p-power"));
var t = new StoreToggleComp(
nameKey,
g,
section,
value,
v -> {
setter.accept(section.getWrapper().getEntry().getStore().asNeeded(), v);
});
var t = new StoreToggleComp(nameKey, g, section, value, v -> {
setter.accept(section.getWrapper().getEntry().getStore().asNeeded(), v);
});
t.tooltipKey("enabled");
t.value.subscribe((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.fxcomps.util.PlatformThread;
import io.xpipe.app.prefs.AppPrefs;
import io.xpipe.app.storage.DataColor;
import io.xpipe.app.storage.DataStorage;
import io.xpipe.app.storage.DataStoreCategory;
import io.xpipe.app.storage.DataColor;
import javafx.beans.property.*;
import javafx.collections.FXCollections;
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.PlatformThread;
import io.xpipe.app.prefs.AppPrefs;
import io.xpipe.app.storage.DataStorage;
import io.xpipe.app.storage.DataColor;
import io.xpipe.app.storage.DataStorage;
import io.xpipe.app.storage.DataStoreEntry;
import io.xpipe.app.update.XPipeDistributionType;
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.issue.ErrorEvent;
import io.xpipe.app.prefs.AppPrefs;
import io.xpipe.app.storage.DataColor;
import io.xpipe.app.storage.DataStorage;
import io.xpipe.app.storage.DataStoreCategory;
import io.xpipe.app.storage.DataColor;
import io.xpipe.app.storage.DataStoreEntry;
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.core.process.OsType;
import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.desktop.*;
import java.util.List;
import javax.imageio.ImageIO;
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.TrackEvent;
import javafx.scene.image.Image;
import javafx.scene.image.WritableImage;
import org.apache.commons.io.FilenameUtils;
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.core.store.EnabledStoreState;
import io.xpipe.core.store.StatefulDataStore;
import javafx.beans.property.SimpleBooleanProperty;
public interface EnabledParentStoreProvider extends DataStoreProvider {
@ -32,11 +33,14 @@ public interface EnabledParentStoreProvider extends DataStoreProvider {
var state = s.getState().toBuilder().enabled(aBoolean).build();
s.setState(state);
var children = DataStorage.get().getStoreChildren(sec.getWrapper().getEntry());
var children =
DataStorage.get().getStoreChildren(sec.getWrapper().getEntry());
ThreadHelper.runFailableAsync(() -> {
for (DataStoreEntry child : children) {
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.util.ContextMenuHelper;
import io.xpipe.app.util.DataStoreFormatter;
import javafx.beans.binding.Bindings;
import javafx.beans.property.SimpleBooleanProperty;
import javafx.css.PseudoClass;
@ -31,6 +32,7 @@ import javafx.scene.input.KeyCodeCombination;
import javafx.scene.input.KeyEvent;
import javafx.scene.input.MouseButton;
import javafx.scene.layout.Region;
import lombok.EqualsAndHashCode;
import lombok.Value;
import org.kordamp.ikonli.javafx.FontIcon;
@ -57,13 +59,15 @@ public class StoreCategoryComp extends SimpleComp {
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";
},
category.getExpanded(), category.getChildren());
category.getExpanded(),
category.getChildren());
var expandButton = new IconButtonComp(expandIcon, () -> {
category.toggleExpanded();
})
category.toggleExpanded();
})
.apply(struc -> AppFont.medium(struc.get()))
.apply(struc -> {
struc.get().setAlignment(Pos.CENTER);
@ -87,7 +91,8 @@ public class StoreCategoryComp extends SimpleComp {
return category.getShare().getValue() ? "mdi2g-git" : "mdi2a-account-cancel";
},
category.getShare(), hover);
category.getShare(),
hover);
var statusButton = new IconButtonComp(statusIcon)
.apply(struc -> AppFont.small(struc.get()))
.apply(struc -> {
@ -98,10 +103,10 @@ public class StoreCategoryComp extends SimpleComp {
})
.apply(new ContextMenuAugment<>(
mouseEvent -> mouseEvent.getButton() == MouseButton.PRIMARY, null, () -> {
var cm = createContextMenu(name);
showing.bind(cm.showingProperty());
return cm;
}))
var cm = createContextMenu(name);
showing.bind(cm.showingProperty());
return cm;
}))
.styleClass("status-button");
var shownList = new DerivedObservableList<>(category.getContainedEntries(), true)
@ -114,7 +119,8 @@ public class StoreCategoryComp extends SimpleComp {
.getList();
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 h = new HorizontalComp(List.of(
expandButton,
@ -153,9 +159,13 @@ public class StoreCategoryComp extends SimpleComp {
new ListBoxViewComp<>(l, l, storeCategoryWrapper -> new StoreCategoryComp(storeCategoryWrapper), false);
children.styleClass("children");
var hide = Bindings.createBooleanBinding(() -> {
return !category.getExpanded().get() || category.getChildren().isEmpty();
}, category.getChildren(), category.getExpanded());
var hide = Bindings.createBooleanBinding(
() -> {
return !category.getExpanded().get()
|| category.getChildren().isEmpty();
},
category.getChildren(),
category.getExpanded());
var v = new VerticalComp(List.of(categoryButton, children.hide(hide)));
v.styleClass("category");
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.augment.Augment;
import io.xpipe.app.fxcomps.util.PlatformThread;
import javafx.beans.binding.Bindings;
import javafx.beans.value.ObservableValue;
import javafx.scene.control.Tooltip;

View file

@ -46,7 +46,9 @@ public abstract class LabelGraphic {
@Override
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;
import io.sentry.*;
import io.sentry.protocol.SentryId;
import io.sentry.protocol.User;
import io.xpipe.app.core.AppLogs;
import io.xpipe.app.core.AppProperties;
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.update.XPipeDistributionType;
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 java.io.ByteArrayInputStream;
@ -163,7 +164,9 @@ public class SentryErrorHandler implements ErrorHandler {
s.setTag("licenseRequired", Boolean.toString(ee.isLicenseRequired()));
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(" ")));
}

View file

@ -16,11 +16,17 @@ public class WorkspacesCategory extends AppPrefsCategory {
@Override
protected Comp<?> create() {
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()
.nameAndDescription("workspaceAdd")
.addComp(new ButtonComp(AppI18n.observable("addWorkspace"), WorkspaceCreationAlert::showAsync)))
.disable(!LicenseProvider.get().getFeature("workspaces").isSupported())
.disable(!LicenseProvider.get().getFeature("workspaces").isSupported())
.buildComp();
}
}

View file

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

View file

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

View file

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

View file

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

View file

@ -43,12 +43,17 @@ public abstract class StorageElement {
@Getter
protected boolean expanded;
protected @NonFinal
@Getter DataColor color;
protected @NonFinal @Getter DataColor color;
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.uuid = uuid;
this.name = name;

View file

@ -13,8 +13,8 @@ import io.xpipe.app.util.*;
import io.xpipe.core.process.*;
import io.xpipe.core.store.FilePath;
import io.xpipe.core.util.FailableFunction;
import io.xpipe.core.util.XPipeInstallation;
import javafx.scene.control.Alert;
import javafx.scene.control.ButtonBar;
import javafx.scene.control.ButtonType;
@ -240,12 +240,17 @@ public interface ExternalTerminalType extends PrefsChoiceValue {
@Override
protected void execute(Path file, LaunchConfiguration configuration) throws Exception {
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
var slashTemp = Path.of(System.getenv("APPDATA"), "MobaXterm", "slash", "tmp");
if (Files.exists(slashTemp)) {
var authFileName = XPipeInstallation.getLocalBeaconAuthFile().getFileName().toString();
Files.writeString(Path.of(slashTemp.toString(), authFileName),AppBeaconServer.get().getLocalAuthSecret());
var authFileName = XPipeInstallation.getLocalBeaconAuthFile()
.getFileName()
.toString();
Files.writeString(
Path.of(slashTemp.toString(), authFileName),
AppBeaconServer.get().getLocalAuthSecret());
}
var fixedFile = configuration

View file

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

View file

@ -25,18 +25,23 @@ public class FileEntry {
String path;
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.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.info = info;
this.size = size;
}
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() {

View file

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

View file

@ -14,10 +14,13 @@ public class LinkFileEntry extends FileEntry {
FileEntry target;
public LinkFileEntry(
FileSystem fileSystem, @NonNull String path, Instant date, long size, @NonNull FileInfo info,
@NonNull FileEntry target
) {
super(fileSystem, path, date, size, info, FileKind.LINK);
FileSystem fileSystem,
@NonNull String path,
Instant date,
long size,
@NonNull FileInfo info,
@NonNull FileEntry target) {
super(fileSystem, path, date, size, info, FileKind.LINK);
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.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;
@ -40,8 +42,13 @@ public class ChgrpAction implements BranchAction {
@Override
public List<LeafAction> getBranchingActions(OpenFileSystemModel model, List<BrowserEntry> entries) {
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))
.map(e -> e.getValue()).map(s -> (LeafAction) new Chgrp(s)).toList();
.filter(e -> !e.getValue().equals("nohome")
&& !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 {

View file

@ -7,9 +7,11 @@ 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;
@ -40,8 +42,12 @@ public class ChownAction implements BranchAction {
@Override
public List<LeafAction> getBranchingActions(OpenFileSystemModel model, List<BrowserEntry> entries) {
return model.getCache().getUsers().entrySet().stream()
.filter(e -> !e.getValue().equals("nohome") && !e.getValue().equals("nobody") && (e.getKey().equals(0) || e.getKey() >= 1000))
.map(e -> e.getValue()).map(s -> (LeafAction) new Chown(s)).toList();
.filter(e -> !e.getValue().equals("nohome")
&& !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 {

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.fs.OpenFileSystemModel;
import io.xpipe.app.browser.icon.BrowserIconFileType;
import io.xpipe.core.store.FileNames;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.value.ObservableValue;
@ -35,6 +35,7 @@ public class JavapAction extends ToFileCommandAction implements FileTypeAction,
@Override
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;
try (var command = pc.command(cmd)
.withWorkingDirectory(
model.getCurrentDirectory().getPath()).start()) {
model.getCurrentDirectory().getPath())
.start()) {
var r = command.readStdoutAndStderr();
out.set(r[0]);
err.set(r[1]);
@ -79,7 +80,8 @@ public abstract class MultiExecuteSelectionAction implements BranchAction {
}
// Only throw actual error output
if (exitCode != 0) {
throw ErrorEvent.expected(ProcessOutputException.of(exitCode, out.get(), err.get()));
throw ErrorEvent.expected(
ProcessOutputException.of(exitCode, out.get(), err.get()));
}
},
false);

View file

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

View file

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