This commit is contained in:
crschnick
2025-09-02 11:44:17 +00:00
parent 78a5aa509f
commit 4e7646bec1
11 changed files with 90 additions and 31 deletions

View File

@@ -3,11 +3,14 @@ package io.xpipe.app.browser.action.impl;
import io.xpipe.app.browser.action.BrowserAction;
import io.xpipe.app.browser.action.BrowserActionProvider;
import io.xpipe.app.browser.file.BrowserEntry;
import io.xpipe.app.browser.file.BrowserFileSystemTabModel;
import io.xpipe.core.FileKind;
import lombok.experimental.SuperBuilder;
import lombok.extern.jackson.Jacksonized;
import java.util.List;
public class ComputeDirectorySizesActionProvider implements BrowserActionProvider {
@Override
@@ -15,6 +18,11 @@ public class ComputeDirectorySizesActionProvider implements BrowserActionProvide
return "computeDirectorySizes";
}
@Override
public boolean isApplicable(BrowserFileSystemTabModel model, List<BrowserEntry> entries) {
return model.getFileSystem().getShell().isPresent();
}
@Jacksonized
@SuperBuilder
public static class Action extends BrowserAction {

View File

@@ -24,6 +24,10 @@ public class OpenFileNativeDetailsActionProvider implements BrowserActionProvide
@Override
public boolean isApplicable(BrowserFileSystemTabModel model, List<BrowserEntry> entries) {
if (model.getFileSystem().getShell().isEmpty()) {
return false;
}
var sc = model.getFileSystem().getShell().orElseThrow();
return sc.getLocalSystemAccess().supportsFileSystemAccess();
}

View File

@@ -28,10 +28,10 @@ public class BrowserBreadcrumbBar extends SimpleComp {
@Override
protected Region createSimple() {
Callback<Breadcrumbs.BreadCrumbItem<String>, ButtonBase> crumbFactory = crumb -> {
var name = crumb.getValue().equals("/")
Callback<Breadcrumbs.BreadCrumbItem<FilePath>, ButtonBase> crumbFactory = crumb -> {
var name = crumb.getValue().toString().equals("/")
? "/"
: FilePath.of(crumb.getValue()).getFileName();
: crumb.getValue().getFileName();
var btn = new Button(name, null);
btn.setMnemonicParsing(false);
btn.setFocusTraversable(false);
@@ -41,10 +41,10 @@ public class BrowserBreadcrumbBar extends SimpleComp {
}
private Region createBreadcrumbs(
Callback<Breadcrumbs.BreadCrumbItem<String>, ButtonBase> crumbFactory,
Callback<Breadcrumbs.BreadCrumbItem<String>, ? extends Node> dividerFactory) {
Callback<Breadcrumbs.BreadCrumbItem<FilePath>, ButtonBase> crumbFactory,
Callback<Breadcrumbs.BreadCrumbItem<FilePath>, ? extends Node> dividerFactory) {
var breadcrumbs = new Breadcrumbs<String>();
var breadcrumbs = new Breadcrumbs<FilePath>();
breadcrumbs.setMinWidth(0);
model.getCurrentPath().subscribe(val -> {
PlatformThread.runLaterIfNeeded(() -> {
@@ -59,7 +59,7 @@ public class BrowserBreadcrumbBar extends SimpleComp {
return null;
}
if (item.isFirst() && item.getValue().equals("/")) {
if (item.isFirst() && item.getValue().toString().equals("/")) {
return new Label("");
}
@@ -71,12 +71,8 @@ public class BrowserBreadcrumbBar extends SimpleComp {
});
var elements = createBreadcumbHierarchy(val);
var modifiedElements = new ArrayList<>(elements);
if (val.toString().startsWith("/")) {
modifiedElements.addFirst("/");
}
Breadcrumbs.BreadCrumbItem<String> items =
Breadcrumbs.buildTreeModel(modifiedElements.toArray(String[]::new));
Breadcrumbs.BreadCrumbItem<FilePath> items =
Breadcrumbs.buildTreeModel(elements.toArray(FilePath[]::new));
breadcrumbs.setSelectedCrumb(items);
});
});
@@ -95,19 +91,24 @@ public class BrowserBreadcrumbBar extends SimpleComp {
return breadcrumbs;
}
private List<String> createBreadcumbHierarchy(FilePath filePath) {
var f = filePath.toString() + "/";
var list = new ArrayList<String>();
private List<FilePath> createBreadcumbHierarchy(FilePath filePath) {
var f = filePath.toDirectory().toString();
var list = new ArrayList<FilePath>();
int lastElementStart = 0;
for (int i = 0; i < f.length(); i++) {
if (f.charAt(i) == '\\' || f.charAt(i) == '/') {
if (i - lastElementStart > 0) {
list.add(f.substring(0, i));
list.add(FilePath.of(f.substring(0, i)));
}
lastElementStart = i + 1;
}
}
if (filePath.toString().startsWith("/")) {
list.addFirst(FilePath.of("/"));
}
return list;
}
}

View File

@@ -229,18 +229,27 @@ public final class BrowserFileListComp extends SimpleComp {
var m = fileList.getFileSystemModel();
var user = unix.getUser() != null
? unix.getUser()
: m.getCache().getUsers().getOrDefault(unix.getUid(), "?");
: m.getCache() != null ? m.getCache().getUsers().getOrDefault(unix.getUid(), "?") : null;
var group = unix.getGroup() != null
? unix.getGroup()
: m.getCache().getGroups().getOrDefault(unix.getGid(), "?");
var uid = String.valueOf(
unix.getUid() != null ? unix.getUid() : m.getCache().getUidForUser(user));
var gid = String.valueOf(
unix.getGid() != null ? unix.getGid() : m.getCache().getGidForGroup(group));
if (uid.equals(gid) && user.equals(group)) {
return user + " [" + uid + "]";
: m.getCache() != null ? m.getCache().getGroups().getOrDefault(unix.getGid(), "?") : null;
var uid =
unix.getUid() != null ? String.valueOf(unix.getUid()) : m.getCache() != null ? m.getCache().getUidForUser(user) : null;
var gid =
unix.getGid() != null ? String.valueOf(unix.getGid()) : m.getCache() != null ? m.getCache().getGidForGroup(group) : null;
var userFormat = user + (uid != null ? " [" + uid + "]" : "");
var groupFormat = group + (gid != null ? " [" + gid + "]" : "");
if (uid != null && uid.equals(gid) && user != null && user.equals(group)) {
return userFormat;
}
return user + " [" + uid + "] / " + group + " [" + gid + "]";
if (uid == null && gid == null && user != null && user.equals(group)) {
return userFormat;
}
return userFormat + " / " + groupFormat;
}
private void prepareTypedSelectionModel(TableView<BrowserEntry> table) {

View File

@@ -64,6 +64,10 @@ public class BrowserFileOpener {
private static boolean requiresSudo(BrowserFileSystemTabModel model, FileInfo.Unix info, FilePath filePath)
throws Exception {
if (model.getFileSystem().getShell().isEmpty() || model.getCache() == null) {
return false;
}
if (model.getCache().isRoot()) {
return false;
}
@@ -168,7 +172,7 @@ public class BrowserFileOpener {
}
public static void openWithAnyApplication(BrowserFileSystemTabModel model, FileEntry entry) {
if (model.getFileSystem().getShell().orElseThrow().isLocal()) {
if (model.getFileSystem().getShell().isPresent() && model.getFileSystem().getShell().get().isLocal()) {
FileOpener.openWithAnyApplication(entry.getPath().toString());
return;
}
@@ -217,7 +221,7 @@ public class BrowserFileOpener {
}
public static void openInDefaultApplication(BrowserFileSystemTabModel model, FileEntry entry) {
if (model.getFileSystem().getShell().orElseThrow().isLocal()) {
if (model.getFileSystem().getShell().isPresent() && model.getFileSystem().getShell().get().isLocal()) {
FileOpener.openInDefaultApplication(entry.getPath().toString());
return;
}
@@ -270,7 +274,8 @@ public class BrowserFileOpener {
if (editor == null) {
return;
}
if (model.getFileSystem().getShell().orElseThrow().isLocal()) {
if (model.getFileSystem().getShell().isPresent() && model.getFileSystem().getShell().get().isLocal()) {
FileOpener.openInTextEditor(entry.getPath().toString());
return;
}

View File

@@ -44,7 +44,7 @@ public class ComputeDirectorySizesMenuProvider implements BrowserMenuLeafProvide
@Override
public boolean isApplicable(BrowserFileSystemTabModel model, List<BrowserEntry> entries) {
return entries.stream()
return model.getFileSystem().getShell().isPresent() && entries.stream()
.allMatch(browserEntry -> browserEntry.getRawFileEntry().getKind() == FileKind.DIRECTORY);
}

View File

@@ -188,7 +188,8 @@ public class NewItemMenuProvider implements BrowserMenuBranchProvider {
@Override
public boolean isApplicable(BrowserFileSystemTabModel model, List<BrowserEntry> entries) {
return model.getFileSystem().getShell().orElseThrow().getOsType() != OsType.WINDOWS;
return model.getFileSystem().getShell().isEmpty() ||
model.getFileSystem().getShell().orElseThrow().getOsType() != OsType.WINDOWS;
}
@Override

View File

@@ -44,6 +44,10 @@ public class OpenTerminalInDirectoryMenuProvider implements BrowserMenuLeafProvi
@Override
public boolean isApplicable(BrowserFileSystemTabModel model, List<BrowserEntry> entries) {
if (model.getFileSystem().getShell().isEmpty()) {
return false;
}
return entries.stream().allMatch(entry -> entry.getRawFileEntry().getKind() == FileKind.DIRECTORY);
}

View File

@@ -8,6 +8,7 @@ import io.xpipe.app.util.DocumentationLink;
import io.xpipe.core.FilePath;
import com.fasterxml.jackson.annotation.JsonIgnore;
import io.xpipe.core.OsType;
import lombok.Getter;
import java.io.InputStream;
@@ -28,6 +29,16 @@ public class ConnectionFileSystem implements FileSystem {
this.shellControl = shellControl;
}
@Override
public Optional<OsType> getOsType() {
return Optional.of(shellControl.getOsType());
}
@Override
public FilePath pwd() throws Exception {
return shellControl.view().pwd();
}
@Override
public FileSystem createTransferOptimizedFileSystem() throws Exception {
// For local, we have our optimized streams regardless

View File

@@ -3,6 +3,7 @@ package io.xpipe.app.ext;
import io.xpipe.app.process.ShellControl;
import io.xpipe.core.FileKind;
import io.xpipe.core.FilePath;
import io.xpipe.core.OsType;
import java.io.Closeable;
import java.io.InputStream;
@@ -15,6 +16,10 @@ import java.util.stream.Stream;
public interface FileSystem extends Closeable, AutoCloseable {
Optional<OsType> getOsType();
FilePath pwd() throws Exception;
FileSystem createTransferOptimizedFileSystem() throws Exception;
long getFileSize(FilePath file) throws Exception;

View File

@@ -3,6 +3,7 @@ package io.xpipe.app.ext;
import io.xpipe.app.process.ShellControl;
import io.xpipe.core.FilePath;
import io.xpipe.core.OsType;
import lombok.Getter;
import java.io.IOException;
@@ -24,6 +25,16 @@ public class WrapperFileSystem implements FileSystem {
this.check = check;
}
@Override
public Optional<OsType> getOsType() {
return fs.getOsType();
}
@Override
public FilePath pwd() throws Exception {
return fs.pwd();
}
@Override
public FileSystem createTransferOptimizedFileSystem() {
return this;