This commit is contained in:
crschnick
2026-01-22 15:33:26 +00:00
parent f47b482816
commit ded364ab7b
22 changed files with 152 additions and 37 deletions
@@ -32,7 +32,8 @@ public final class BrowserConnectionListFilterComp extends SimpleRegionBuilder {
var category = new DataStoreCategoryChoiceComp(
StoreViewState.get().getAllConnectionsCategory(),
StoreViewState.get().getActiveCategory(),
this.category)
this.category,
true)
.style(Styles.LEFT_PILL)
.apply(struc -> {
AppFontSizes.base(struc);
@@ -11,6 +11,7 @@ import javafx.collections.ListChangeListener;
import javafx.collections.ObservableList;
import javafx.geometry.Orientation;
import javafx.geometry.Pos;
import javafx.scene.Node;
import javafx.scene.control.CheckBox;
import javafx.scene.control.Label;
import javafx.scene.control.ScrollPane;
@@ -65,6 +66,7 @@ public class ListSelectorComp<T> extends SimpleRegionBuilder {
}
vbox.getChildren().clear();
cbs.clear();
var newChildren = new ArrayList<Node>();
for (var v : currentVals) {
var cb = new CheckBox(null);
if (disable.test(v)) {
@@ -105,8 +107,9 @@ public class ListSelectorComp<T> extends SimpleRegionBuilder {
event.consume();
});
l.opacityProperty().bind(cb.opacityProperty());
vbox.getChildren().add(l);
newChildren.add(l);
}
vbox.getChildren().addAll(newChildren);
if (showAllSelector.get()) {
var allSelector = new CheckBox(null);
@@ -19,17 +19,20 @@ public class DataStoreCategoryChoiceComp extends SimpleRegionBuilder {
private final StoreCategoryWrapper root;
private final Property<StoreCategoryWrapper> external;
private final Property<StoreCategoryWrapper> value;
private final boolean applyExternalInitially;
public DataStoreCategoryChoiceComp(
StoreCategoryWrapper root, Property<StoreCategoryWrapper> external, Property<StoreCategoryWrapper> value) {
StoreCategoryWrapper root, Property<StoreCategoryWrapper> external, Property<StoreCategoryWrapper> value, boolean applyExternalInitially) {
this.root = root;
this.external = external;
this.value = value;
this.applyExternalInitially = applyExternalInitially;
}
@Override
protected Region createSimple() {
var initialized = new SimpleBooleanProperty();
var last = value.getValue();
external.subscribe(newValue -> {
if (newValue == null) {
value.setValue(root);
@@ -44,6 +47,9 @@ public class DataStoreCategoryChoiceComp extends SimpleRegionBuilder {
}
initialized.set(true);
});
if (!applyExternalInitially) {
value.setValue(last);
}
var box = new ComboBox<>(StoreViewState.get().getSortedCategories(root).getList());
box.setValue(value.getValue());
box.valueProperty().addListener((observable, oldValue, newValue) -> {
@@ -22,6 +22,8 @@ import javafx.scene.layout.Region;
import atlantafx.base.theme.Styles;
import lombok.RequiredArgsConstructor;
import lombok.Setter;
import lombok.val;
import org.int4.fx.builders.common.AbstractRegionBuilder;
import io.xpipe.app.comp.BaseRegionBuilder;
import org.kordamp.ikonli.javafx.FontIcon;
@@ -33,22 +35,33 @@ public class StoreChoiceComp<T extends DataStore> extends SimpleRegionBuilder {
private final ObjectProperty<DataStoreEntryRef<T>> selected;
private final StoreChoicePopover<T> popover;
private StoreChoicePopover<T> popover;
public StoreChoiceComp(
DataStoreEntry self,
ObjectProperty<DataStoreEntryRef<T>> selected,
Class<?> storeClass,
Predicate<DataStoreEntryRef<T>> applicableCheck,
StoreCategoryWrapper initialCategory) {
StoreCategoryWrapper categoryRoot) {
this(self, selected, storeClass, applicableCheck, categoryRoot, null);
}
public StoreChoiceComp(
DataStoreEntry self,
ObjectProperty<DataStoreEntryRef<T>> selected,
Class<?> storeClass,
Predicate<DataStoreEntryRef<T>> applicableCheck,
StoreCategoryWrapper categoryRoot,
StoreCategoryWrapper explicitCategory) {
this.selected = selected;
this.popover = new StoreChoicePopover<>(
self,
selected,
storeClass,
applicableCheck,
initialCategory,
"selectConnection",
categoryRoot,
explicitCategory,
StoreViewState.get().getAllConnectionsCategory().equals(categoryRoot) ? "selectConnection" : "selectEntry",
"noCompatibleConnection");
}
@@ -60,13 +73,21 @@ public class StoreChoiceComp<T extends DataStore> extends SimpleRegionBuilder {
return DataStorage.get().getStoreEntryDisplayName(entry);
}
protected String toGraphic(DataStoreEntry entry) {
if (entry == null) {
return null;
}
return entry.getEffectiveIconFile();
}
@Override
protected Region createSimple() {
var button = new ButtonComp(
Bindings.createStringBinding(
() -> {
var val = selected.getValue();
return val != null ? toName(val.get()) : null;
return toName(val != null ? val.get() : null);
},
selected),
() -> {});
@@ -84,12 +105,7 @@ public class StoreChoiceComp<T extends DataStore> extends SimpleRegionBuilder {
BaseRegionBuilder<?,?> graphic = PrettyImageHelper.ofFixedSize(
Bindings.createStringBinding(
() -> {
var val = selected.getValue();
if (val == null) {
return null;
}
return val.get().getEffectiveIconFile();
return toGraphic(selected.getValue() != null ? selected.getValue().get() : null);
},
selected),
16,
@@ -119,6 +135,7 @@ public class StoreChoiceComp<T extends DataStore> extends SimpleRegionBuilder {
AppFontSizes.xl(dropdownIcon);
var pane = new AnchorPane(r, dropdownIcon);
r.prefHeightProperty().bind(pane.heightProperty());
pane.focusedProperty().addListener((observable, oldValue, newValue) -> {
if (newValue) {
r.requestFocus();
@@ -43,7 +43,8 @@ public class StoreChoicePopover<T extends DataStore> {
private final Property<DataStoreEntryRef<T>> selected;
private final Class<?> storeClass;
private final Predicate<DataStoreEntryRef<T>> applicableCheck;
private final StoreCategoryWrapper initialCategory;
private final StoreCategoryWrapper rootCategory;
private final StoreCategoryWrapper explicitCategory;
private final String titleKey;
private final String noMatchKey;
private Consumer<Popover> consumer;
@@ -74,9 +75,9 @@ public class StoreChoicePopover<T extends DataStore> {
if (popover == null || applicableCheck != null) {
var cur = StoreViewState.get().getActiveCategory().getValue();
var selectedCategory = new SimpleObjectProperty<>(
initialCategory != null
? (initialCategory.getRoot().equals(cur.getRoot()) ? cur : initialCategory)
: cur);
explicitCategory != null ? explicitCategory : (rootCategory != null
? (rootCategory.getRoot().equals(cur.getRoot()) ? cur : rootCategory)
: cur));
var filterText = new SimpleStringProperty();
popover = new Popover();
Predicate<StoreEntryWrapper> applicable = storeEntryWrapper -> {
@@ -101,7 +102,7 @@ public class StoreChoicePopover<T extends DataStore> {
var applicableMatch =
StoreViewState.get().getCurrentTopLevelSection().anyMatches(applicable);
if (!applicableMatch) {
selectedCategory.set(initialCategory);
selectedCategory.set(rootCategory);
}
var applicableCount = StoreViewState.get().getAllEntries().getList().stream()
@@ -134,9 +135,10 @@ public class StoreChoicePopover<T extends DataStore> {
initialExpanded);
var category = new DataStoreCategoryChoiceComp(
initialCategory != null ? initialCategory.getRoot() : null,
rootCategory != null ? rootCategory.getRoot() : null,
StoreViewState.get().getActiveCategory(),
selectedCategory)
selectedCategory,
explicitCategory == null)
.style(Styles.LEFT_PILL);
var filter =
new FilterComp(filterText).style(Styles.CENTER_PILL).hgrow();
@@ -75,6 +75,7 @@ public class StoreComboChoiceComp<T extends DataStore> extends SimpleRegionBuild
storeClass,
applicableCheck,
initialCategory,
null,
"selectConnection",
"noCompatibleConnection");
@@ -302,6 +302,7 @@ public class IdentitySelectComp extends RegionBuilder<HBox> {
IdentityStore.class,
null,
StoreViewState.get().getAllIdentitiesCategory(),
null,
"selectIdentity",
"noCompatibleIdentity");
@@ -1,25 +1,38 @@
package io.xpipe.ext.base.script;
import io.xpipe.app.comp.RegionBuilder;
import io.xpipe.app.comp.base.*;
import io.xpipe.app.core.AppI18n;
import io.xpipe.app.ext.ShellDialectChoiceComp;
import io.xpipe.app.ext.ShellDialectIcons;
import io.xpipe.app.hub.comp.StoreChoiceComp;
import io.xpipe.app.hub.comp.StoreCreationDialog;
import io.xpipe.app.hub.comp.StoreViewState;
import io.xpipe.app.issue.ErrorEventFactory;
import io.xpipe.app.platform.DerivedObservableList;
import io.xpipe.app.platform.LabelGraphic;
import io.xpipe.app.platform.OptionsBuilder;
import io.xpipe.app.prefs.AppPrefs;
import io.xpipe.app.storage.DataStorage;
import io.xpipe.app.storage.DataStoreEntry;
import io.xpipe.app.storage.DataStoreEntryRef;
import io.xpipe.app.util.BooleanScope;
import io.xpipe.app.util.ThreadHelper;
import io.xpipe.core.FilePath;
import io.xpipe.ext.base.desktop.DesktopBaseStore;
import javafx.application.Platform;
import javafx.beans.binding.Bindings;
import javafx.beans.property.*;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.scene.layout.HBox;
import javafx.scene.layout.Priority;
import lombok.Getter;
import org.kordamp.ikonli.javafx.FontIcon;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
public class ScriptCollectionSourceImportDialog {
@@ -30,6 +43,7 @@ public class ScriptCollectionSourceImportDialog {
private final StringProperty filter = new SimpleStringProperty();
private final BooleanProperty busy = new SimpleBooleanProperty();
private final IntegerProperty count = new SimpleIntegerProperty();
private final ObjectProperty<DataStoreEntryRef<ScriptGroupStore>> targetGroup = new SimpleObjectProperty<>();
public ScriptCollectionSourceImportDialog(ScriptCollectionSource source) {
this.source = source;
@@ -45,6 +59,7 @@ public class ScriptCollectionSourceImportDialog {
var filterField = new FilterComp(filter).hgrow();
// Ugly solution to focus the filter on show
filterField.apply(r -> {
HBox.setHgrow(r, Priority.SOMETIMES);
r.sceneProperty().subscribe(s -> {
if (s != null) {
Platform.runLater(() -> {
@@ -81,7 +96,35 @@ public class ScriptCollectionSourceImportDialog {
var stack = new StackComp(List.of(notFound, selector));
stack.prefWidth(600);
stack.prefHeight(700);
stack.prefHeight(650);
var storeChoice = new StoreChoiceComp<>(
null,
targetGroup,
ScriptGroupStore.class,
null,
StoreViewState.get().getAllScriptsCategory(),
StoreViewState.get().getAllScriptsCategory()) {
@Override
protected String toName(DataStoreEntry entry) {
if (entry == null) {
return AppI18n.get("selectCategory");
} else {
return super.toName(entry);
}
}
@Override
protected String toGraphic(DataStoreEntry entry) {
if (entry == null) {
return "scriptGroup_icon.svg";
} else {
return super.toGraphic(entry);
}
}
};
storeChoice.hgrow();
storeChoice.maxHeight(100);
var modal = ModalOverlay.of(
Bindings.createStringBinding(() -> {
@@ -91,13 +134,42 @@ public class ScriptCollectionSourceImportDialog {
null);
modal.addButtonBarComp(refresh);
modal.addButtonBarComp(filterField);
modal.addButtonBarComp(storeChoice);
modal.addButton(ModalButton.ok(() -> {
ThreadHelper.runAsync(() -> {
finish();
});
}))
.augment(button -> button.disableProperty().bind(Bindings.isEmpty(selected)));
.augment(button -> button.disableProperty().bind(Bindings.isEmpty(selected).or(targetGroup.isNull())));
modal.show();
}
private void finish() {
var targetCat = DataStorage.get().getStoreCategory(targetGroup.getValue().get());
StoreViewState.get().selectCategoryIntoViewIfNeeded(StoreViewState.get().getCategoryWrapper(targetCat));
var added = new ArrayList<DataStoreEntry>();
for (ScriptCollectionSourceEntry e : selected) {
var name = FilePath.of(e.getName()).getBaseName().toString();
var textSource = ScriptTextSource.SourceReference.builder().entry(e).build();
var alreadyAdded = DataStorage.get().getStoreEntries().stream().anyMatch(entry -> entry.getStore() instanceof ScriptStore ss &&
textSource.equals(ss.getTextSource()));
if (alreadyAdded) {
continue;
}
var store = ScriptStore.builder().textSource(textSource).group(targetGroup.get()).build();
var entry = DataStoreEntry.createNew(name, store);
DataStorage.get().addStoreEntryIfNotPresent(entry);
added.add(entry);
}
if (added.size() == 1) {
StoreCreationDialog.showEdit(added.getFirst());
}
}
private void update() {
if (filter.get() == null) {
shown.setAll(available);
@@ -29,7 +29,7 @@ public class ScriptCollectionSourceImportHubProvider implements HubLeafProvider<
@Override
public LabelGraphic getIcon(DataStoreEntryRef<ScriptCollectionSourceStore> store) {
return new LabelGraphic.IconGraphic("mdi2f-file-undo-outline");
return new LabelGraphic.IconGraphic("mdi2i-import");
}
@Override
@@ -91,8 +91,9 @@ public class ScriptCollectionSourceStoreProvider implements DataStoreProvider {
return Bindings.createStringBinding(() -> {
var s = st.getState();
var summary = st.getSource().toSummary();
var init = s.getEntries() != null;
var format = new StoreStateFormat(List.of(), summary,
s.getEntries() != null ? AppI18n.get("scriptsContained", s.getEntries().size()) : null);
init ? AppI18n.get("scriptsContained", s.getEntries().size()) : null, !init ? AppI18n.get("notInitialized") : null);
return format.format();
}, section.getWrapper().getPersistentState(), AppI18n.activeLanguage());
}
+1 -1
View File
@@ -34,7 +34,7 @@ open module io.xpipe.ext.base {
requires com.sun.jna;
requires javafx.base;
requires javafx.graphics;
provides ActionProvider with
IdentityApplyHubLeafProvider,
AbstractHostCreationActionProvider,
Binary file not shown.

Before

Width:  |  Height:  |  Size: 442 B

After

Width:  |  Height:  |  Size: 472 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 451 B

After

Width:  |  Height:  |  Size: 478 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 562 B

After

Width:  |  Height:  |  Size: 602 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 576 B

After

Width:  |  Height:  |  Size: 607 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 772 B

After

Width:  |  Height:  |  Size: 839 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 783 B

After

Width:  |  Height:  |  Size: 840 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

After

Width:  |  Height:  |  Size: 1.4 KiB

+8 -5
View File
@@ -22,9 +22,9 @@
inkscape:pageopacity="0.0"
inkscape:pagecheckerboard="0"
inkscape:deskcolor="#d1d1d1"
inkscape:zoom="0.9861186"
inkscape:cx="-94.309143"
inkscape:cy="129.29479"
inkscape:zoom="1"
inkscape:cx="104"
inkscape:cy="-51.5"
inkscape:window-width="1920"
inkscape:window-height="1009"
inkscape:window-x="-8"
@@ -37,7 +37,7 @@
id="title858">identity</title><metadata
id="metadata932"><rdf:RDF><cc:Work
rdf:about=""><dc:title>identity</dc:title></cc:Work></rdf:RDF></metadata><rect
style="fill:#11b011;fill-opacity:1;stroke:none;stroke-width:4.74555"
style="fill:#0066e3;fill-opacity:1;stroke:none;stroke-width:4.74555"
id="rect1"
width="121.50683"
height="21.030029"
@@ -45,4 +45,7 @@
y="94.474846" /><path
d="M 177.95845,49.696965 H 60.617329 c 0,-11.767445 9.567305,-21.33475 21.33475,-21.33475 h 96.006371 c 11.76745,0 21.33475,9.567305 21.33475,21.33475 v 64.004265 c 0,11.76745 -9.5673,21.33475 -21.33475,21.33475 h -16.00106 v -21.33475 h 16.00106 z M 7.2804476,92.366468 c 0,-11.767448 9.5673054,-21.334741 21.3347504,-21.334741 h 96.006372 c 11.76746,0 21.33475,9.567293 21.33475,21.334741 v 64.004262 c 0,11.76744 -9.56729,21.33475 -21.33475,21.33475 H 28.615198 c -11.767445,0 -21.3347504,-9.56731 -21.3347504,-21.33475 z M 28.615198,105.70069 c 0,4.43363 3.566908,8.00054 8.00053,8.00054 h 80.005312 c 4.43363,0 8.00053,-3.56691 8.00053,-8.00054 0,-4.43362 -3.5669,-8.000531 -8.00053,-8.000531 H 36.615728 c -4.433622,0 -8.00053,3.566911 -8.00053,8.000531 z"
id="path1"
style="fill:#f38626;fill-opacity:1;stroke-width:0.333356" /></svg>
style="fill:#f38626;fill-opacity:1;stroke-width:0.333356" /><path
d="M 177.9574,49.697613 H 60.616282 c 0,-11.767445 9.567306,-21.33475 21.33475,-21.33475 H 177.9574 c 11.76745,0 21.33475,9.567305 21.33475,21.33475 v 64.004267 c 0,11.76744 -9.5673,21.33475 -21.33475,21.33475 h -16.00106 v -21.33475 h 16.00106 z"
style="fill:#38ad35;fill-opacity:1;stroke-width:0.333356"
id="path1-9" /></svg>

Before

Width:  |  Height:  |  Size: 2.5 KiB

After

Width:  |  Height:  |  Size: 2.8 KiB

+9 -5
View File
@@ -22,9 +22,9 @@
inkscape:pageopacity="0.0"
inkscape:pagecheckerboard="0"
inkscape:deskcolor="#d1d1d1"
inkscape:zoom="1.3945823"
inkscape:cx="-15.775333"
inkscape:cy="89.991103"
inkscape:zoom="0.9861186"
inkscape:cx="-11.154845"
inkscape:cy="-62.365723"
inkscape:window-width="1920"
inkscape:window-height="1009"
inkscape:window-x="-8"
@@ -37,7 +37,7 @@
id="title858">identity</title><metadata
id="metadata932"><rdf:RDF><cc:Work
rdf:about=""><dc:title>identity</dc:title></cc:Work></rdf:RDF></metadata><rect
style="fill:#18ce16;fill-opacity:1;stroke:none;stroke-width:4.74555"
style="fill:#0066e3;fill-opacity:1;stroke:none;stroke-width:4.74555"
id="rect1"
width="121.50683"
height="21.030029"
@@ -45,4 +45,8 @@
y="94.474846" /><path
d="M 177.95845,49.696965 H 60.617329 c 0,-11.767445 9.567305,-21.33475 21.33475,-21.33475 h 96.006371 c 11.76745,0 21.33475,9.567305 21.33475,21.33475 v 64.004265 c 0,11.76745 -9.5673,21.33475 -21.33475,21.33475 h -16.00106 v -21.33475 h 16.00106 z M 7.2804476,92.366468 c 0,-11.767448 9.5673054,-21.334741 21.3347504,-21.334741 h 96.006372 c 11.76746,0 21.33475,9.567293 21.33475,21.334741 v 64.004262 c 0,11.76744 -9.56729,21.33475 -21.33475,21.33475 H 28.615198 c -11.767445,0 -21.3347504,-9.56731 -21.3347504,-21.33475 z M 28.615198,105.70069 c 0,4.43363 3.566908,8.00054 8.00053,8.00054 h 80.005312 c 4.43363,0 8.00053,-3.56691 8.00053,-8.00054 0,-4.43362 -3.5669,-8.000531 -8.00053,-8.000531 H 36.615728 c -4.433622,0 -8.00053,3.566911 -8.00053,8.000531 z"
id="path1"
style="fill:#e1710c;fill-opacity:1;stroke-width:0.333356" /></svg>
style="fill:#e1710c;fill-opacity:1;stroke-width:0.333356"
sodipodi:nodetypes="ccsssssccccssssssssssssssss" /><path
d="M 177.96605,49.703711 H 60.624928 c 0,-11.767445 9.567305,-21.33475 21.33475,-21.33475 h 96.006372 c 11.76745,0 21.33475,9.567305 21.33475,21.33475 v 64.004259 c 0,11.76745 -9.5673,21.33475 -21.33475,21.33475 h -16.00106 v -21.33475 h 16.00106 z"
style="fill:#30962e;fill-opacity:1;stroke-width:0.333356"
id="path1-9" /></svg>

Before

Width:  |  Height:  |  Size: 2.5 KiB

After

Width:  |  Height:  |  Size: 2.9 KiB

+4
View File
@@ -74,6 +74,7 @@ customCommand=Custom command
other=Other
setLock=Set lock
selectConnection=Select connection
selectEntry=Select entry
createLock=Create passphrase
changeLock=Change passphrase
test=Test
@@ -1928,3 +1929,6 @@ importScripts=Import scripts
scriptsContained=$NUMBER$ scripts
scriptSourceCollectionImportTitle=Import scripts from source ($COUNT$)
noScriptsFound=No scripts found
tunnel=Tunnel
notInitialized=Not initialized
selectCategory=Select category ...