From 4a21dffdab3605ac6df00e34971ca7cfa92d3d2e Mon Sep 17 00:00:00 2001 From: crschnick Date: Tue, 30 May 2023 10:08:58 +0000 Subject: [PATCH] Introduce file kinds --- .../io/xpipe/app/browser/BrowserAlerts.java | 5 +- .../io/xpipe/app/browser/BrowserEntry.java | 5 +- .../app/browser/BrowserFileListComp.java | 19 +-- .../app/browser/BrowserFileListCompEntry.java | 13 +- .../app/browser/BrowserFileListModel.java | 7 +- .../xpipe/app/browser/FileSystemHelper.java | 9 +- .../app/browser/OpenFileSystemModel.java | 9 +- .../xpipe/app/browser/icon/DirectoryType.java | 3 +- .../app/browser/icon/FileIconManager.java | 5 +- .../io/xpipe/app/browser/icon/FileType.java | 3 +- app/src/main/java/io/xpipe/app/core/App.java | 7 -- .../java/io/xpipe/app/core/mode/BaseMode.java | 2 + .../xpipe/app/issue/TerminalErrorHandler.java | 2 + .../java/io/xpipe/core/impl/LocalStore.java | 111 ++---------------- .../java/io/xpipe/core/store/FileKind.java | 9 ++ .../java/io/xpipe/core/store/FileSystem.java | 16 +-- .../browser/BrowseInNativeManagerAction.java | 7 +- .../ext/base/browser/EditFileAction.java | 3 +- .../ext/base/browser/OpenDirectoryAction.java | 3 +- .../browser/OpenDirectoryInNewTabAction.java | 3 +- .../base/browser/OpenFileDefaultAction.java | 3 +- .../ext/base/browser/OpenFileWithAction.java | 3 +- .../ext/base/browser/OpenTerminalAction.java | 3 +- .../xpipe/ext/base/browser/PasteAction.java | 5 +- .../io/xpipe/ext/base/browser/RunAction.java | 3 +- 25 files changed, 94 insertions(+), 164 deletions(-) create mode 100644 core/src/main/java/io/xpipe/core/store/FileKind.java diff --git a/app/src/main/java/io/xpipe/app/browser/BrowserAlerts.java b/app/src/main/java/io/xpipe/app/browser/BrowserAlerts.java index 7d9c33b1..6cb4f3df 100644 --- a/app/src/main/java/io/xpipe/app/browser/BrowserAlerts.java +++ b/app/src/main/java/io/xpipe/app/browser/BrowserAlerts.java @@ -2,6 +2,7 @@ package io.xpipe.app.browser; import io.xpipe.app.core.AppI18n; import io.xpipe.app.core.AppWindowHelper; +import io.xpipe.core.store.FileKind; import io.xpipe.core.store.FileSystem; import javafx.scene.control.Alert; @@ -11,7 +12,7 @@ import java.util.stream.Collectors; public class BrowserAlerts { public static boolean showMoveAlert(List source, FileSystem.FileEntry target) { - if (source.stream().noneMatch(entry -> entry.isDirectory())) { + if (source.stream().noneMatch(entry -> entry.getKind() == FileKind.DIRECTORY)) { return true; } @@ -26,7 +27,7 @@ public class BrowserAlerts { } public static boolean showDeleteAlert(List source) { - if (source.stream().noneMatch(entry -> entry.isDirectory())) { + if (source.stream().noneMatch(entry -> entry.getKind() == FileKind.DIRECTORY)) { return true; } diff --git a/app/src/main/java/io/xpipe/app/browser/BrowserEntry.java b/app/src/main/java/io/xpipe/app/browser/BrowserEntry.java index 680022cf..1d718a72 100644 --- a/app/src/main/java/io/xpipe/app/browser/BrowserEntry.java +++ b/app/src/main/java/io/xpipe/app/browser/BrowserEntry.java @@ -3,6 +3,7 @@ package io.xpipe.app.browser; import io.xpipe.app.browser.icon.DirectoryType; import io.xpipe.app.browser.icon.FileType; import io.xpipe.core.impl.FileNames; +import io.xpipe.core.store.FileKind; import io.xpipe.core.store.FileSystem; import lombok.Getter; @@ -24,7 +25,7 @@ public class BrowserEntry { } private static FileType fileType(FileSystem.FileEntry rawFileEntry) { - if (rawFileEntry.isDirectory()) { + if (rawFileEntry.getKind() == FileKind.DIRECTORY) { return null; } @@ -38,7 +39,7 @@ public class BrowserEntry { } private static DirectoryType directoryType(FileSystem.FileEntry rawFileEntry) { - if (!rawFileEntry.isDirectory()) { + if (rawFileEntry.getKind() != FileKind.DIRECTORY) { return null; } diff --git a/app/src/main/java/io/xpipe/app/browser/BrowserFileListComp.java b/app/src/main/java/io/xpipe/app/browser/BrowserFileListComp.java index 43806ea9..8fdab11b 100644 --- a/app/src/main/java/io/xpipe/app/browser/BrowserFileListComp.java +++ b/app/src/main/java/io/xpipe/app/browser/BrowserFileListComp.java @@ -15,6 +15,7 @@ import io.xpipe.app.util.HumanReadableFormat; import io.xpipe.app.util.ThreadHelper; import io.xpipe.core.impl.FileNames; import io.xpipe.core.process.OsType; +import io.xpipe.core.store.FileKind; import io.xpipe.core.store.FileSystem; import javafx.application.Platform; import javafx.beans.binding.Bindings; @@ -111,7 +112,7 @@ final class BrowserFileListComp extends SimpleComp { var syntheticFirst = Comparator.comparing(path -> !path.isSynthetic()); var dirsFirst = Comparator.comparing( - path -> !path.getRawFileEntry().isDirectory()); + path -> path.getRawFileEntry().getKind() != FileKind.DIRECTORY); Comparator us = syntheticFirst.thenComparing(dirsFirst).thenComparing(comp); @@ -149,9 +150,9 @@ final class BrowserFileListComp extends SimpleComp { .getCurrentParentDirectory() .getPath())); // Remove unsuitable selection - toSelect.removeIf(browserEntry -> (browserEntry.getRawFileEntry().isDirectory() + toSelect.removeIf(browserEntry -> (browserEntry.getRawFileEntry().getKind() == FileKind.DIRECTORY && !fileList.getMode().isAcceptsDirectories()) - || (!browserEntry.getRawFileEntry().isDirectory() + || (browserEntry.getRawFileEntry().getKind() != FileKind.DIRECTORY && !fileList.getMode().isAcceptsFiles())); fileList.getSelection().setAll(toSelect); @@ -233,11 +234,11 @@ final class BrowserFileListComp extends SimpleComp { return event.getButton() == MouseButton.SECONDARY; } - if (row.getItem() != null && row.getItem().getRawFileEntry().isDirectory()) { + if (row.getItem() != null && row.getItem().getRawFileEntry().getKind() == FileKind.DIRECTORY) { return event.getButton() == MouseButton.SECONDARY; } - if (row.getItem() != null && !row.getItem().getRawFileEntry().isDirectory()) { + if (row.getItem() != null && row.getItem().getRawFileEntry().getKind() != FileKind.DIRECTORY) { return event.getButton() == MouseButton.SECONDARY || event.getButton() == MouseButton.PRIMARY && event.getClickCount() == 2; } @@ -261,9 +262,9 @@ final class BrowserFileListComp extends SimpleComp { row.itemProperty().addListener((observable, oldValue, newValue) -> { row.pseudoClassStateChanged(EMPTY, newValue == null); row.pseudoClassStateChanged( - FILE, newValue != null && !newValue.getRawFileEntry().isDirectory()); + FILE, newValue != null && newValue.getRawFileEntry().getKind() != FileKind.DIRECTORY); row.pseudoClassStateChanged( - FOLDER, newValue != null && newValue.getRawFileEntry().isDirectory()); + FOLDER, newValue != null && newValue.getRawFileEntry().getKind() == FileKind.DIRECTORY); }); fileList.getDraggedOverDirectory().addListener((observable, oldValue, newValue) -> { @@ -455,7 +456,7 @@ final class BrowserFileListComp extends SimpleComp { : getTableRow().getItem().getRawFileEntry(), isParentLink)); - var isDirectory = getTableRow().getItem().getRawFileEntry().isDirectory(); + var isDirectory = getTableRow().getItem().getRawFileEntry().getKind() == FileKind.DIRECTORY; pseudoClassStateChanged(FOLDER, isDirectory); var fileName = isParentLink ? ".." : FileNames.getFileName(fullPath); @@ -477,7 +478,7 @@ final class BrowserFileListComp extends SimpleComp { setText(null); } else { var path = getTableRow().getItem(); - if (path.getRawFileEntry().isDirectory()) { + if (path.getRawFileEntry().getKind() == FileKind.DIRECTORY) { setText(""); } else { setText(byteCount(fileSize.longValue())); diff --git a/app/src/main/java/io/xpipe/app/browser/BrowserFileListCompEntry.java b/app/src/main/java/io/xpipe/app/browser/BrowserFileListCompEntry.java index dab1c01a..6f5192bc 100644 --- a/app/src/main/java/io/xpipe/app/browser/BrowserFileListCompEntry.java +++ b/app/src/main/java/io/xpipe/app/browser/BrowserFileListCompEntry.java @@ -1,5 +1,6 @@ package io.xpipe.app.browser; +import io.xpipe.core.store.FileKind; import javafx.geometry.Point2D; import javafx.scene.Node; import javafx.scene.control.TableView; @@ -80,7 +81,7 @@ public class BrowserFileListCompEntry { // Prevent drag and drops of files into the current directory if (BrowserClipboard.currentDragClipboard .getBaseDirectory().getPath() - .equals(model.getFileSystemModel().getCurrentDirectory().getPath()) && (item == null || !item.getRawFileEntry().isDirectory())) { + .equals(model.getFileSystemModel().getCurrentDirectory().getPath()) && (item == null || item.getRawFileEntry().getKind() != FileKind.DIRECTORY)) { return false; } @@ -100,7 +101,7 @@ public class BrowserFileListCompEntry { if (event.getGestureSource() == null && event.getDragboard().hasFiles()) { Dragboard db = event.getDragboard(); var list = db.getFiles().stream().map(File::toPath).toList(); - var target = item != null && item.getRawFileEntry().isDirectory() + var target = item != null && item.getRawFileEntry().getKind() == FileKind.DIRECTORY ? item.getRawFileEntry() : model.getFileSystemModel().getCurrentDirectory(); model.getFileSystemModel().dropLocalFilesIntoAsync(target, list); @@ -111,7 +112,7 @@ public class BrowserFileListCompEntry { // Accept drops from inside the app window if (event.getGestureSource() != null) { var files = BrowserClipboard.retrieveDrag(event.getDragboard()).getEntries(); - var target = item != null && item.getRawFileEntry().isDirectory() + var target = item != null && item.getRawFileEntry().getKind() == FileKind.DIRECTORY ? item.getRawFileEntry() : model.getFileSystemModel().getCurrentDirectory(); model.getFileSystemModel().dropFilesIntoAsync(target, files, false); @@ -121,7 +122,7 @@ public class BrowserFileListCompEntry { } public void onDragExited(DragEvent event) { - if (item != null && item.getRawFileEntry().isDirectory()) { + if (item != null && item.getRawFileEntry().getKind() == FileKind.DIRECTORY) { model.getDraggedOverDirectory().setValue(null); } else { model.getDraggedOverEmpty().setValue(false); @@ -151,13 +152,13 @@ public class BrowserFileListCompEntry { } private void acceptDrag(DragEvent event) { - model.getDraggedOverEmpty().setValue(item == null || !item.getRawFileEntry().isDirectory()); + model.getDraggedOverEmpty().setValue(item == null || item.getRawFileEntry().getKind() != FileKind.DIRECTORY); model.getDraggedOverDirectory().setValue(item); event.acceptTransferModes(TransferMode.COPY_OR_MOVE); } private void handleHoverTimer(DragEvent event) { - if (item == null || !item.getRawFileEntry().isDirectory()) { + if (item == null || item.getRawFileEntry().getKind() != FileKind.DIRECTORY) { return; } diff --git a/app/src/main/java/io/xpipe/app/browser/BrowserFileListModel.java b/app/src/main/java/io/xpipe/app/browser/BrowserFileListModel.java index aaaa7087..a867554e 100644 --- a/app/src/main/java/io/xpipe/app/browser/BrowserFileListModel.java +++ b/app/src/main/java/io/xpipe/app/browser/BrowserFileListModel.java @@ -3,6 +3,7 @@ package io.xpipe.app.browser; import io.xpipe.app.fxcomps.util.BindingsHelper; import io.xpipe.app.issue.ErrorEvent; import io.xpipe.core.impl.FileNames; +import io.xpipe.core.store.FileKind; import io.xpipe.core.store.FileSystem; import javafx.beans.property.Property; import javafx.beans.property.SimpleBooleanProperty; @@ -23,7 +24,7 @@ import java.util.stream.Stream; public final class BrowserFileListModel { static final Comparator FILE_TYPE_COMPARATOR = - Comparator.comparing(path -> !path.getRawFileEntry().isDirectory()); + Comparator.comparing(path -> path.getRawFileEntry().getKind() != FileKind.DIRECTORY); static final Predicate PREDICATE_ANY = path -> true; static final Predicate PREDICATE_NOT_HIDDEN = path -> true; @@ -112,12 +113,12 @@ public final class BrowserFileListModel { } public void onDoubleClick(BrowserEntry entry) { - if (!entry.getRawFileEntry().isDirectory() && getMode().equals(BrowserModel.Mode.SINGLE_FILE_CHOOSER)) { + if (entry.getRawFileEntry().getKind() != FileKind.DIRECTORY && getMode().equals(BrowserModel.Mode.SINGLE_FILE_CHOOSER)) { getFileSystemModel().getBrowserModel().finishChooser(); return; } - if (entry.getRawFileEntry().isDirectory()) { + if (entry.getRawFileEntry().getKind() == FileKind.DIRECTORY) { var dir = fileSystemModel.cd(entry.getRawFileEntry().getPath()); if (dir.isPresent()) { fileSystemModel.cd(dir.get()); diff --git a/app/src/main/java/io/xpipe/app/browser/FileSystemHelper.java b/app/src/main/java/io/xpipe/app/browser/FileSystemHelper.java index 58e2416d..8a53261e 100644 --- a/app/src/main/java/io/xpipe/app/browser/FileSystemHelper.java +++ b/app/src/main/java/io/xpipe/app/browser/FileSystemHelper.java @@ -5,6 +5,7 @@ import io.xpipe.core.impl.FileNames; import io.xpipe.core.impl.LocalStore; import io.xpipe.core.process.OsType; import io.xpipe.core.store.ConnectionFileSystem; +import io.xpipe.core.store.FileKind; import io.xpipe.core.store.FileSystem; import java.nio.file.Files; @@ -96,11 +97,11 @@ public class FileSystemHelper { localFileSystem, file.toString(), Files.getLastModifiedTime(file).toInstant(), - Files.isDirectory(file), Files.isHidden(file), Files.isExecutable(file), Files.size(file), - null + null, + Files.isDirectory(file) ? FileKind.DIRECTORY : FileKind.FILE ); } @@ -176,7 +177,7 @@ public class FileSystemHelper { return; } - if (source.isDirectory()) { + if (source.getKind() == FileKind.DIRECTORY) { var directoryName = FileNames.getFileName(source.getPath()); flatFiles.put(source, directoryName); @@ -197,7 +198,7 @@ public class FileSystemHelper { throw new IllegalStateException(); } - if (sourceFile.isDirectory()) { + if (sourceFile.getKind() == FileKind.DIRECTORY) { target.getFileSystem().mkdirs(targetFile); } else { try (var in = sourceFile.getFileSystem().openInput(sourceFile.getPath()); diff --git a/app/src/main/java/io/xpipe/app/browser/OpenFileSystemModel.java b/app/src/main/java/io/xpipe/app/browser/OpenFileSystemModel.java index 4477a49c..b1f9fe89 100644 --- a/app/src/main/java/io/xpipe/app/browser/OpenFileSystemModel.java +++ b/app/src/main/java/io/xpipe/app/browser/OpenFileSystemModel.java @@ -10,10 +10,7 @@ import io.xpipe.app.util.XPipeDaemon; import io.xpipe.core.impl.FileNames; import io.xpipe.core.process.ShellControl; import io.xpipe.core.process.ShellDialects; -import io.xpipe.core.store.ConnectionFileSystem; -import io.xpipe.core.store.FileSystem; -import io.xpipe.core.store.FileSystemStore; -import io.xpipe.core.store.ShellStore; +import io.xpipe.core.store.*; import javafx.beans.binding.Bindings; import javafx.beans.property.*; import lombok.Getter; @@ -94,7 +91,7 @@ public final class OpenFileSystemModel { return null; } - return new FileSystem.FileEntry(fileSystem, parent, null, true, false, false, 0, null); + return new FileSystem.FileEntry(fileSystem, parent, null, false, false, 0, null, FileKind.DIRECTORY); } public FileSystem.FileEntry getCurrentDirectory() { @@ -102,7 +99,7 @@ public final class OpenFileSystemModel { return null; } - return new FileSystem.FileEntry(fileSystem, currentPath.get(), null, true, false, false, 0, null); + return new FileSystem.FileEntry(fileSystem, currentPath.get(), null, false, false, 0, null, FileKind.DIRECTORY); } public Optional cd(String path) { diff --git a/app/src/main/java/io/xpipe/app/browser/icon/DirectoryType.java b/app/src/main/java/io/xpipe/app/browser/icon/DirectoryType.java index fa389c10..4ffc31cb 100644 --- a/app/src/main/java/io/xpipe/app/browser/icon/DirectoryType.java +++ b/app/src/main/java/io/xpipe/app/browser/icon/DirectoryType.java @@ -2,6 +2,7 @@ package io.xpipe.app.browser.icon; import io.xpipe.app.core.AppResources; import io.xpipe.core.impl.FileNames; +import io.xpipe.core.store.FileKind; import io.xpipe.core.store.FileSystem; import lombok.Getter; @@ -94,7 +95,7 @@ public interface DirectoryType { @Override public boolean matches(FileSystem.FileEntry entry) { - if (!entry.isDirectory()) { + if (entry.getKind() != FileKind.DIRECTORY) { return false; } diff --git a/app/src/main/java/io/xpipe/app/browser/icon/FileIconManager.java b/app/src/main/java/io/xpipe/app/browser/icon/FileIconManager.java index 07773d99..cc688c22 100644 --- a/app/src/main/java/io/xpipe/app/browser/icon/FileIconManager.java +++ b/app/src/main/java/io/xpipe/app/browser/icon/FileIconManager.java @@ -3,6 +3,7 @@ package io.xpipe.app.browser.icon; import io.xpipe.app.core.AppImages; import io.xpipe.app.core.AppResources; import io.xpipe.app.fxcomps.impl.SvgCache; +import io.xpipe.core.store.FileKind; import io.xpipe.core.store.FileSystem; import javafx.scene.image.Image; import lombok.Getter; @@ -46,7 +47,7 @@ public class FileIconManager { loadIfNecessary(); - if (!entry.isDirectory()) { + if (entry.getKind() != FileKind.DIRECTORY) { for (var f : FileType.ALL) { if (f.matches(entry)) { return getIconPath(f.getIcon()); @@ -60,7 +61,7 @@ public class FileIconManager { } } - return entry.isDirectory() ? (open ? "default_folder_opened.svg" : "default_folder.svg") : "default_file.svg"; + return entry.getKind() == FileKind.DIRECTORY ? (open ? "default_folder_opened.svg" : "default_folder.svg") : "default_file.svg"; } private static String getIconPath(String name) { diff --git a/app/src/main/java/io/xpipe/app/browser/icon/FileType.java b/app/src/main/java/io/xpipe/app/browser/icon/FileType.java index cbc44d0b..a42bd328 100644 --- a/app/src/main/java/io/xpipe/app/browser/icon/FileType.java +++ b/app/src/main/java/io/xpipe/app/browser/icon/FileType.java @@ -1,6 +1,7 @@ package io.xpipe.app.browser.icon; import io.xpipe.app.core.AppResources; +import io.xpipe.core.store.FileKind; import io.xpipe.core.store.FileSystem; import lombok.Getter; @@ -65,7 +66,7 @@ public interface FileType { @Override public boolean matches(FileSystem.FileEntry entry) { - if (entry.isDirectory()) { + if (entry.getKind() == FileKind.DIRECTORY) { return false; } diff --git a/app/src/main/java/io/xpipe/app/core/App.java b/app/src/main/java/io/xpipe/app/core/App.java index 64715be5..94136f7d 100644 --- a/app/src/main/java/io/xpipe/app/core/App.java +++ b/app/src/main/java/io/xpipe/app/core/App.java @@ -12,7 +12,6 @@ import javafx.application.Application; import javafx.application.Platform; import javafx.beans.binding.Bindings; import javafx.scene.image.Image; -import javafx.scene.input.MouseEvent; import javafx.stage.Stage; import javax.imageio.ImageIO; @@ -64,12 +63,6 @@ public class App extends Application { public void setupWindow() { var content = new AppLayoutComp(); - content.apply(struc -> { - struc.get().addEventFilter(MouseEvent.MOUSE_CLICKED, event -> { - // AppActionLinkDetector.detectOnFocus(); - }); - }); - var titleBinding = Bindings.createStringBinding( () -> { var base = String.format( diff --git a/app/src/main/java/io/xpipe/app/core/mode/BaseMode.java b/app/src/main/java/io/xpipe/app/core/mode/BaseMode.java index e3b48d4f..17e2994f 100644 --- a/app/src/main/java/io/xpipe/app/core/mode/BaseMode.java +++ b/app/src/main/java/io/xpipe/app/core/mode/BaseMode.java @@ -9,6 +9,7 @@ import io.xpipe.app.storage.DataStorage; import io.xpipe.app.util.DefaultSecretValue; import io.xpipe.app.util.FileBridge; import io.xpipe.app.util.LockedSecretValue; +import io.xpipe.core.impl.LocalStore; import io.xpipe.core.util.JacksonMapper; public class BaseMode extends OperationMode { @@ -37,6 +38,7 @@ public class BaseMode extends OperationMode { JacksonMapper.configure(objectMapper -> { objectMapper.registerSubtypes(LockedSecretValue.class, DefaultSecretValue.class); }); + LocalStore.init(); AppPrefs.init(); AppCharsets.init(); AppCharsetter.init(); diff --git a/app/src/main/java/io/xpipe/app/issue/TerminalErrorHandler.java b/app/src/main/java/io/xpipe/app/issue/TerminalErrorHandler.java index fc913158..b27599bd 100644 --- a/app/src/main/java/io/xpipe/app/issue/TerminalErrorHandler.java +++ b/app/src/main/java/io/xpipe/app/issue/TerminalErrorHandler.java @@ -47,6 +47,8 @@ public class TerminalErrorHandler implements ErrorHandler { event.clearAttachments(); handleSecondaryException(event, r); return; + } else { + PlatformState.setCurrent(PlatformState.RUNNING); } } } diff --git a/core/src/main/java/io/xpipe/core/impl/LocalStore.java b/core/src/main/java/io/xpipe/core/impl/LocalStore.java index 0b54f98e..0b5bfc03 100644 --- a/core/src/main/java/io/xpipe/core/impl/LocalStore.java +++ b/core/src/main/java/io/xpipe/core/impl/LocalStore.java @@ -2,131 +2,38 @@ package io.xpipe.core.impl; import com.fasterxml.jackson.annotation.JsonTypeName; import io.xpipe.core.process.ProcessControlProvider; -import io.xpipe.core.process.ShellDialects; import io.xpipe.core.process.ShellControl; -import io.xpipe.core.store.ConnectionFileSystem; import io.xpipe.core.store.FileSystem; -import io.xpipe.core.store.FileSystemStore; import io.xpipe.core.store.ShellStore; import io.xpipe.core.util.JacksonizedValue; -import java.nio.file.Path; - @JsonTypeName("local") public class LocalStore extends JacksonizedValue implements ShellStore { private static ShellControl local; private static FileSystem localFileSystem; - public static ShellControl getShell() throws Exception { + public static void init() throws Exception { + local = ProcessControlProvider.createLocal(false).start(); + localFileSystem = new LocalStore().createFileSystem(); + } + + public static ShellControl getShell() { if (local == null) { - local = ProcessControlProvider.createLocal(false).start(); + throw new IllegalStateException("Local shell not initialized yet"); } return local; } - public static FileSystem getFileSystem() throws Exception { + public static FileSystem getFileSystem() { if (localFileSystem == null) { - localFileSystem = new LocalStore().createFileSystem(); + throw new IllegalStateException("Local file system not initialized yet"); } return localFileSystem; } - @Override - public FileSystem createFileSystem() { - return new ConnectionFileSystem(ShellStore.createLocal().control(), LocalStore.this) { - - @Override - public FileSystemStore getStore() { - return LocalStore.this; - } - - - private Path wrap(String file) { - for (var e : System.getenv().entrySet()) { - file = file.replace( - ShellDialects.getPlatformDefault().environmentVariable(e.getKey()), - e.getValue()); - } - return Path.of(file); - } - -// @Override -// public boolean exists(String file) { -// return Files.exists(wrap(file)); -// } -// -// @Override -// public void delete(String file) throws Exception { -// Files.delete(wrap(file)); -// } -// -// @Override -// public void copy(String file, String newFile) throws Exception { -// Files.copy(wrap(file), wrap(newFile), StandardCopyOption.REPLACE_EXISTING); -// } -// -// @Override -// public void move(String file, String newFile) throws Exception { -// Files.move(wrap(file), wrap(newFile), StandardCopyOption.REPLACE_EXISTING); -// } -// -// @Override -// public boolean mkdirs(String file) throws Exception { -// try { -// Files.createDirectories(wrap(file)); -// return true; -// } catch (Exception ex) { -// return false; -// } -// } -// -// @Override -// public void touch(String file) throws Exception { -// if (exists(file)) { -// return; -// } -// -// Files.createFile(wrap(file)); -// } -// -// @Override -// public boolean isDirectory(String file) throws Exception { -// return Files.isDirectory(wrap(file)); -// } -// -// @Override -// public Stream listFiles(String file) throws Exception { -// return Files.list(wrap(file)).map(path -> { -// try { -// var date = Files.getLastModifiedTime(path); -// var size = Files.isDirectory(path) ? 0 : Files.size(path); -// return new FileEntry( -// this, -// path.toString(), -// date.toInstant(), -// Files.isDirectory(path), -// Files.isHidden(path), -// Files.isExecutable(path), -// size); -// } catch (IOException e) { -// throw new UncheckedIOException(e); -// } -// }); -// } -// -// @Override -// public List listRoots() throws Exception { -// return StreamSupport.stream( -// FileSystems.getDefault().getRootDirectories().spliterator(), false) -// .map(path -> path.toString()) -// .toList(); -// } - }; - } - @Override public ShellControl createBasicControl() { return ProcessControlProvider.createLocal(true); diff --git a/core/src/main/java/io/xpipe/core/store/FileKind.java b/core/src/main/java/io/xpipe/core/store/FileKind.java new file mode 100644 index 00000000..b71fc8d0 --- /dev/null +++ b/core/src/main/java/io/xpipe/core/store/FileKind.java @@ -0,0 +1,9 @@ +package io.xpipe.core.store; + +public enum FileKind { + + FILE, + DIRECTORY, + LINK, + OTHER; +} diff --git a/core/src/main/java/io/xpipe/core/store/FileSystem.java b/core/src/main/java/io/xpipe/core/store/FileSystem.java index c3487a3b..be0c0080 100644 --- a/core/src/main/java/io/xpipe/core/store/FileSystem.java +++ b/core/src/main/java/io/xpipe/core/store/FileSystem.java @@ -22,29 +22,31 @@ public interface FileSystem extends Closeable, AutoCloseable { @NonNull String path; Instant date; - boolean directory; boolean hidden; Boolean executable; long size; String mode; + @NonNull + FileKind kind; public FileEntry( - @NonNull FileSystem fileSystem, @NonNull String path, Instant date, boolean directory, boolean hidden, Boolean executable, + @NonNull FileSystem fileSystem, @NonNull String path, Instant date, boolean hidden, Boolean executable, long size, - String mode + String mode, + @NonNull FileKind kind ) { this.fileSystem = fileSystem; this.mode = mode; - this.path = directory ? FileNames.toDirectory(path) : path; + this.kind = kind; + this.path = kind == FileKind.DIRECTORY ? FileNames.toDirectory(path) : path; this.date = date; - this.directory = directory; this.hidden = hidden; this.executable = executable; this.size = size; } public static FileEntry ofDirectory(FileSystem fileSystem, String path) { - return new FileEntry(fileSystem, path, Instant.now(), true, false, false, 0, null); + return new FileEntry(fileSystem, path, Instant.now(), true, false, 0, null, FileKind.DIRECTORY); } } @@ -79,7 +81,7 @@ public interface FileSystem extends Closeable, AutoCloseable { default Stream listFilesRecursively(String file) throws Exception { return listFiles(file).flatMap(fileEntry -> { - if (!fileEntry.isDirectory()) { + if (fileEntry.getKind() != FileKind.DIRECTORY) { return Stream.of(fileEntry); } diff --git a/ext/base/src/main/java/io/xpipe/ext/base/browser/BrowseInNativeManagerAction.java b/ext/base/src/main/java/io/xpipe/ext/base/browser/BrowseInNativeManagerAction.java index 583ecf42..8c5f5dbe 100644 --- a/ext/base/src/main/java/io/xpipe/ext/base/browser/BrowseInNativeManagerAction.java +++ b/ext/base/src/main/java/io/xpipe/ext/base/browser/BrowseInNativeManagerAction.java @@ -6,6 +6,7 @@ import io.xpipe.app.browser.action.LeafAction; import io.xpipe.core.process.OsType; import io.xpipe.core.process.ShellControl; import io.xpipe.core.process.ShellDialect; +import io.xpipe.core.store.FileKind; import java.util.List; @@ -19,21 +20,21 @@ public class BrowseInNativeManagerAction implements LeafAction { var e = entry.getRawFileEntry().getPath(); switch (OsType.getLocal()) { case OsType.Windows windows -> { - if (entry.getRawFileEntry().isDirectory()) { + if (entry.getRawFileEntry().getKind() == FileKind.DIRECTORY) { sc.executeSimpleCommand("explorer " + d.fileArgument(e)); } else { sc.executeSimpleCommand("explorer /select," + d.fileArgument(e)); } } case OsType.Linux linux -> { - var action = entry.getRawFileEntry().isDirectory() ? "org.freedesktop.FileManager1.ShowFolders" : "org.freedesktop.FileManager1.ShowItems"; + var action = entry.getRawFileEntry().getKind() == FileKind.DIRECTORY ? "org.freedesktop.FileManager1.ShowFolders" : "org.freedesktop.FileManager1.ShowItems"; var dbus = String.format(""" dbus-send --session --print-reply --dest=org.freedesktop.FileManager1 --type=method_call /org/freedesktop/FileManager1 %s array:string:"file://%s" string:"" """, action, entry.getRawFileEntry().getPath()); sc.executeSimpleCommand(dbus); } case OsType.MacOs macOs -> { - sc.executeSimpleCommand("open " + (entry.getRawFileEntry().isDirectory() ? "" : "-R ") + sc.executeSimpleCommand("open " + (entry.getRawFileEntry().getKind() == FileKind.DIRECTORY ? "" : "-R ") + d.fileArgument(entry.getRawFileEntry().getPath())); } } diff --git a/ext/base/src/main/java/io/xpipe/ext/base/browser/EditFileAction.java b/ext/base/src/main/java/io/xpipe/ext/base/browser/EditFileAction.java index 89275b81..da6659a4 100644 --- a/ext/base/src/main/java/io/xpipe/ext/base/browser/EditFileAction.java +++ b/ext/base/src/main/java/io/xpipe/ext/base/browser/EditFileAction.java @@ -5,6 +5,7 @@ import io.xpipe.app.browser.OpenFileSystemModel; import io.xpipe.app.browser.action.LeafAction; import io.xpipe.app.prefs.AppPrefs; import io.xpipe.app.util.FileOpener; +import io.xpipe.core.store.FileKind; import javafx.scene.Node; import org.kordamp.ikonli.javafx.FontIcon; @@ -31,7 +32,7 @@ public class EditFileAction implements LeafAction { @Override public boolean isApplicable(OpenFileSystemModel model, List entries) { - return entries.stream().noneMatch(entry -> entry.getRawFileEntry().isDirectory()); + return entries.stream().allMatch(entry -> entry.getRawFileEntry().getKind() == FileKind.FILE); } @Override diff --git a/ext/base/src/main/java/io/xpipe/ext/base/browser/OpenDirectoryAction.java b/ext/base/src/main/java/io/xpipe/ext/base/browser/OpenDirectoryAction.java index 5aaf9336..4532a895 100644 --- a/ext/base/src/main/java/io/xpipe/ext/base/browser/OpenDirectoryAction.java +++ b/ext/base/src/main/java/io/xpipe/ext/base/browser/OpenDirectoryAction.java @@ -3,6 +3,7 @@ package io.xpipe.ext.base.browser; import io.xpipe.app.browser.BrowserEntry; import io.xpipe.app.browser.OpenFileSystemModel; import io.xpipe.app.browser.action.LeafAction; +import io.xpipe.core.store.FileKind; import javafx.scene.Node; import javafx.scene.input.KeyCode; import javafx.scene.input.KeyCodeCombination; @@ -30,7 +31,7 @@ public class OpenDirectoryAction implements LeafAction { @Override public boolean isApplicable(OpenFileSystemModel model, List entries) { - return entries.size() == 1 && entries.stream().allMatch(entry -> entry.getRawFileEntry().isDirectory()); + return entries.size() == 1 && entries.stream().allMatch(entry -> entry.getRawFileEntry().getKind() == FileKind.DIRECTORY); } @Override diff --git a/ext/base/src/main/java/io/xpipe/ext/base/browser/OpenDirectoryInNewTabAction.java b/ext/base/src/main/java/io/xpipe/ext/base/browser/OpenDirectoryInNewTabAction.java index 31a4e478..22c74311 100644 --- a/ext/base/src/main/java/io/xpipe/ext/base/browser/OpenDirectoryInNewTabAction.java +++ b/ext/base/src/main/java/io/xpipe/ext/base/browser/OpenDirectoryInNewTabAction.java @@ -3,6 +3,7 @@ package io.xpipe.ext.base.browser; import io.xpipe.app.browser.BrowserEntry; import io.xpipe.app.browser.OpenFileSystemModel; import io.xpipe.app.browser.action.LeafAction; +import io.xpipe.core.store.FileKind; import javafx.scene.Node; import javafx.scene.input.KeyCode; import javafx.scene.input.KeyCodeCombination; @@ -30,7 +31,7 @@ public class OpenDirectoryInNewTabAction implements LeafAction { @Override public boolean isApplicable(OpenFileSystemModel model, List entries) { - return entries.size() == 1 && entries.stream().allMatch(entry -> entry.getRawFileEntry().isDirectory()); + return entries.size() == 1 && entries.stream().allMatch(entry -> entry.getRawFileEntry().getKind() == FileKind.DIRECTORY); } @Override diff --git a/ext/base/src/main/java/io/xpipe/ext/base/browser/OpenFileDefaultAction.java b/ext/base/src/main/java/io/xpipe/ext/base/browser/OpenFileDefaultAction.java index 52ba759d..72d6e85c 100644 --- a/ext/base/src/main/java/io/xpipe/ext/base/browser/OpenFileDefaultAction.java +++ b/ext/base/src/main/java/io/xpipe/ext/base/browser/OpenFileDefaultAction.java @@ -4,6 +4,7 @@ import io.xpipe.app.browser.BrowserEntry; import io.xpipe.app.browser.OpenFileSystemModel; import io.xpipe.app.browser.action.LeafAction; import io.xpipe.app.util.FileOpener; +import io.xpipe.core.store.FileKind; import javafx.scene.Node; import javafx.scene.input.KeyCode; import javafx.scene.input.KeyCodeCombination; @@ -33,7 +34,7 @@ public class OpenFileDefaultAction implements LeafAction { @Override public boolean isApplicable(OpenFileSystemModel model, List entries) { - return entries.stream().noneMatch(entry -> entry.getRawFileEntry().isDirectory()); + return entries.stream().allMatch(entry -> entry.getRawFileEntry().getKind() == FileKind.FILE); } @Override diff --git a/ext/base/src/main/java/io/xpipe/ext/base/browser/OpenFileWithAction.java b/ext/base/src/main/java/io/xpipe/ext/base/browser/OpenFileWithAction.java index 2507df28..ef562cc5 100644 --- a/ext/base/src/main/java/io/xpipe/ext/base/browser/OpenFileWithAction.java +++ b/ext/base/src/main/java/io/xpipe/ext/base/browser/OpenFileWithAction.java @@ -8,6 +8,7 @@ import io.xpipe.app.browser.action.LeafAction; import io.xpipe.core.process.OsType; import io.xpipe.core.process.ShellControl; import io.xpipe.core.process.ShellDialect; +import io.xpipe.core.store.FileKind; import javafx.scene.Node; import javafx.scene.input.KeyCode; import javafx.scene.input.KeyCodeCombination; @@ -58,7 +59,7 @@ public class OpenFileWithAction implements LeafAction { return os.isPresent() && os.get().getOsType().equals(OsType.WINDOWS) && entries.size() == 1 - && entries.stream().noneMatch(entry -> entry.getRawFileEntry().isDirectory()); + && entries.stream().allMatch(entry -> entry.getRawFileEntry().getKind() == FileKind.FILE); } @Override diff --git a/ext/base/src/main/java/io/xpipe/ext/base/browser/OpenTerminalAction.java b/ext/base/src/main/java/io/xpipe/ext/base/browser/OpenTerminalAction.java index 7ee2847f..d529a6c2 100644 --- a/ext/base/src/main/java/io/xpipe/ext/base/browser/OpenTerminalAction.java +++ b/ext/base/src/main/java/io/xpipe/ext/base/browser/OpenTerminalAction.java @@ -3,6 +3,7 @@ package io.xpipe.ext.base.browser; import io.xpipe.app.browser.BrowserEntry; import io.xpipe.app.browser.OpenFileSystemModel; import io.xpipe.app.browser.action.LeafAction; +import io.xpipe.core.store.FileKind; import javafx.scene.Node; import javafx.scene.input.KeyCode; import javafx.scene.input.KeyCodeCombination; @@ -46,7 +47,7 @@ public class OpenTerminalAction implements LeafAction { @Override public boolean isApplicable(OpenFileSystemModel model, List entries) { - return entries.stream().allMatch(entry -> entry.getRawFileEntry().isDirectory()); + return entries.stream().allMatch(entry -> entry.getRawFileEntry().getKind() == FileKind.DIRECTORY); } @Override diff --git a/ext/base/src/main/java/io/xpipe/ext/base/browser/PasteAction.java b/ext/base/src/main/java/io/xpipe/ext/base/browser/PasteAction.java index bf3bc178..d41707c0 100644 --- a/ext/base/src/main/java/io/xpipe/ext/base/browser/PasteAction.java +++ b/ext/base/src/main/java/io/xpipe/ext/base/browser/PasteAction.java @@ -4,6 +4,7 @@ import io.xpipe.app.browser.BrowserClipboard; import io.xpipe.app.browser.BrowserEntry; import io.xpipe.app.browser.OpenFileSystemModel; import io.xpipe.app.browser.action.LeafAction; +import io.xpipe.core.store.FileKind; import javafx.scene.Node; import javafx.scene.input.KeyCode; import javafx.scene.input.KeyCodeCombination; @@ -21,7 +22,7 @@ public class PasteAction implements LeafAction { return; } - var target = entries.size() == 1 && entries.get(0).getRawFileEntry().isDirectory() ? entries.get(0).getRawFileEntry() : model.getCurrentDirectory(); + var target = entries.size() == 1 && entries.get(0).getRawFileEntry().getKind() == FileKind.DIRECTORY ? entries.get(0).getRawFileEntry() : model.getCurrentDirectory(); var files = clipboard.getEntries(); model.dropFilesIntoAsync(target, files, true); } @@ -38,7 +39,7 @@ public class PasteAction implements LeafAction { @Override public boolean isApplicable(OpenFileSystemModel model, List entries) { - return entries.size() < 2 && entries.stream().allMatch(entry -> entry.getRawFileEntry().isDirectory()); + return entries.size() < 2 && entries.stream().allMatch(entry -> entry.getRawFileEntry().getKind() == FileKind.DIRECTORY); } @Override diff --git a/ext/base/src/main/java/io/xpipe/ext/base/browser/RunAction.java b/ext/base/src/main/java/io/xpipe/ext/base/browser/RunAction.java index 12f0e3d1..263e222a 100644 --- a/ext/base/src/main/java/io/xpipe/ext/base/browser/RunAction.java +++ b/ext/base/src/main/java/io/xpipe/ext/base/browser/RunAction.java @@ -5,6 +5,7 @@ import io.xpipe.app.browser.OpenFileSystemModel; import io.xpipe.app.browser.action.MultiExecuteAction; import io.xpipe.core.process.OsType; import io.xpipe.core.process.ShellControl; +import io.xpipe.core.store.FileKind; import io.xpipe.core.store.FileSystem; import javafx.scene.Node; import org.kordamp.ikonli.javafx.FontIcon; @@ -14,7 +15,7 @@ import java.util.List; public class RunAction extends MultiExecuteAction { private boolean isExecutable(FileSystem.FileEntry e) { - if (e.isDirectory()) { + if (e.getKind() != FileKind.FILE) { return false; }