From dfcb90bd164be8262737ce1b94485df7a49d97f0 Mon Sep 17 00:00:00 2001 From: crschnick Date: Sun, 7 Apr 2024 08:07:05 +0000 Subject: [PATCH] Rework --- .../app/browser/fs/OpenFileSystemModel.java | 2 +- .../session/BrowserAbstractSessionModel.java | 27 ++++++++++--- .../browser/session/BrowserChooserComp.java | 24 +++-------- .../browser/session/BrowserSessionEntry.java | 8 ++-- .../browser/session/BrowserSessionModel.java | 2 +- .../ContextualFileReferenceChoiceComp.java | 31 +++++++------- .../app/fxcomps/impl/StringSourceComp.java | 40 +++++++++++++------ .../io/xpipe/app/storage/DataStoreEntry.java | 2 +- lang/app/strings/translations_en.properties | 2 +- lang/proc/texts/sshOptions_de.md | 2 +- lang/proc/texts/sshOptions_en.md | 2 +- 11 files changed, 80 insertions(+), 62 deletions(-) diff --git a/app/src/main/java/io/xpipe/app/browser/fs/OpenFileSystemModel.java b/app/src/main/java/io/xpipe/app/browser/fs/OpenFileSystemModel.java index 775344615..0d21cc3ac 100644 --- a/app/src/main/java/io/xpipe/app/browser/fs/OpenFileSystemModel.java +++ b/app/src/main/java/io/xpipe/app/browser/fs/OpenFileSystemModel.java @@ -35,7 +35,7 @@ import java.util.Optional; import java.util.stream.Stream; @Getter -public final class OpenFileSystemModel extends BrowserSessionEntry { +public final class OpenFileSystemModel extends BrowserSessionEntry { private final Property filter = new SimpleStringProperty(); private final BrowserFileListModel fileList; diff --git a/app/src/main/java/io/xpipe/app/browser/session/BrowserAbstractSessionModel.java b/app/src/main/java/io/xpipe/app/browser/session/BrowserAbstractSessionModel.java index 10eb1a33a..d3229ff9e 100644 --- a/app/src/main/java/io/xpipe/app/browser/session/BrowserAbstractSessionModel.java +++ b/app/src/main/java/io/xpipe/app/browser/session/BrowserAbstractSessionModel.java @@ -1,28 +1,43 @@ package io.xpipe.app.browser.session; +import io.xpipe.app.util.BooleanScope; import io.xpipe.app.util.ThreadHelper; +import javafx.beans.property.BooleanProperty; import javafx.beans.property.Property; +import javafx.beans.property.SimpleBooleanProperty; import javafx.beans.property.SimpleObjectProperty; import javafx.collections.FXCollections; import javafx.collections.ObservableList; import lombok.Getter; @Getter -public class BrowserAbstractSessionModel { +public class BrowserAbstractSessionModel> { protected final ObservableList sessionEntries = FXCollections.observableArrayList(); protected final Property selectedEntry = new SimpleObjectProperty<>(); - public void closeAsync(BrowserSessionEntry open) { + public void closeAsync(BrowserSessionEntry e) { ThreadHelper.runAsync(() -> { - closeSync(open); + closeSync(e); }); } - void closeSync(BrowserSessionEntry open) { - open.close(); + public void openSync(T e, BooleanProperty externalBusy) throws Exception { + try (var b = new BooleanScope(externalBusy != null ? externalBusy : new SimpleBooleanProperty()).start()) { + e.init(); + // Prevent multiple calls from interfering with each other + synchronized (this) { + sessionEntries.add(e); + // The tab pane doesn't automatically select new tabs + selectedEntry.setValue(e); + } + } + } + + void closeSync(BrowserSessionEntry e) { + e.close(); synchronized (BrowserAbstractSessionModel.this) { - this.sessionEntries.remove(open); + this.sessionEntries.remove(e); } } } diff --git a/app/src/main/java/io/xpipe/app/browser/session/BrowserChooserComp.java b/app/src/main/java/io/xpipe/app/browser/session/BrowserChooserComp.java index 14c9ccd88..0fc206e63 100644 --- a/app/src/main/java/io/xpipe/app/browser/session/BrowserChooserComp.java +++ b/app/src/main/java/io/xpipe/app/browser/session/BrowserChooserComp.java @@ -1,7 +1,7 @@ package io.xpipe.app.browser.session; import atlantafx.base.controls.Spacer; -import io.xpipe.app.browser.*; +import io.xpipe.app.browser.BrowserBookmarkComp; import io.xpipe.app.browser.file.BrowserEntry; import io.xpipe.app.browser.fs.OpenFileSystemComp; import io.xpipe.app.browser.fs.OpenFileSystemModel; @@ -21,7 +21,6 @@ import io.xpipe.app.util.ThreadHelper; import io.xpipe.core.store.FileSystemStore; import io.xpipe.core.store.ShellStore; import javafx.beans.property.BooleanProperty; -import javafx.beans.property.Property; import javafx.collections.ListChangeListener; import javafx.geometry.Insets; import javafx.geometry.Orientation; @@ -45,34 +44,21 @@ public class BrowserChooserComp extends SimpleComp { } public static void openSingleFile( - Supplier> store, Consumer file) { + Supplier> store, Consumer file, boolean save) { PlatformThread.runLaterIfNeeded(() -> { var model = new BrowserChooserModel(OpenFileSystemModel.SelectionMode.SINGLE_FILE); var comp = new BrowserChooserComp(model) .apply(struc -> struc.get().setPrefSize(1200, 700)) .apply(struc -> AppFont.normal(struc.get())); - var window = AppWindowHelper.sideWindow(AppI18n.get("openFileTitle"), stage -> comp, false, null); + var window = AppWindowHelper.sideWindow(AppI18n.get(save ? "saveFileTitle" : "openFileTitle"), stage -> comp, false, null); model.setOnFinish(fileStores -> { file.accept(fileStores.size() > 0 ? fileStores.getFirst() : null); window.close(); }); window.show(); - model.openFileSystemAsync(store.get(), null, null); - }); - } - - public static void saveSingleFile(Property file) { - PlatformThread.runLaterIfNeeded(() -> { - var model = new BrowserChooserModel(OpenFileSystemModel.SelectionMode.SINGLE_FILE); - var comp = new BrowserChooserComp(model) - .apply(struc -> struc.get().setPrefSize(1200, 700)) - .apply(struc -> AppFont.normal(struc.get())); - var window = AppWindowHelper.sideWindow(AppI18n.get("saveFileTitle"), stage -> comp, true, null); - model.setOnFinish(fileStores -> { - file.setValue(fileStores.size() > 0 ? fileStores.getFirst() : null); - window.close(); + ThreadHelper.runAsync(() -> { + model.openFileSystemAsync(store.get(), null, null); }); - window.show(); }); } diff --git a/app/src/main/java/io/xpipe/app/browser/session/BrowserSessionEntry.java b/app/src/main/java/io/xpipe/app/browser/session/BrowserSessionEntry.java index 8b14eb456..702d581a5 100644 --- a/app/src/main/java/io/xpipe/app/browser/session/BrowserSessionEntry.java +++ b/app/src/main/java/io/xpipe/app/browser/session/BrowserSessionEntry.java @@ -3,21 +3,21 @@ package io.xpipe.app.browser.session; import io.xpipe.app.fxcomps.Comp; import io.xpipe.app.storage.DataStorage; import io.xpipe.app.storage.DataStoreEntryRef; -import io.xpipe.core.store.FileSystemStore; +import io.xpipe.core.store.DataStore; import javafx.beans.property.BooleanProperty; import javafx.beans.property.SimpleBooleanProperty; import lombok.Getter; @Getter -public abstract class BrowserSessionEntry { +public abstract class BrowserSessionEntry { - protected final DataStoreEntryRef entry; + protected final DataStoreEntryRef entry; protected final BooleanProperty busy = new SimpleBooleanProperty(); protected final BrowserAbstractSessionModel browserModel; protected final String name; protected final String tooltip; - public BrowserSessionEntry(BrowserAbstractSessionModel browserModel, DataStoreEntryRef entry) { + public BrowserSessionEntry(BrowserAbstractSessionModel browserModel, DataStoreEntryRef entry) { this.browserModel = browserModel; this.entry = entry; this.name = DataStorage.get().getStoreDisplayName(entry.get()); diff --git a/app/src/main/java/io/xpipe/app/browser/session/BrowserSessionModel.java b/app/src/main/java/io/xpipe/app/browser/session/BrowserSessionModel.java index 6756d4fb4..d05f45e47 100644 --- a/app/src/main/java/io/xpipe/app/browser/session/BrowserSessionModel.java +++ b/app/src/main/java/io/xpipe/app/browser/session/BrowserSessionModel.java @@ -21,7 +21,7 @@ import lombok.Getter; import java.util.ArrayList; @Getter -public class BrowserSessionModel extends BrowserAbstractSessionModel { +public class BrowserSessionModel extends BrowserAbstractSessionModel> { public static final BrowserSessionModel DEFAULT = new BrowserSessionModel(BrowserSavedStateImpl.load()); 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 c6751244f..b9191cd95 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 @@ -6,7 +6,9 @@ import io.xpipe.app.comp.base.ButtonComp; import io.xpipe.app.core.AppI18n; import io.xpipe.app.core.AppLayoutModel; import io.xpipe.app.core.AppWindowHelper; -import io.xpipe.app.fxcomps.SimpleComp; +import io.xpipe.app.fxcomps.Comp; +import io.xpipe.app.fxcomps.CompStructure; +import io.xpipe.app.fxcomps.SimpleCompStructure; import io.xpipe.app.issue.ErrorEvent; import io.xpipe.app.prefs.AppPrefs; import io.xpipe.app.storage.ContextualFileReference; @@ -22,7 +24,6 @@ import javafx.beans.value.ObservableValue; import javafx.scene.control.Alert; import javafx.scene.layout.HBox; import javafx.scene.layout.Priority; -import javafx.scene.layout.Region; import org.kordamp.ikonli.javafx.FontIcon; import java.nio.file.Files; @@ -30,7 +31,7 @@ import java.nio.file.Path; import java.nio.file.StandardCopyOption; import java.util.List; -public class ContextualFileReferenceChoiceComp extends SimpleComp { +public class ContextualFileReferenceChoiceComp extends Comp> { private final Property> fileSystem; private final Property filePath; @@ -45,23 +46,23 @@ public class ContextualFileReferenceChoiceComp extends SimpleComp { } @Override - protected Region createSimple() { + public CompStructure createBase() { var fileNameComp = new TextFieldComp(filePath) .apply(struc -> HBox.setHgrow(struc.get(), Priority.ALWAYS)) .styleClass(Styles.LEFT_PILL) .grow(false, true); var fileBrowseButton = new ButtonComp(null, new FontIcon("mdi2f-folder-open-outline"), () -> { - BrowserChooserComp.openSingleFile(() -> fileSystem.getValue(), fileStore -> { - if (fileStore == null) { - filePath.setValue(null); - fileSystem.setValue(null); - } else { - filePath.setValue(fileStore.getPath()); - fileSystem.setValue(fileStore.getFileSystem()); - } - }); - }) + BrowserChooserComp.openSingleFile(() -> fileSystem.getValue(), fileStore -> { + if (fileStore == null) { + filePath.setValue(null); + fileSystem.setValue(null); + } else { + filePath.setValue(fileStore.getPath()); + fileSystem.setValue(fileStore.getFileSystem()); + } + }, false); + }) .styleClass(Styles.CENTER_PILL) .grow(false, true); @@ -129,6 +130,6 @@ public class ContextualFileReferenceChoiceComp extends SimpleComp { }); }); - return layout.createRegion(); + return new SimpleCompStructure<>(layout.createStructure().get()); } } diff --git a/app/src/main/java/io/xpipe/app/fxcomps/impl/StringSourceComp.java b/app/src/main/java/io/xpipe/app/fxcomps/impl/StringSourceComp.java index 302610210..5bff3c19b 100644 --- a/app/src/main/java/io/xpipe/app/fxcomps/impl/StringSourceComp.java +++ b/app/src/main/java/io/xpipe/app/fxcomps/impl/StringSourceComp.java @@ -5,36 +5,52 @@ import io.xpipe.app.storage.DataStoreEntryRef; import io.xpipe.app.util.StringSource; import io.xpipe.core.store.ShellStore; import javafx.beans.property.Property; +import javafx.beans.property.SimpleBooleanProperty; import javafx.beans.property.SimpleObjectProperty; import javafx.beans.value.ObservableValue; -import javafx.scene.control.Tab; -import javafx.scene.control.TabPane; +import javafx.scene.layout.AnchorPane; import javafx.scene.layout.Region; +import javafx.scene.layout.StackPane; public class StringSourceComp extends SimpleComp { - private final Property> fileSystem; + private final Property> fileSystem; private final Property stringSource; public StringSourceComp(ObservableValue> fileSystem, Property stringSource) { this.stringSource = stringSource; this.fileSystem = new SimpleObjectProperty<>(); fileSystem.subscribe(val -> { - this.fileSystem.setValue(val); + this.fileSystem.setValue(val.get().ref()); }); } @Override protected Region createSimple() { - var tab = new TabPane(); - var inPlace = new SimpleObjectProperty<>(stringSource.getValue() instanceof StringSource.InPlace i ? i.get() : null); - var stringField = new TextAreaComp(inPlace); - tab.getTabs().add(new Tab()); - var fs = stringSource.getValue() instanceof StringSource.File f ? f.getFile() : null; - var file = new SimpleObjectProperty<>(stringSource.getValue() instanceof StringSource.File f ? f.getFile() : null); - // new ContextualFileReferenceChoiceComp(fileSystem, file); - return null; + var file = new SimpleObjectProperty<>(stringSource.getValue() instanceof StringSource.File f ? f.getFile().serialize() : null); + var showText = new SimpleBooleanProperty(inPlace.get() != null); + + var stringField = new TextAreaComp(inPlace); + stringField.hide(showText.not()); + var fileComp = new ContextualFileReferenceChoiceComp(fileSystem, file); + fileComp.hide(showText); + + var tr = stringField.createRegion(); + var button = new IconButtonComp("mdi2c-checkbox-marked-outline", () -> { + showText.set(!showText.getValue()); + }).createRegion(); + AnchorPane.setBottomAnchor(button, 10.0); + AnchorPane.setRightAnchor(button, 10.0); + var anchorPane = new AnchorPane(tr, button); + AnchorPane.setBottomAnchor(tr, 0.0); + AnchorPane.setTopAnchor(tr, 0.0); + AnchorPane.setLeftAnchor(tr, 0.0); + AnchorPane.setRightAnchor(tr, 0.0); + + var fr = fileComp.createRegion(); + + return new StackPane(tr, fr); } } diff --git a/app/src/main/java/io/xpipe/app/storage/DataStoreEntry.java b/app/src/main/java/io/xpipe/app/storage/DataStoreEntry.java index e709f08d6..eb32ae21a 100644 --- a/app/src/main/java/io/xpipe/app/storage/DataStoreEntry.java +++ b/app/src/main/java/io/xpipe/app/storage/DataStoreEntry.java @@ -111,7 +111,7 @@ public class DataStoreEntry extends StorageElement { this.categoryUuid = categoryUuid; this.store = store; this.storeNode = null; - this.validity = Validity.COMPLETE; + this.validity = Validity.INCOMPLETE; this.configuration = Configuration.defaultConfiguration(); this.expanded = false; this.color = null; diff --git a/lang/app/strings/translations_en.properties b/lang/app/strings/translations_en.properties index 29f75f8e5..6cd74f31f 100644 --- a/lang/app/strings/translations_en.properties +++ b/lang/app/strings/translations_en.properties @@ -426,7 +426,7 @@ predefined=Predefined default=Default goodMorning=Good morning goodAfternoon=Good afternoon -goodNight=Good night +goodEvening=Good evening addVisual=Visual ... ssh=SSH sshConfiguration=SSH Configuration diff --git a/lang/proc/texts/sshOptions_de.md b/lang/proc/texts/sshOptions_de.md index 03d534714..86b98ac1b 100644 --- a/lang/proc/texts/sshOptions_de.md +++ b/lang/proc/texts/sshOptions_de.md @@ -12,7 +12,7 @@ Die genaue Anzahl der unterstützten Optionen hängt ausschließlich von deinem Der Inhalt hier entspricht einem Host-Abschnitt in einer SSH-Konfigurationsdatei. Beachte, dass du den `Host`-Eintrag nicht explizit definieren musst, denn das wird automatisch erledigt. -Wenn du mehr als einen Host-Abschnitt definieren willst, z. B. bei abhängigen Verbindungen wie einem Proxy-Jump-Host, der von einem anderen Config-Host abhängt, solltest du stattdessen eine richtige SSH-Konfigurationsdatei verwenden, da hier nur genau eine Host-Definition unterstützt wird. +Wenn du mehr als einen Host-Abschnitt definieren willst, z. B. bei abhängigen Verbindungen wie einem Proxy-Jump-Host, der von einem anderen Config-Host abhängt, kannst du auch mehrere Host-Einträge definieren. Es wird dann der erste Host als Verbindung genutzt. Du musst keine Formatierung mit Leerzeichen oder Einrückung vornehmen, das ist für die Funktion nicht erforderlich. diff --git a/lang/proc/texts/sshOptions_en.md b/lang/proc/texts/sshOptions_en.md index 4724ab223..5a66dd8c9 100644 --- a/lang/proc/texts/sshOptions_en.md +++ b/lang/proc/texts/sshOptions_en.md @@ -12,7 +12,7 @@ The exact amount of supported options purely depends on your installed SSH clien The content here is equivalent to one host section in an SSH config file. Note that you don't have to explicitly define the `Host` entry, as that will be done automatically. -If you intend to define more than one host section, e.g. with dependent connections such as a proxy jump host that depends on another config host, you should use a proper SSH config file instead as only exactly one host definition is supported here. +If you intend to define more than one host section, e.g. with dependent connections such as a proxy jump host that depends on another config host, you can define multiple host entries in here as well. XPipe will then launch the first host entry. You don't have to perform any formatting with whitespace or indentation, this is not needed for it to function.