diff --git a/app/src/main/java/io/xpipe/app/browser/file/BrowserContextMenu.java b/app/src/main/java/io/xpipe/app/browser/file/BrowserContextMenu.java index 9fb3512e1..4fb3cc424 100644 --- a/app/src/main/java/io/xpipe/app/browser/file/BrowserContextMenu.java +++ b/app/src/main/java/io/xpipe/app/browser/file/BrowserContextMenu.java @@ -41,10 +41,18 @@ public final class BrowserContextMenu extends ContextMenu { selected.add(source); } + if (model.isClosed()) { + return; + } + for (BrowserAction.Category cat : BrowserAction.Category.values()) { var all = BrowserAction.ALL.stream() .filter(browserAction -> browserAction.getCategory() == cat) .filter(browserAction -> { + if (model.isClosed()) { + return false; + } + var used = browserAction.resolveFilesIfNeeded(selected); if (!browserAction.isApplicable(model, used)) { return false; @@ -66,6 +74,10 @@ public final class BrowserContextMenu extends ContextMenu { } for (BrowserAction a : all) { + if (model.isClosed()) { + return; + } + var used = a.resolveFilesIfNeeded(selected); getItems().add(a.toMenuItem(model, used)); } diff --git a/app/src/main/java/io/xpipe/app/fxcomps/impl/ContextualFileReferenceChoiceComp.java b/app/src/main/java/io/xpipe/app/fxcomps/impl/ContextualFileReferenceChoiceComp.java index 66f91c71d..ea0513053 100644 --- a/app/src/main/java/io/xpipe/app/fxcomps/impl/ContextualFileReferenceChoiceComp.java +++ b/app/src/main/java/io/xpipe/app/fxcomps/impl/ContextualFileReferenceChoiceComp.java @@ -7,37 +7,56 @@ import io.xpipe.app.core.window.AppWindowHelper; import io.xpipe.app.fxcomps.Comp; import io.xpipe.app.fxcomps.CompStructure; import io.xpipe.app.fxcomps.SimpleCompStructure; +import io.xpipe.app.fxcomps.augment.GrowAugment; import io.xpipe.app.issue.ErrorEvent; import io.xpipe.app.prefs.AppPrefs; import io.xpipe.app.storage.ContextualFileReference; import io.xpipe.app.storage.DataStorage; import io.xpipe.app.storage.DataStoreEntryRef; +import io.xpipe.app.terminal.ExternalTerminalType; import io.xpipe.core.store.FileNames; import io.xpipe.core.store.FileSystemStore; import javafx.application.Platform; import javafx.beans.property.Property; import javafx.beans.property.SimpleObjectProperty; +import javafx.scene.control.Cell; +import javafx.scene.control.ComboBox; +import javafx.scene.control.ListCell; import javafx.scene.layout.HBox; import javafx.scene.layout.Priority; import atlantafx.base.theme.Styles; +import javafx.scene.paint.Color; +import lombok.Value; import org.kordamp.ikonli.javafx.FontIcon; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.StandardCopyOption; import java.util.ArrayList; +import java.util.List; public class ContextualFileReferenceChoiceComp extends Comp> { + @Value + public static class PreviousFileReference { + + String displayName; + Path path; + } + private final Property> fileSystem; private final Property filePath; private final boolean allowSync; + private final List previousFileReferences; public ContextualFileReferenceChoiceComp( - Property> fileSystem, Property filePath, boolean allowSync) { + Property> fileSystem, Property filePath, boolean allowSync, + List previousFileReferences + ) { this.allowSync = allowSync; + this.previousFileReferences = previousFileReferences; this.fileSystem = new SimpleObjectProperty<>(); fileSystem.subscribe(val -> { this.fileSystem.setValue(val); @@ -50,11 +69,7 @@ public class ContextualFileReferenceChoiceComp extends Comp> @Override public CompStructure createBase() { - var fileNameComp = new TextFieldComp(filePath) - .apply(struc -> HBox.setHgrow(struc.get(), Priority.ALWAYS)) - .styleClass(Styles.LEFT_PILL) - .grow(false, true); - + var path = previousFileReferences.isEmpty() ? createTextField() : createComboBox(); var fileBrowseButton = new ButtonComp(null, new FontIcon("mdi2f-folder-open-outline"), () -> { BrowserChooserComp.openSingleFile( () -> fileSystem.getValue(), @@ -112,7 +127,7 @@ public class ContextualFileReferenceChoiceComp extends Comp> gitShareButton.styleClass(Styles.RIGHT_PILL).grow(false, true); var nodes = new ArrayList>(); - nodes.add(fileNameComp); + nodes.add(path); nodes.add(fileBrowseButton); if (allowSync) { nodes.add(gitShareButton); @@ -127,4 +142,43 @@ public class ContextualFileReferenceChoiceComp extends Comp> return new SimpleCompStructure<>(layout.createStructure().get()); } + + private Comp createComboBox() { + var combo = new ComboBox(); + combo.setEditable(true); + combo.setMaxWidth(2000); + combo.setCellFactory(param -> { + return new ListCell<>() { + @Override + protected void updateItem(String item, boolean empty) { + super.updateItem(item, empty); + if (empty) { + return; + } + + var display = previousFileReferences.stream() + .filter(ref -> ref.path.toString().equals(item)) + .findFirst() + .map(previousFileReference -> previousFileReference.getDisplayName()) + .orElse(item); + setText(display); + } + }; + }); + previousFileReferences.forEach(previousFileReference -> { + combo.getItems().add(previousFileReference.getPath().toString()); + }); + HBox.setHgrow(combo, Priority.ALWAYS); + combo.getStyleClass().add(Styles.LEFT_PILL); + GrowAugment.create(false, true).augment(combo); + return Comp.of(() -> combo); + } + + private Comp createTextField() { + var fileNameComp = new TextFieldComp(filePath) + .apply(struc -> HBox.setHgrow(struc.get(), Priority.ALWAYS)) + .styleClass(Styles.LEFT_PILL) + .grow(false, true); + return fileNameComp; + } } diff --git a/app/src/main/java/io/xpipe/app/storage/DataStorageSyncHandler.java b/app/src/main/java/io/xpipe/app/storage/DataStorageSyncHandler.java index 86e3b5513..2710e0d7c 100644 --- a/app/src/main/java/io/xpipe/app/storage/DataStorageSyncHandler.java +++ b/app/src/main/java/io/xpipe/app/storage/DataStorageSyncHandler.java @@ -3,6 +3,7 @@ package io.xpipe.app.storage; import io.xpipe.app.ext.ProcessControlProvider; import java.nio.file.Path; +import java.util.List; public interface DataStorageSyncHandler { @@ -33,4 +34,6 @@ public interface DataStorageSyncHandler { void handleDeletion(Path target, String name); Path getDirectory(); + + List getSavedDataFiles(); }