mirror of
https://github.com/xpipe-io/xpipe.git
synced 2024-11-25 00:50:31 +00:00
Rework dialogs
This commit is contained in:
parent
ba9918e166
commit
5b25f34988
8 changed files with 269 additions and 268 deletions
|
@ -9,11 +9,8 @@ import io.xpipe.app.comp.base.DialogComp;
|
|||
import io.xpipe.app.comp.base.SideSplitPaneComp;
|
||||
import io.xpipe.app.comp.store.StoreEntryWrapper;
|
||||
import io.xpipe.app.core.AppFont;
|
||||
import io.xpipe.app.core.AppI18n;
|
||||
import io.xpipe.app.core.AppLayoutModel;
|
||||
import io.xpipe.app.core.window.AppWindowHelper;
|
||||
import io.xpipe.app.fxcomps.Comp;
|
||||
import io.xpipe.app.fxcomps.SimpleComp;
|
||||
import io.xpipe.app.fxcomps.impl.StackComp;
|
||||
import io.xpipe.app.fxcomps.impl.VerticalComp;
|
||||
import io.xpipe.app.fxcomps.util.BindingsHelper;
|
||||
|
@ -23,14 +20,12 @@ import io.xpipe.app.util.FileReference;
|
|||
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.collections.ListChangeListener;
|
||||
import javafx.geometry.Pos;
|
||||
import javafx.scene.control.TextField;
|
||||
import javafx.scene.layout.HBox;
|
||||
import javafx.scene.layout.Priority;
|
||||
import javafx.scene.layout.Region;
|
||||
import javafx.scene.layout.StackPane;
|
||||
import javafx.scene.shape.Rectangle;
|
||||
|
||||
|
@ -40,7 +35,7 @@ import java.util.function.Consumer;
|
|||
import java.util.function.Predicate;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
public class BrowserChooserComp extends SimpleComp {
|
||||
public class BrowserChooserComp extends DialogComp {
|
||||
|
||||
private final BrowserFileChooserModel model;
|
||||
|
||||
|
@ -52,24 +47,16 @@ public class BrowserChooserComp extends SimpleComp {
|
|||
Supplier<DataStoreEntryRef<? extends FileSystemStore>> store, Consumer<FileReference> file, boolean save) {
|
||||
PlatformThread.runLaterIfNeeded(() -> {
|
||||
var model = new BrowserFileChooserModel(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(save ? "saveFileTitle" : "openFileTitle"),
|
||||
stage -> {
|
||||
return comp;
|
||||
},
|
||||
false,
|
||||
null);
|
||||
DialogComp.showWindow(save ? "saveFileTitle" : "openFileTitle", stage -> {
|
||||
var comp = new BrowserChooserComp(model);
|
||||
comp.apply(struc -> struc.get().setPrefSize(1200, 700))
|
||||
.apply(struc -> AppFont.normal(struc.get()))
|
||||
.styleClass("browser")
|
||||
.styleClass("chooser");
|
||||
return comp;
|
||||
});
|
||||
model.setOnFinish(fileStores -> {
|
||||
file.accept(fileStores.size() > 0 ? fileStores.getFirst() : null);
|
||||
window.close();
|
||||
});
|
||||
window.show();
|
||||
window.setOnHidden(event -> {
|
||||
model.finishWithoutChoice();
|
||||
event.consume();
|
||||
});
|
||||
ThreadHelper.runAsync(() -> {
|
||||
model.openFileSystemAsync(store.get(), null, null);
|
||||
|
@ -77,8 +64,32 @@ public class BrowserChooserComp extends SimpleComp {
|
|||
});
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
protected Region createSimple() {
|
||||
protected String finishKey() {
|
||||
return "select";
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Comp<?> pane(Comp<?> content) {
|
||||
return content;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void finish() {
|
||||
model.finishChooser();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void discard() {
|
||||
model.finishWithoutChoice();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Comp<?> content() {
|
||||
Predicate<StoreEntryWrapper> applicable = storeEntryWrapper -> {
|
||||
return (storeEntryWrapper.getEntry().getStore() instanceof ShellStore)
|
||||
&& storeEntryWrapper.getEntry().getValidity().isUsable();
|
||||
|
@ -144,60 +155,33 @@ public class BrowserChooserComp extends SimpleComp {
|
|||
struc.getLeft().setMinWidth(200);
|
||||
struc.getLeft().setMaxWidth(500);
|
||||
});
|
||||
return splitPane;
|
||||
}
|
||||
|
||||
var dialogPane = new DialogComp() {
|
||||
|
||||
@Override
|
||||
protected String finishKey() {
|
||||
return "select";
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Comp<?> pane(Comp<?> content) {
|
||||
return content;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void finish() {
|
||||
model.finishChooser();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Comp<?> content() {
|
||||
return splitPane;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Comp<?> bottom() {
|
||||
return Comp.of(() -> {
|
||||
var selected = new HBox();
|
||||
selected.setAlignment(Pos.CENTER_LEFT);
|
||||
model.getFileSelection().addListener((ListChangeListener<? super BrowserEntry>) c -> {
|
||||
PlatformThread.runLaterIfNeeded(() -> {
|
||||
selected.getChildren()
|
||||
.setAll(c.getList().stream()
|
||||
.map(s -> {
|
||||
var field = new TextField(
|
||||
s.getRawFileEntry().getPath());
|
||||
field.setEditable(false);
|
||||
field.getStyleClass().add("chooser-selection");
|
||||
HBox.setHgrow(field, Priority.ALWAYS);
|
||||
return field;
|
||||
})
|
||||
.toList());
|
||||
});
|
||||
});
|
||||
var bottomBar = new HBox(selected);
|
||||
HBox.setHgrow(selected, Priority.ALWAYS);
|
||||
bottomBar.setAlignment(Pos.CENTER);
|
||||
return bottomBar;
|
||||
@Override
|
||||
public Comp<?> bottom() {
|
||||
return Comp.of(() -> {
|
||||
var selected = new HBox();
|
||||
selected.setAlignment(Pos.CENTER_LEFT);
|
||||
model.getFileSelection().addListener((ListChangeListener<? super BrowserEntry>) c -> {
|
||||
PlatformThread.runLaterIfNeeded(() -> {
|
||||
selected.getChildren()
|
||||
.setAll(c.getList().stream()
|
||||
.map(s -> {
|
||||
var field = new TextField(
|
||||
s.getRawFileEntry().getPath());
|
||||
field.setEditable(false);
|
||||
field.getStyleClass().add("chooser-selection");
|
||||
HBox.setHgrow(field, Priority.ALWAYS);
|
||||
return field;
|
||||
})
|
||||
.toList());
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
var r = dialogPane.createRegion();
|
||||
r.getStyleClass().add("browser");
|
||||
r.getStyleClass().add("chooser");
|
||||
return r;
|
||||
});
|
||||
var bottomBar = new HBox(selected);
|
||||
HBox.setHgrow(selected, Priority.ALWAYS);
|
||||
bottomBar.setAlignment(Pos.CENTER);
|
||||
return bottomBar;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -20,22 +20,30 @@ import javafx.stage.Stage;
|
|||
import atlantafx.base.theme.Styles;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
import java.util.function.Function;
|
||||
|
||||
public abstract class DialogComp extends Comp<CompStructure<Region>> {
|
||||
|
||||
public static void showWindow(String titleKey, Function<Stage, DialogComp> f) {
|
||||
var loading = new SimpleBooleanProperty();
|
||||
var dialog = new AtomicReference<DialogComp>();
|
||||
Platform.runLater(() -> {
|
||||
var stage = AppWindowHelper.sideWindow(
|
||||
AppI18n.get(titleKey),
|
||||
window -> {
|
||||
var c = f.apply(window);
|
||||
dialog.set(c);
|
||||
loading.bind(c.busy());
|
||||
return c;
|
||||
},
|
||||
false,
|
||||
loading);
|
||||
stage.setOnCloseRequest(event -> {
|
||||
if (dialog.get() != null) {
|
||||
dialog.get().discard();
|
||||
}
|
||||
});
|
||||
stage.show();
|
||||
});
|
||||
}
|
||||
|
@ -97,6 +105,8 @@ public abstract class DialogComp extends Comp<CompStructure<Region>> {
|
|||
|
||||
protected abstract void finish();
|
||||
|
||||
protected abstract void discard();
|
||||
|
||||
public abstract Comp<?> content();
|
||||
|
||||
protected Comp<?> pane(Comp<?> content) {
|
||||
|
|
|
@ -323,9 +323,6 @@ public class StoreCreationComp extends DialogComp {
|
|||
try (var ignored = new BooleanScope(busy).start()) {
|
||||
DataStorage.get().addStoreEntryInProgress(entry.getValue());
|
||||
var context = entry.getValue().validateAndKeepOpenOrThrowAndClose(null);
|
||||
if (context == null) {
|
||||
entry.getValue().validateRefreshChildrenOrThrow();
|
||||
}
|
||||
commit(context, true);
|
||||
} catch (Throwable ex) {
|
||||
if (ex instanceof ValidationException) {
|
||||
|
@ -354,6 +351,9 @@ public class StoreCreationComp extends DialogComp {
|
|||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void discard() {}
|
||||
|
||||
@Override
|
||||
public Comp<?> content() {
|
||||
return Comp.of(this::createLayout);
|
||||
|
|
|
@ -63,6 +63,9 @@ public class StoreIconChoiceDialogComp extends SimpleComp {
|
|||
dialogStage.close();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void discard() {}
|
||||
|
||||
@Override
|
||||
public Comp<?> content() {
|
||||
return new StoreIconChoiceComp(selected, SystemIcons.getSystemIcons(), 5, filterText, () -> {
|
||||
|
|
|
@ -96,6 +96,9 @@ public class StoreNotesComp extends Comp<StoreNotesComp.Structure> {
|
|||
ref.get().hide();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void discard() {}
|
||||
|
||||
@Override
|
||||
protected String finishKey() {
|
||||
return "apply";
|
||||
|
@ -130,8 +133,7 @@ public class StoreNotesComp extends Comp<StoreNotesComp.Structure> {
|
|||
popover.setTitle(wrapper.getName().getValue());
|
||||
popover.showingProperty().addListener((observable, oldValue, newValue) -> {
|
||||
if (!newValue) {
|
||||
n.setValue(
|
||||
new StoreNotes(n.getValue().getCommited(), n.getValue().getCommited()));
|
||||
n.setValue(new StoreNotes(n.getValue().getCommited(), n.getValue().getCommited()));
|
||||
DataStorage.get().saveAsync();
|
||||
ref.set(null);
|
||||
}
|
||||
|
|
|
@ -115,13 +115,14 @@ public class AppLayoutModel {
|
|||
null,
|
||||
() -> Hyperlinks.open(
|
||||
"http://localhost:" + AppBeaconServer.get().getPort()),
|
||||
null),
|
||||
new Entry(
|
||||
AppI18n.observable("webtop"),
|
||||
"mdi2d-desktop-mac",
|
||||
null,
|
||||
() -> Hyperlinks.open(Hyperlinks.GITHUB_WEBTOP),
|
||||
null)));
|
||||
null)
|
||||
// new Entry(
|
||||
// AppI18n.observable("webtop"),
|
||||
// "mdi2d-desktop-mac",
|
||||
// null,
|
||||
// () -> Hyperlinks.open(Hyperlinks.GITHUB_WEBTOP),
|
||||
// null)
|
||||
));
|
||||
return l;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,16 +1,9 @@
|
|||
package io.xpipe.app.util;
|
||||
|
||||
import io.xpipe.app.comp.base.DialogComp;
|
||||
import io.xpipe.app.comp.base.ListSelectorComp;
|
||||
import io.xpipe.app.comp.store.StoreViewState;
|
||||
import io.xpipe.app.core.AppI18n;
|
||||
import io.xpipe.app.ext.ScanProvider;
|
||||
import io.xpipe.app.fxcomps.Comp;
|
||||
import io.xpipe.app.fxcomps.impl.DataStoreChoiceComp;
|
||||
import io.xpipe.app.issue.ErrorEvent;
|
||||
import io.xpipe.app.storage.DataStorage;
|
||||
import io.xpipe.app.storage.DataStoreEntry;
|
||||
import io.xpipe.app.storage.DataStoreEntryRef;
|
||||
import io.xpipe.core.process.ShellControl;
|
||||
import io.xpipe.core.process.ShellStoreState;
|
||||
import io.xpipe.core.process.ShellTtyState;
|
||||
|
@ -18,21 +11,9 @@ import io.xpipe.core.store.ShellStore;
|
|||
import io.xpipe.core.store.ShellValidationContext;
|
||||
import io.xpipe.core.store.ValidationContext;
|
||||
|
||||
import javafx.application.Platform;
|
||||
import javafx.beans.property.*;
|
||||
import javafx.beans.value.ObservableValue;
|
||||
import javafx.collections.FXCollections;
|
||||
import javafx.geometry.Insets;
|
||||
import javafx.scene.layout.StackPane;
|
||||
import javafx.scene.layout.VBox;
|
||||
import javafx.stage.Stage;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.function.BiFunction;
|
||||
import java.util.function.Function;
|
||||
|
||||
import static javafx.scene.layout.Priority.ALWAYS;
|
||||
|
||||
public class ScanAlert {
|
||||
|
||||
|
@ -90,168 +71,8 @@ public class ScanAlert {
|
|||
ShellValidationContext shellValidationContext) {
|
||||
DialogComp.showWindow(
|
||||
"scanAlertTitle",
|
||||
stage -> new Dialog(
|
||||
stage -> new ScanDialog(
|
||||
stage, initialStore != null ? initialStore.ref() : null, applicable, shellValidationContext));
|
||||
}
|
||||
|
||||
private static class Dialog extends DialogComp {
|
||||
|
||||
private final DataStoreEntryRef<ShellStore> initialStore;
|
||||
private final BiFunction<DataStoreEntry, ShellControl, List<ScanProvider.ScanOperation>> applicable;
|
||||
private final Stage window;
|
||||
private final ObjectProperty<DataStoreEntryRef<ShellStore>> entry;
|
||||
private final ListProperty<ScanProvider.ScanOperation> selected =
|
||||
new SimpleListProperty<>(FXCollections.observableArrayList());
|
||||
private final BooleanProperty busy = new SimpleBooleanProperty();
|
||||
private ShellValidationContext shellValidationContext;
|
||||
|
||||
private Dialog(
|
||||
Stage window,
|
||||
DataStoreEntryRef<ShellStore> entry,
|
||||
BiFunction<DataStoreEntry, ShellControl, List<ScanProvider.ScanOperation>> applicable,
|
||||
ShellValidationContext shellValidationContext) {
|
||||
this.window = window;
|
||||
this.initialStore = entry;
|
||||
this.entry = new SimpleObjectProperty<>(entry);
|
||||
this.applicable = applicable;
|
||||
this.shellValidationContext = shellValidationContext;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ObservableValue<Boolean> busy() {
|
||||
return busy;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void finish() {
|
||||
ThreadHelper.runFailableAsync(() -> {
|
||||
try {
|
||||
if (entry.get() == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
Platform.runLater(() -> {
|
||||
window.close();
|
||||
});
|
||||
|
||||
BooleanScope.executeExclusive(busy, () -> {
|
||||
entry.get().get().setExpanded(true);
|
||||
var copy = new ArrayList<>(selected);
|
||||
for (var a : copy) {
|
||||
// If the user decided to remove the selected entry
|
||||
// while the scan is running, just return instantly
|
||||
if (!DataStorage.get()
|
||||
.getStoreEntriesSet()
|
||||
.contains(entry.get().get())) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Previous scan operation could have exited the shell
|
||||
shellValidationContext.get().start();
|
||||
|
||||
try {
|
||||
a.getScanner().run();
|
||||
} catch (Throwable ex) {
|
||||
ErrorEvent.fromThrowable(ex).handle();
|
||||
}
|
||||
}
|
||||
});
|
||||
} finally {
|
||||
shellValidationContext.close();
|
||||
shellValidationContext = null;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Comp<?> pane(Comp<?> content) {
|
||||
return content;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Comp<?> content() {
|
||||
StackPane stackPane = new StackPane();
|
||||
stackPane.getStyleClass().add("scan-list");
|
||||
|
||||
var b = new OptionsBuilder()
|
||||
.name("scanAlertChoiceHeader")
|
||||
.description("scanAlertChoiceHeaderDescription")
|
||||
.addComp(new DataStoreChoiceComp<>(
|
||||
DataStoreChoiceComp.Mode.OTHER,
|
||||
null,
|
||||
entry,
|
||||
ShellStore.class,
|
||||
store1 -> true,
|
||||
StoreViewState.get().getAllConnectionsCategory())
|
||||
.disable(new SimpleBooleanProperty(initialStore != null)))
|
||||
.name("scanAlertHeader")
|
||||
.description("scanAlertHeaderDescription")
|
||||
.addComp(Comp.of(() -> stackPane).vgrow())
|
||||
.buildComp()
|
||||
.prefWidth(500)
|
||||
.prefHeight(680)
|
||||
.apply(struc -> {
|
||||
VBox.setVgrow(struc.get().getChildren().get(1), ALWAYS);
|
||||
})
|
||||
.padding(new Insets(5, 20, 20, 20));
|
||||
|
||||
entry.subscribe(newValue -> {
|
||||
selected.clear();
|
||||
stackPane.getChildren().clear();
|
||||
|
||||
if (newValue == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
ThreadHelper.runFailableAsync(() -> {
|
||||
BooleanScope.executeExclusive(busy, () -> {
|
||||
if (shellValidationContext != null) {
|
||||
shellValidationContext.close();
|
||||
shellValidationContext = null;
|
||||
}
|
||||
|
||||
shellValidationContext = new ShellValidationContext(newValue.getStore()
|
||||
.control()
|
||||
.withoutLicenseCheck()
|
||||
.start());
|
||||
var a = applicable.apply(entry.get().get(), shellValidationContext.get());
|
||||
|
||||
Platform.runLater(() -> {
|
||||
if (a == null) {
|
||||
window.close();
|
||||
return;
|
||||
}
|
||||
|
||||
selected.setAll(a.stream()
|
||||
.filter(scanOperation ->
|
||||
scanOperation.isDefaultSelected() && !scanOperation.isDisabled())
|
||||
.toList());
|
||||
Function<ScanProvider.ScanOperation, String> nameFunc = (ScanProvider.ScanOperation s) -> {
|
||||
var n = AppI18n.get(s.getNameKey());
|
||||
if (s.getLicensedFeatureId() == null) {
|
||||
return n;
|
||||
}
|
||||
|
||||
var suffix = LicenseProvider.get().getFeature(s.getLicensedFeatureId());
|
||||
return n
|
||||
+ suffix.getDescriptionSuffix()
|
||||
.map(d -> " (" + d + ")")
|
||||
.orElse("");
|
||||
};
|
||||
var r = new ListSelectorComp<>(
|
||||
a,
|
||||
nameFunc,
|
||||
selected,
|
||||
scanOperation -> scanOperation.isDisabled(),
|
||||
a.size() > 3)
|
||||
.createRegion();
|
||||
stackPane.getChildren().add(r);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
return b;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
180
app/src/main/java/io/xpipe/app/util/ScanDialog.java
Normal file
180
app/src/main/java/io/xpipe/app/util/ScanDialog.java
Normal file
|
@ -0,0 +1,180 @@
|
|||
package io.xpipe.app.util;
|
||||
|
||||
import io.xpipe.app.comp.base.DialogComp;
|
||||
import io.xpipe.app.comp.base.ListSelectorComp;
|
||||
import io.xpipe.app.comp.store.StoreViewState;
|
||||
import io.xpipe.app.core.AppI18n;
|
||||
import io.xpipe.app.ext.ScanProvider;
|
||||
import io.xpipe.app.fxcomps.Comp;
|
||||
import io.xpipe.app.fxcomps.impl.DataStoreChoiceComp;
|
||||
import io.xpipe.app.issue.ErrorEvent;
|
||||
import io.xpipe.app.storage.DataStorage;
|
||||
import io.xpipe.app.storage.DataStoreEntry;
|
||||
import io.xpipe.app.storage.DataStoreEntryRef;
|
||||
import io.xpipe.core.process.ShellControl;
|
||||
import io.xpipe.core.store.ShellStore;
|
||||
import io.xpipe.core.store.ShellValidationContext;
|
||||
import javafx.application.Platform;
|
||||
import javafx.beans.property.*;
|
||||
import javafx.beans.value.ObservableValue;
|
||||
import javafx.collections.FXCollections;
|
||||
import javafx.geometry.Insets;
|
||||
import javafx.scene.layout.StackPane;
|
||||
import javafx.scene.layout.VBox;
|
||||
import javafx.stage.Stage;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.function.BiFunction;
|
||||
import java.util.function.Function;
|
||||
|
||||
import static javafx.scene.layout.Priority.ALWAYS;
|
||||
|
||||
class ScanDialog extends DialogComp {
|
||||
|
||||
private final DataStoreEntryRef<ShellStore> initialStore;
|
||||
private final BiFunction<DataStoreEntry, ShellControl, List<ScanProvider.ScanOperation>> applicable;
|
||||
private final Stage window;
|
||||
private final ObjectProperty<DataStoreEntryRef<ShellStore>> entry;
|
||||
private final ListProperty<ScanProvider.ScanOperation> selected = new SimpleListProperty<>(FXCollections.observableArrayList());
|
||||
private final BooleanProperty busy = new SimpleBooleanProperty();
|
||||
private ShellValidationContext shellValidationContext;
|
||||
|
||||
ScanDialog(
|
||||
Stage window, DataStoreEntryRef<ShellStore> entry, BiFunction<DataStoreEntry, ShellControl, List<ScanProvider.ScanOperation>> applicable,
|
||||
ShellValidationContext shellValidationContext
|
||||
) {
|
||||
this.window = window;
|
||||
this.initialStore = entry;
|
||||
this.entry = new SimpleObjectProperty<>(entry);
|
||||
this.applicable = applicable;
|
||||
this.shellValidationContext = shellValidationContext;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ObservableValue<Boolean> busy() {
|
||||
return busy;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void finish() {
|
||||
ThreadHelper.runFailableAsync(() -> {
|
||||
try {
|
||||
if (entry.get() == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
Platform.runLater(() -> {
|
||||
window.close();
|
||||
});
|
||||
|
||||
BooleanScope.executeExclusive(busy, () -> {
|
||||
entry.get().get().setExpanded(true);
|
||||
var copy = new ArrayList<>(selected);
|
||||
for (var a : copy) {
|
||||
// If the user decided to remove the selected entry
|
||||
// while the scan is running, just return instantly
|
||||
if (!DataStorage.get().getStoreEntriesSet().contains(entry.get().get())) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Previous scan operation could have exited the shell
|
||||
shellValidationContext.get().start();
|
||||
|
||||
try {
|
||||
a.getScanner().run();
|
||||
} catch (Throwable ex) {
|
||||
ErrorEvent.fromThrowable(ex).handle();
|
||||
}
|
||||
}
|
||||
});
|
||||
} finally {
|
||||
shellValidationContext.close();
|
||||
shellValidationContext = null;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void discard() {
|
||||
ThreadHelper.runAsync(() -> {
|
||||
shellValidationContext.close();
|
||||
shellValidationContext = null;
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Comp<?> pane(Comp<?> content) {
|
||||
return content;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Comp<?> content() {
|
||||
StackPane stackPane = new StackPane();
|
||||
stackPane.getStyleClass().add("scan-list");
|
||||
|
||||
var b = new OptionsBuilder().name("scanAlertChoiceHeader")
|
||||
.description("scanAlertChoiceHeaderDescription")
|
||||
.addComp(new DataStoreChoiceComp<>(DataStoreChoiceComp.Mode.OTHER, null, entry, ShellStore.class, store1 -> true,
|
||||
StoreViewState.get().getAllConnectionsCategory()).disable(new SimpleBooleanProperty(initialStore != null)))
|
||||
.name("scanAlertHeader")
|
||||
.description("scanAlertHeaderDescription")
|
||||
.addComp(Comp.of(() -> stackPane).vgrow())
|
||||
.buildComp()
|
||||
.prefWidth(500)
|
||||
.prefHeight(680)
|
||||
.apply(struc -> {
|
||||
VBox.setVgrow(struc.get().getChildren().get(1), ALWAYS);
|
||||
})
|
||||
.padding(new Insets(5, 20, 20, 20));
|
||||
|
||||
entry.subscribe(newValue -> {
|
||||
onUpdate(newValue, stackPane);
|
||||
});
|
||||
|
||||
return b;
|
||||
}
|
||||
|
||||
private void onUpdate(DataStoreEntryRef<ShellStore> newValue, StackPane stackPane) {
|
||||
selected.clear();
|
||||
stackPane.getChildren().clear();
|
||||
|
||||
if (newValue == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
ThreadHelper.runFailableAsync(() -> {
|
||||
BooleanScope.executeExclusive(busy, () -> {
|
||||
if (shellValidationContext != null) {
|
||||
shellValidationContext.close();
|
||||
shellValidationContext = null;
|
||||
}
|
||||
|
||||
shellValidationContext = new ShellValidationContext(newValue.getStore().control().withoutLicenseCheck().start());
|
||||
var a = applicable.apply(entry.get().get(), shellValidationContext.get());
|
||||
|
||||
Platform.runLater(() -> {
|
||||
if (a == null) {
|
||||
window.close();
|
||||
return;
|
||||
}
|
||||
|
||||
selected.setAll(
|
||||
a.stream().filter(scanOperation -> scanOperation.isDefaultSelected() && !scanOperation.isDisabled()).toList());
|
||||
Function<ScanProvider.ScanOperation, String> nameFunc = (ScanProvider.ScanOperation s) -> {
|
||||
var n = AppI18n.get(s.getNameKey());
|
||||
if (s.getLicensedFeatureId() == null) {
|
||||
return n;
|
||||
}
|
||||
|
||||
var suffix = LicenseProvider.get().getFeature(s.getLicensedFeatureId());
|
||||
return n + suffix.getDescriptionSuffix().map(d -> " (" + d + ")").orElse("");
|
||||
};
|
||||
var r = new ListSelectorComp<>(a, nameFunc, selected, scanOperation -> scanOperation.isDisabled(),
|
||||
a.size() > 3).createRegion();
|
||||
stackPane.getChildren().add(r);
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue