mirror of
https://github.com/xpipe-io/xpipe.git
synced 2024-11-22 07:30:24 +00:00
Rework
This commit is contained in:
parent
7263214894
commit
dfcb90bd16
11 changed files with 80 additions and 62 deletions
|
@ -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<FileSystemStore> {
|
||||
|
||||
private final Property<String> filter = new SimpleStringProperty();
|
||||
private final BrowserFileListModel fileList;
|
||||
|
|
|
@ -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<T extends BrowserSessionEntry> {
|
||||
public class BrowserAbstractSessionModel<T extends BrowserSessionEntry<?>> {
|
||||
|
||||
protected final ObservableList<T> sessionEntries = FXCollections.observableArrayList();
|
||||
protected final Property<T> 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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<DataStoreEntryRef<? extends FileSystemStore>> store, Consumer<FileReference> file) {
|
||||
Supplier<DataStoreEntryRef<? extends FileSystemStore>> store, Consumer<FileReference> 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<FileReference> 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();
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -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<T extends DataStore> {
|
||||
|
||||
protected final DataStoreEntryRef<? extends FileSystemStore> entry;
|
||||
protected final DataStoreEntryRef<? extends T> entry;
|
||||
protected final BooleanProperty busy = new SimpleBooleanProperty();
|
||||
protected final BrowserAbstractSessionModel<?> browserModel;
|
||||
protected final String name;
|
||||
protected final String tooltip;
|
||||
|
||||
public BrowserSessionEntry(BrowserAbstractSessionModel<?> browserModel, DataStoreEntryRef<? extends FileSystemStore> entry) {
|
||||
public BrowserSessionEntry(BrowserAbstractSessionModel<?> browserModel, DataStoreEntryRef<? extends T> entry) {
|
||||
this.browserModel = browserModel;
|
||||
this.entry = entry;
|
||||
this.name = DataStorage.get().getStoreDisplayName(entry.get());
|
||||
|
|
|
@ -21,7 +21,7 @@ import lombok.Getter;
|
|||
import java.util.ArrayList;
|
||||
|
||||
@Getter
|
||||
public class BrowserSessionModel extends BrowserAbstractSessionModel<BrowserSessionEntry> {
|
||||
public class BrowserSessionModel extends BrowserAbstractSessionModel<BrowserSessionEntry<?>> {
|
||||
|
||||
public static final BrowserSessionModel DEFAULT = new BrowserSessionModel(BrowserSavedStateImpl.load());
|
||||
|
||||
|
|
|
@ -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<CompStructure<HBox>> {
|
||||
|
||||
private final Property<DataStoreEntryRef<? extends FileSystemStore>> fileSystem;
|
||||
private final Property<String> filePath;
|
||||
|
@ -45,23 +46,23 @@ public class ContextualFileReferenceChoiceComp extends SimpleComp {
|
|||
}
|
||||
|
||||
@Override
|
||||
protected Region createSimple() {
|
||||
public CompStructure<HBox> 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());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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<DataStoreEntryRef<? extends ShellStore>> fileSystem;
|
||||
private final Property<DataStoreEntryRef<ShellStore>> fileSystem;
|
||||
private final Property<StringSource> stringSource;
|
||||
|
||||
public <T extends ShellStore> StringSourceComp(ObservableValue<DataStoreEntryRef<T>> fileSystem, Property<StringSource> 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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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.
|
||||
|
||||
|
|
|
@ -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.
|
||||
|
||||
|
|
Loading…
Reference in a new issue