mirror of
https://github.com/xpipe-io/xpipe.git
synced 2024-10-01 09:40:35 +13:00
Improve automatic scan dialog
This commit is contained in:
parent
63269bbbfb
commit
ce6a56d234
8 changed files with 108 additions and 26 deletions
|
@ -0,0 +1,38 @@
|
|||
package io.xpipe.app.comp.storage.store;
|
||||
|
||||
import atlantafx.base.theme.Styles;
|
||||
import io.xpipe.app.comp.base.ButtonComp;
|
||||
import io.xpipe.app.core.AppFont;
|
||||
import io.xpipe.app.core.AppI18n;
|
||||
import io.xpipe.app.fxcomps.SimpleComp;
|
||||
import io.xpipe.app.fxcomps.impl.FancyTooltipAugment;
|
||||
import io.xpipe.app.fxcomps.impl.VerticalComp;
|
||||
import io.xpipe.app.util.ScanAlert;
|
||||
import javafx.scene.input.KeyCode;
|
||||
import javafx.scene.input.KeyCodeCombination;
|
||||
import javafx.scene.input.KeyCombination;
|
||||
import javafx.scene.layout.Region;
|
||||
import org.kordamp.ikonli.javafx.FontIcon;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class StoreScanBarComp extends SimpleComp {
|
||||
|
||||
@Override
|
||||
protected Region createSimple() {
|
||||
var newTunnelStore = new ButtonComp(AppI18n.observable("addAutomatically"), new FontIcon("mdi2e-eye-plus-outline"), () -> {
|
||||
ScanAlert.showAsync(null);
|
||||
})
|
||||
.styleClass(Styles.FLAT)
|
||||
.shortcut(new KeyCodeCombination(KeyCode.A, KeyCombination.SHORTCUT_DOWN))
|
||||
.apply(new FancyTooltipAugment<>("addAutomatically"));
|
||||
|
||||
var box = new VerticalComp(List.of(newTunnelStore))
|
||||
.apply(struc -> struc.get().setFillWidth(true));
|
||||
box.apply(s -> AppFont.medium(s.get()));
|
||||
var bar = box.createRegion();
|
||||
bar.getStyleClass().add("bar");
|
||||
bar.getStyleClass().add("store-creation-bar");
|
||||
return bar;
|
||||
}
|
||||
}
|
|
@ -15,10 +15,11 @@ public class StoreSidebarComp extends SimpleComp {
|
|||
protected Region createSimple() {
|
||||
var sideBar = new VerticalComp(List.of(
|
||||
new StoreEntryListHeaderComp(),
|
||||
new StoreScanBarComp(),
|
||||
new StoreCreationBarComp(),
|
||||
new StoreOrganizationComp(),
|
||||
Comp.of(() -> new Region()).styleClass("bar").styleClass("filler-bar")));
|
||||
sideBar.apply(s -> VBox.setVgrow(s.get().getChildren().get(3), Priority.ALWAYS));
|
||||
sideBar.apply(s -> VBox.setVgrow(s.get().getChildren().get(4), Priority.ALWAYS));
|
||||
sideBar.styleClass("sidebar");
|
||||
return sideBar.createRegion();
|
||||
}
|
||||
|
|
|
@ -16,6 +16,7 @@ import javafx.scene.control.Label;
|
|||
import javafx.scene.layout.Region;
|
||||
import lombok.AllArgsConstructor;
|
||||
|
||||
import java.util.Locale;
|
||||
import java.util.Optional;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
|
@ -91,7 +92,7 @@ public class DataStoreChoiceComp<T extends DataStore> extends SimpleComp {
|
|||
@SuppressWarnings("unchecked")
|
||||
protected Region createSimple() {
|
||||
var list = StoreEntryFlatMiniSectionComp.ALL;
|
||||
var comboBox = new CustomComboBoxBuilder<>(
|
||||
var comboBox = new CustomComboBoxBuilder<T>(
|
||||
selected,
|
||||
t -> list.stream()
|
||||
.filter(e -> t.equals(e.getEntry().getStore()))
|
||||
|
@ -100,6 +101,14 @@ public class DataStoreChoiceComp<T extends DataStore> extends SimpleComp {
|
|||
.createRegion(),
|
||||
new Label(AppI18n.get("none")),
|
||||
n -> true);
|
||||
|
||||
if (list.size() > 5) {
|
||||
comboBox.addFilter((t, s) -> {
|
||||
var entry = DataStorage.get().getStoreDisplayName(t).orElse("?");
|
||||
return entry.toLowerCase(Locale.ROOT).contains(s.toLowerCase(Locale.ROOT));
|
||||
});
|
||||
}
|
||||
|
||||
comboBox.setAccessibleNames(t -> toName(t));
|
||||
comboBox.setSelectedDisplay(t -> createGraphic(t));
|
||||
comboBox.setUnknownNode(t -> createGraphic(t));
|
||||
|
|
|
@ -15,6 +15,7 @@ import javafx.scene.control.ComboBox;
|
|||
import javafx.scene.control.Label;
|
||||
import javafx.scene.control.ListCell;
|
||||
import javafx.scene.control.Separator;
|
||||
import javafx.scene.input.MouseEvent;
|
||||
import javafx.scene.layout.Region;
|
||||
import javafx.scene.layout.VBox;
|
||||
|
||||
|
@ -223,6 +224,14 @@ public class CustomComboBoxBuilder<T> {
|
|||
|
||||
private class Cell extends ListCell<Node> {
|
||||
|
||||
public Cell() {
|
||||
addEventFilter(MouseEvent.MOUSE_PRESSED, event -> {
|
||||
if (!nodeMap.containsKey(getItem())) {
|
||||
event.consume();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void updateItem(Node item, boolean empty) {
|
||||
setGraphic(item);
|
||||
|
|
|
@ -6,16 +6,20 @@ import io.xpipe.app.core.AppI18n;
|
|||
import io.xpipe.app.core.AppWindowHelper;
|
||||
import io.xpipe.app.ext.ScanProvider;
|
||||
import io.xpipe.app.fxcomps.Comp;
|
||||
import io.xpipe.app.fxcomps.impl.DataStoreChoiceComp;
|
||||
import io.xpipe.app.fxcomps.impl.LabelComp;
|
||||
import io.xpipe.app.fxcomps.impl.VerticalComp;
|
||||
import io.xpipe.app.issue.ErrorEvent;
|
||||
import io.xpipe.app.storage.DataStorage;
|
||||
import io.xpipe.app.storage.DataStoreEntry;
|
||||
import io.xpipe.core.store.ShellStore;
|
||||
import javafx.application.Platform;
|
||||
import javafx.beans.property.SimpleBooleanProperty;
|
||||
import javafx.beans.property.SimpleListProperty;
|
||||
import javafx.beans.property.SimpleObjectProperty;
|
||||
import javafx.collections.FXCollections;
|
||||
import javafx.event.ActionEvent;
|
||||
import javafx.geometry.Insets;
|
||||
import javafx.scene.control.Alert;
|
||||
import javafx.scene.control.Button;
|
||||
import javafx.scene.control.ButtonType;
|
||||
|
@ -25,32 +29,20 @@ import javafx.scene.layout.VBox;
|
|||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.function.Supplier;
|
||||
import java.util.function.Function;
|
||||
|
||||
public class ScanAlert {
|
||||
|
||||
public static void showAsync(DataStoreEntry entry) {
|
||||
ThreadHelper.runAsync(() -> {
|
||||
if (entry.getStore() instanceof ShellStore) {
|
||||
if (entry == null || entry.getStore() instanceof ShellStore) {
|
||||
showForShellStore(entry);
|
||||
} else {
|
||||
showForOtherStore(entry);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private static void showForOtherStore(DataStoreEntry entry) {
|
||||
show(entry, () -> {
|
||||
var providers = ScanProvider.getAll();
|
||||
return providers.stream()
|
||||
.map(scanProvider -> scanProvider.create(entry.getStore()))
|
||||
.filter(scanOperation -> scanOperation != null)
|
||||
.toList();
|
||||
});
|
||||
}
|
||||
|
||||
private static void showForShellStore(DataStoreEntry entry) {
|
||||
show(entry, () -> {
|
||||
private static void showForShellStore(DataStoreEntry initial) {
|
||||
show(initial != null ? initial.getStore().asNeeded() : null, (DataStoreEntry entry) -> {
|
||||
try (var sc = ((ShellStore) entry.getStore()).control().start()) {
|
||||
var providers = ScanProvider.getAll();
|
||||
var applicable = new ArrayList<ScanProvider.ScanOperation>();
|
||||
|
@ -68,8 +60,10 @@ public class ScanAlert {
|
|||
});
|
||||
}
|
||||
|
||||
private static void show(DataStoreEntry entry, Supplier<List<ScanProvider.ScanOperation>> applicable) {
|
||||
private static void show(
|
||||
ShellStore initialStore, Function<DataStoreEntry, List<ScanProvider.ScanOperation>> applicable) {
|
||||
var busy = new SimpleBooleanProperty();
|
||||
var store = new SimpleObjectProperty<ShellStore>();
|
||||
var selected = new SimpleListProperty<ScanProvider.ScanOperation>(FXCollections.observableArrayList());
|
||||
AppWindowHelper.showAlert(
|
||||
alert -> {
|
||||
|
@ -78,23 +72,40 @@ public class ScanAlert {
|
|||
alert.getButtonTypes().add(ButtonType.OK);
|
||||
var content = new LoadingOverlayComp(
|
||||
new VerticalComp(List.<Comp<?>>of(
|
||||
new LabelComp(AppI18n.get("scanAlertHeader"))
|
||||
new LabelComp(AppI18n.get("scanAlertChoiceHeader"))
|
||||
.apply(struc ->
|
||||
struc.get().setWrapText(true)),
|
||||
new DataStoreChoiceComp<>(
|
||||
DataStoreChoiceComp.Mode.OTHER,
|
||||
null,
|
||||
store,
|
||||
ShellStore.class,
|
||||
store1 -> true)
|
||||
.disable(new SimpleBooleanProperty(initialStore != null)),
|
||||
new LabelComp(AppI18n.get("scanAlertHeader"))
|
||||
.apply(struc ->
|
||||
struc.get().setWrapText(true))
|
||||
.padding(new Insets(20, 0, 0, 0)),
|
||||
Comp.of(() -> new Region())))
|
||||
.apply(struc -> struc.get().setSpacing(15))
|
||||
.styleClass("window-content"),
|
||||
busy)
|
||||
.createRegion();
|
||||
content.setPrefWidth(500);
|
||||
content.setPrefHeight(450);
|
||||
content.setPrefHeight(550);
|
||||
alert.getDialogPane().setContent(content);
|
||||
|
||||
// Custom behavior for ok button
|
||||
var btOk = (Button) alert.getDialogPane().lookupButton(ButtonType.OK);
|
||||
btOk.addEventFilter(ActionEvent.ACTION, event -> {
|
||||
if (store.get() == null) {
|
||||
event.consume();
|
||||
return;
|
||||
}
|
||||
|
||||
ThreadHelper.runAsync(() -> {
|
||||
BusyProperty.execute(busy, () -> {
|
||||
var entry = DataStorage.get().getStoreEntry(store.get());
|
||||
entry.setExpanded(true);
|
||||
|
||||
for (var a : selected) {
|
||||
|
@ -113,11 +124,21 @@ public class ScanAlert {
|
|||
});
|
||||
});
|
||||
|
||||
// Asynchronous loading of content
|
||||
alert.setOnShown(event -> {
|
||||
store.addListener((observable, oldValue, newValue) -> {
|
||||
if (newValue == null) {
|
||||
selected.clear();
|
||||
((VBox) ((StackPane) alert.getDialogPane().getContent())
|
||||
.getChildren()
|
||||
.get(0))
|
||||
.getChildren()
|
||||
.set(3, new Region());
|
||||
return;
|
||||
}
|
||||
|
||||
ThreadHelper.runAsync(() -> {
|
||||
BusyProperty.execute(busy, () -> {
|
||||
var a = applicable.get();
|
||||
var entry = DataStorage.get().getStoreEntry(newValue);
|
||||
var a = applicable.apply(entry);
|
||||
|
||||
Platform.runLater(() -> {
|
||||
if (a == null) {
|
||||
|
@ -139,11 +160,13 @@ public class ScanAlert {
|
|||
.getChildren()
|
||||
.get(0))
|
||||
.getChildren()
|
||||
.set(1, r);
|
||||
.set(3, r);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
store.set(initialStore);
|
||||
},
|
||||
busy,
|
||||
null);
|
||||
|
|
|
@ -46,6 +46,7 @@ addTunnel=Add Tunnel ...
|
|||
addHost=Add Remote Host ...
|
||||
addShell=Add Environment ...
|
||||
addCommand=Add Command ...
|
||||
addAutomatically=Add Automatically ...
|
||||
addOther=Add Other ...
|
||||
addStreamTitle=Add Stream Store
|
||||
addConnection=Add Connection
|
||||
|
|
|
@ -64,7 +64,7 @@ logLevel=Log level
|
|||
appBehaviour=Application behaviour
|
||||
logLevelDescription=The log level that should be used when writing log files.
|
||||
developerMode=Developer mode
|
||||
developerModeDescription=When enabled, you will have access to a variety of additional options that are useful for development.
|
||||
developerModeDescription=When enabled, you will have access to a variety of additional options that are useful for development. Only active after a restart.
|
||||
editor=Editor
|
||||
custom=Custom
|
||||
passwordManagerCommand=Password manager command
|
||||
|
|
|
@ -55,6 +55,7 @@ connectionNameDescription=Give this connection a custom name
|
|||
openFileTitle=Open file
|
||||
unknown=Unknown
|
||||
scanAlertTitle=Add connections
|
||||
scanAlertChoiceHeader=Choose from where to add connections:
|
||||
scanAlertHeader=Select types of connections you want to automatically add for the host system:
|
||||
namedHostFeatureUnsupported=$HOST$ does not support this feature
|
||||
namedHostNotActive=$HOST$ is not active
|
||||
|
|
Loading…
Reference in a new issue