mirror of
https://github.com/xpipe-io/xpipe.git
synced 2026-05-19 13:58:37 -04:00
More ui rework
This commit is contained in:
@@ -1,6 +1,5 @@
|
||||
package io.xpipe.app.comp.storage.store;
|
||||
|
||||
import atlantafx.base.controls.Spacer;
|
||||
import atlantafx.base.theme.Styles;
|
||||
import com.jfoenix.controls.JFXButton;
|
||||
import io.xpipe.app.comp.base.LoadingOverlayComp;
|
||||
@@ -13,14 +12,12 @@ import io.xpipe.app.fxcomps.SimpleCompStructure;
|
||||
import io.xpipe.app.fxcomps.augment.ContextMenuAugment;
|
||||
import io.xpipe.app.fxcomps.augment.GrowAugment;
|
||||
import io.xpipe.app.fxcomps.impl.*;
|
||||
import io.xpipe.app.fxcomps.util.BindingsHelper;
|
||||
import io.xpipe.app.fxcomps.util.PlatformThread;
|
||||
import io.xpipe.app.fxcomps.util.SimpleChangeListener;
|
||||
import io.xpipe.app.prefs.AppPrefs;
|
||||
import io.xpipe.app.storage.DataStorage;
|
||||
import io.xpipe.app.util.DesktopHelper;
|
||||
import io.xpipe.app.util.ThreadHelper;
|
||||
import io.xpipe.core.store.FixedHierarchyStore;
|
||||
import javafx.beans.binding.Bindings;
|
||||
import javafx.beans.property.SimpleStringProperty;
|
||||
import javafx.css.PseudoClass;
|
||||
@@ -30,8 +27,6 @@ import javafx.scene.Node;
|
||||
import javafx.scene.control.*;
|
||||
import javafx.scene.input.MouseButton;
|
||||
import javafx.scene.layout.ColumnConstraints;
|
||||
import javafx.scene.layout.HBox;
|
||||
import javafx.scene.layout.Priority;
|
||||
import javafx.scene.layout.Region;
|
||||
import org.kordamp.ikonli.javafx.FontIcon;
|
||||
|
||||
@@ -50,11 +45,11 @@ public abstract class StoreEntryComp extends SimpleComp {
|
||||
|
||||
public static final PseudoClass FAILED = PseudoClass.getPseudoClass("failed");
|
||||
public static final PseudoClass INCOMPLETE = PseudoClass.getPseudoClass("incomplete");
|
||||
protected final StoreEntryWrapper entry;
|
||||
protected final StoreEntryWrapper wrapper;
|
||||
protected final Comp<?> content;
|
||||
|
||||
public StoreEntryComp(StoreEntryWrapper entry, Comp<?> content) {
|
||||
this.entry = entry;
|
||||
public StoreEntryComp(StoreEntryWrapper wrapper, Comp<?> content) {
|
||||
this.wrapper = wrapper;
|
||||
this.content = content;
|
||||
}
|
||||
|
||||
@@ -72,23 +67,19 @@ public abstract class StoreEntryComp extends SimpleComp {
|
||||
button.accessibleTextProperty()
|
||||
.bind(Bindings.createStringBinding(
|
||||
() -> {
|
||||
return entry.getName();
|
||||
return wrapper.getName();
|
||||
},
|
||||
entry.nameProperty()));
|
||||
button.accessibleHelpProperty().bind(entry.getInformation());
|
||||
wrapper.nameProperty()));
|
||||
button.accessibleHelpProperty().bind(wrapper.getInformation());
|
||||
button.setOnAction(event -> {
|
||||
event.consume();
|
||||
ThreadHelper.runFailableAsync(() -> {
|
||||
entry.executeDefaultAction();
|
||||
wrapper.executeDefaultAction();
|
||||
});
|
||||
});
|
||||
new ContextMenuAugment<>(() -> this.createContextMenu())
|
||||
.augment(new SimpleCompStructure<>(button));
|
||||
new ContextMenuAugment<>(() -> this.createContextMenu()).augment(new SimpleCompStructure<>(button));
|
||||
|
||||
HBox.setHgrow(button, Priority.ALWAYS);
|
||||
var hbox = new HBox(button, new Spacer(25));
|
||||
|
||||
var loading = new LoadingOverlayComp(Comp.of(() -> hbox), entry.getLoading());
|
||||
var loading = new LoadingOverlayComp(Comp.of(() -> button), wrapper.getLoading());
|
||||
var region = loading.createRegion();
|
||||
return region;
|
||||
}
|
||||
@@ -98,11 +89,13 @@ public abstract class StoreEntryComp extends SimpleComp {
|
||||
protected Label createInformation() {
|
||||
var information = new Label();
|
||||
information.setGraphicTextGap(7);
|
||||
information.textProperty().bind(PlatformThread.sync(entry.getInformation()));
|
||||
information.textProperty().bind(PlatformThread.sync(wrapper.getInformation()));
|
||||
information.getStyleClass().add("information");
|
||||
AppFont.header(information);
|
||||
|
||||
var state = entry.getEntry().getProvider().stateDisplay(entry);
|
||||
var state = wrapper.getEntry().getProvider() != null
|
||||
? wrapper.getEntry().getProvider().stateDisplay(wrapper)
|
||||
: Comp.empty();
|
||||
information.setGraphic(state.createRegion());
|
||||
|
||||
return information;
|
||||
@@ -110,14 +103,14 @@ public abstract class StoreEntryComp extends SimpleComp {
|
||||
|
||||
protected Label createSummary() {
|
||||
var summary = new Label();
|
||||
summary.textProperty().bind(PlatformThread.sync(entry.getSummary()));
|
||||
summary.textProperty().bind(PlatformThread.sync(wrapper.getSummary()));
|
||||
summary.getStyleClass().add("summary");
|
||||
AppFont.small(summary);
|
||||
return summary;
|
||||
}
|
||||
|
||||
protected void applyState(Node node) {
|
||||
SimpleChangeListener.apply(PlatformThread.sync(entry.getState()), val -> {
|
||||
SimpleChangeListener.apply(PlatformThread.sync(wrapper.getState()), val -> {
|
||||
switch (val) {
|
||||
case LOAD_FAILED -> {
|
||||
node.pseudoClassStateChanged(FAILED, true);
|
||||
@@ -136,24 +129,24 @@ public abstract class StoreEntryComp extends SimpleComp {
|
||||
}
|
||||
|
||||
protected Comp<?> createName() {
|
||||
var filtered = BindingsHelper.filteredContentBinding(
|
||||
StoreViewState.get().getAllEntries(),
|
||||
other -> other.getEntry().getState().isUsable()
|
||||
&& entry.getEntry()
|
||||
.getStore()
|
||||
.equals(other.getEntry()
|
||||
.getProvider()
|
||||
.getLogicalParent(other.getEntry().getStore())));
|
||||
// var filtered = BindingsHelper.filteredContentBinding(
|
||||
// StoreViewState.get().getAllEntries(),
|
||||
// other -> other.getEntry().getState().isUsable()
|
||||
// && entry.getEntry()
|
||||
// .getStore()
|
||||
// .equals(other.getEntry()
|
||||
// .getProvider()
|
||||
// .getLogicalParent(other.getEntry().getStore())));
|
||||
LabelComp name = new LabelComp(Bindings.createStringBinding(
|
||||
() -> {
|
||||
return entry.getName()
|
||||
+ (filtered.size() > 0 && entry.getEntry().getStore() instanceof FixedHierarchyStore
|
||||
? " (" + filtered.size() + ")"
|
||||
: "");
|
||||
return wrapper.getName();
|
||||
// + (filtered.size() > 0 && entry.getEntry().getStore() instanceof
|
||||
// FixedHierarchyStore
|
||||
// ? " (" + filtered.size() + ")"
|
||||
// : "");
|
||||
},
|
||||
entry.nameProperty(),
|
||||
entry.getInformation(),
|
||||
filtered));
|
||||
wrapper.nameProperty(),
|
||||
wrapper.getInformation()));
|
||||
name.apply(struc -> struc.get().setTextOverrun(OverrunStyle.CENTER_ELLIPSIS))
|
||||
.apply(struc -> struc.get().setPadding(new Insets(5, 5, 5, 0)));
|
||||
name.apply(s -> AppFont.header(s.get()));
|
||||
@@ -161,17 +154,17 @@ public abstract class StoreEntryComp extends SimpleComp {
|
||||
}
|
||||
|
||||
protected Node createIcon(int w, int h) {
|
||||
var img = entry.isDisabled()
|
||||
var img = wrapper.isDisabled()
|
||||
? "disabled_icon.png"
|
||||
: entry.getEntry()
|
||||
: wrapper.getEntry()
|
||||
.getProvider()
|
||||
.getDisplayIconFileName(entry.getEntry().getStore());
|
||||
.getDisplayIconFileName(wrapper.getEntry().getStore());
|
||||
var imageComp = new PrettyImageComp(new SimpleStringProperty(img), w, h);
|
||||
var storeIcon = imageComp.createRegion();
|
||||
storeIcon.getStyleClass().add("icon");
|
||||
if (entry.getState().getValue().isUsable()) {
|
||||
if (wrapper.getState().getValue().isUsable()) {
|
||||
new FancyTooltipAugment<>(new SimpleStringProperty(
|
||||
entry.getEntry().getProvider().getDisplayName()))
|
||||
wrapper.getEntry().getProvider().getDisplayName()))
|
||||
.augment(storeIcon);
|
||||
}
|
||||
storeIcon.setPadding(new Insets(3, 0, 0, 0));
|
||||
@@ -180,23 +173,23 @@ public abstract class StoreEntryComp extends SimpleComp {
|
||||
|
||||
protected Comp<?> createButtonBar() {
|
||||
var list = new ArrayList<Comp<?>>();
|
||||
for (var p : entry.getActionProviders().entrySet()) {
|
||||
for (var p : wrapper.getActionProviders().entrySet()) {
|
||||
var actionProvider = p.getKey().getDataStoreCallSite();
|
||||
if (!actionProvider.isMajor()
|
||||
|| p.getKey().equals(entry.getDefaultActionProvider().getValue())) {
|
||||
|| p.getKey().equals(wrapper.getDefaultActionProvider().getValue())) {
|
||||
continue;
|
||||
}
|
||||
|
||||
var button = new IconButtonComp(
|
||||
actionProvider.getIcon(entry.getEntry().getStore().asNeeded()), () -> {
|
||||
actionProvider.getIcon(wrapper.getEntry().getStore().asNeeded()), () -> {
|
||||
ThreadHelper.runFailableAsync(() -> {
|
||||
var action = actionProvider.createAction(
|
||||
entry.getEntry().getStore().asNeeded());
|
||||
wrapper.getEntry().getStore().asNeeded());
|
||||
action.execute();
|
||||
});
|
||||
});
|
||||
button.apply(new FancyTooltipAugment<>(
|
||||
actionProvider.getName(entry.getEntry().getStore().asNeeded())));
|
||||
actionProvider.getName(wrapper.getEntry().getStore().asNeeded())));
|
||||
if (actionProvider.activeType() == ActionProvider.DataStoreCallSite.ActiveType.ONLY_SHOW_IF_ENABLED) {
|
||||
button.hide(Bindings.not(p.getValue()));
|
||||
} else if (actionProvider.activeType() == ActionProvider.DataStoreCallSite.ActiveType.ALWAYS_SHOW) {
|
||||
@@ -239,19 +232,19 @@ public abstract class StoreEntryComp extends SimpleComp {
|
||||
var contextMenu = new ContextMenu();
|
||||
AppFont.normal(contextMenu.getStyleableNode());
|
||||
|
||||
for (var p : entry.getActionProviders().entrySet()) {
|
||||
for (var p : wrapper.getActionProviders().entrySet()) {
|
||||
var actionProvider = p.getKey().getDataStoreCallSite();
|
||||
if (actionProvider.isMajor()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
var name = actionProvider.getName(entry.getEntry().getStore().asNeeded());
|
||||
var icon = actionProvider.getIcon(entry.getEntry().getStore().asNeeded());
|
||||
var name = actionProvider.getName(wrapper.getEntry().getStore().asNeeded());
|
||||
var icon = actionProvider.getIcon(wrapper.getEntry().getStore().asNeeded());
|
||||
var item = new MenuItem(null, new FontIcon(icon));
|
||||
item.setOnAction(event -> {
|
||||
ThreadHelper.runFailableAsync(() -> {
|
||||
var action = actionProvider.createAction(
|
||||
entry.getEntry().getStore().asNeeded());
|
||||
wrapper.getEntry().getStore().asNeeded());
|
||||
action.execute();
|
||||
});
|
||||
});
|
||||
@@ -264,27 +257,27 @@ public abstract class StoreEntryComp extends SimpleComp {
|
||||
contextMenu.getItems().add(item);
|
||||
}
|
||||
|
||||
if (entry.getActionProviders().size() > 0) {
|
||||
if (wrapper.getActionProviders().size() > 0) {
|
||||
contextMenu.getItems().add(new SeparatorMenuItem());
|
||||
}
|
||||
|
||||
if (AppPrefs.get().developerMode().getValue()) {
|
||||
var browse = new MenuItem(AppI18n.get("browse"), new FontIcon("mdi2f-folder-open-outline"));
|
||||
browse.setOnAction(
|
||||
event -> DesktopHelper.browsePath(entry.getEntry().getDirectory()));
|
||||
event -> DesktopHelper.browsePath(wrapper.getEntry().getDirectory()));
|
||||
contextMenu.getItems().add(browse);
|
||||
}
|
||||
|
||||
var refresh = new MenuItem(AppI18n.get("refresh"), new FontIcon("mdal-360"));
|
||||
refresh.disableProperty().bind(entry.getRefreshable().not());
|
||||
refresh.disableProperty().bind(wrapper.getRefreshable().not());
|
||||
refresh.setOnAction(event -> {
|
||||
DataStorage.get().refreshAsync(entry.getEntry(), true);
|
||||
DataStorage.get().refreshAsync(wrapper.getEntry(), true);
|
||||
});
|
||||
contextMenu.getItems().add(refresh);
|
||||
|
||||
var del = new MenuItem(AppI18n.get("remove"), new FontIcon("mdal-delete_outline"));
|
||||
del.disableProperty().bind(entry.getDeletable().not());
|
||||
del.setOnAction(event -> entry.delete());
|
||||
del.disableProperty().bind(wrapper.getDeletable().not());
|
||||
del.setOnAction(event -> wrapper.delete());
|
||||
contextMenu.getItems().add(del);
|
||||
|
||||
return contextMenu;
|
||||
|
||||
@@ -5,12 +5,15 @@ import io.xpipe.app.comp.base.MultiContentComp;
|
||||
import io.xpipe.app.core.AppState;
|
||||
import io.xpipe.app.fxcomps.Comp;
|
||||
import io.xpipe.app.fxcomps.SimpleComp;
|
||||
import io.xpipe.app.fxcomps.impl.HorizontalComp;
|
||||
import io.xpipe.app.fxcomps.util.BindingsHelper;
|
||||
import javafx.beans.binding.Bindings;
|
||||
import javafx.beans.value.ObservableBooleanValue;
|
||||
import javafx.geometry.Insets;
|
||||
import javafx.scene.layout.Region;
|
||||
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
|
||||
public class StoreEntryListComp extends SimpleComp {
|
||||
|
||||
@@ -22,8 +25,9 @@ public class StoreEntryListComp extends SimpleComp {
|
||||
.getFilterString()
|
||||
.map(s -> (storeEntrySection -> storeEntrySection.shouldShow(s))));
|
||||
var content = new ListBoxViewComp<>(filtered, topLevel.getChildren(), (StoreSection e) -> {
|
||||
return StoreSection.customSection(e).styleClass("top");
|
||||
});
|
||||
var custom = StoreSection.customSection(e).hgrow();
|
||||
return new HorizontalComp(List.of(Comp.spacer(20), custom, Comp.spacer(20))).styleClass("top");
|
||||
}).apply(struc -> ((Region) struc.get().getContent()).setPadding(new Insets(20, 0, 20, 0)));
|
||||
return content.styleClass("store-list-comp");
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package io.xpipe.app.comp.storage.store;
|
||||
|
||||
import atlantafx.base.theme.Styles;
|
||||
import io.xpipe.app.comp.base.ListBoxViewComp;
|
||||
import io.xpipe.app.fxcomps.Comp;
|
||||
import io.xpipe.app.fxcomps.CompStructure;
|
||||
@@ -8,7 +9,9 @@ import io.xpipe.app.fxcomps.impl.HorizontalComp;
|
||||
import io.xpipe.app.fxcomps.impl.IconButtonComp;
|
||||
import io.xpipe.app.fxcomps.impl.VerticalComp;
|
||||
import io.xpipe.app.fxcomps.util.BindingsHelper;
|
||||
import io.xpipe.app.fxcomps.util.SimpleChangeListener;
|
||||
import javafx.beans.binding.Bindings;
|
||||
import javafx.css.PseudoClass;
|
||||
import javafx.scene.layout.*;
|
||||
import javafx.scene.paint.Color;
|
||||
|
||||
@@ -16,6 +19,8 @@ import java.util.List;
|
||||
|
||||
public class StoreEntrySectionComp extends Comp<CompStructure<VBox>> {
|
||||
|
||||
public static final PseudoClass EXPANDED = PseudoClass.getPseudoClass("expanded");
|
||||
|
||||
private final StoreSection section;
|
||||
|
||||
public StoreEntrySectionComp(StoreSection section) {
|
||||
@@ -61,15 +66,28 @@ public class StoreEntrySectionComp extends Comp<CompStructure<VBox>> {
|
||||
padding.setMaxWidth(25);
|
||||
return padding;
|
||||
});
|
||||
|
||||
var expanded = Bindings.createBooleanBinding(() -> {
|
||||
return section.getWrapper().getExpanded().get() && section.getChildren().size() > 0;
|
||||
}, section.getWrapper().getExpanded(), section.getChildren());
|
||||
|
||||
return new VerticalComp(List.of(
|
||||
new HorizontalComp(topEntryList)
|
||||
.apply(struc -> struc.get().setFillHeight(true)),
|
||||
Comp.separator().visible(expanded),
|
||||
new HorizontalComp(List.of(spacer, content))
|
||||
.apply(struc -> struc.get().setFillHeight(true))
|
||||
.hide(BindingsHelper.persist(Bindings.or(
|
||||
Bindings.not(section.getWrapper().getExpanded()),
|
||||
Bindings.size(section.getChildren()).isEqualTo(0))))))
|
||||
.styleClass("store-entry-section-comp")
|
||||
.styleClass(Styles.ELEVATED_1)
|
||||
.apply(struc -> {
|
||||
struc.get().setFillWidth(true);
|
||||
SimpleChangeListener.apply(expanded, val -> {
|
||||
struc.get().pseudoClassStateChanged(EXPANDED, val);
|
||||
});
|
||||
})
|
||||
.createStructure();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,6 +16,7 @@ public class StoreLayoutComp extends SimpleComp {
|
||||
var groupHeader = new StoreSidebarComp().createRegion();
|
||||
r.setLeft(groupHeader);
|
||||
r.setCenter(listR);
|
||||
r.getStyleClass().add("layout");
|
||||
return r;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package io.xpipe.app.comp.storage.store;
|
||||
|
||||
import atlantafx.base.theme.Styles;
|
||||
import io.xpipe.app.fxcomps.Comp;
|
||||
import io.xpipe.app.fxcomps.SimpleComp;
|
||||
import io.xpipe.app.fxcomps.impl.VerticalComp;
|
||||
@@ -13,8 +14,8 @@ public class StoreSidebarComp extends SimpleComp {
|
||||
@Override
|
||||
protected Region createSimple() {
|
||||
var sideBar = new VerticalComp(List.of(
|
||||
new StoreEntryListHeaderComp(),
|
||||
new StoreCreationBarComp(),
|
||||
new StoreEntryListHeaderComp().styleClass(Styles.ELEVATED_1),
|
||||
new StoreCreationBarComp().styleClass(Styles.ELEVATED_1),
|
||||
Comp.of(() -> new Region()).styleClass("bar").styleClass("filler-bar")));
|
||||
sideBar.apply(s -> VBox.setVgrow(s.get().getChildren().get(2), Priority.ALWAYS));
|
||||
sideBar.styleClass("sidebar");
|
||||
|
||||
@@ -12,8 +12,10 @@ import javafx.collections.FXCollections;
|
||||
import javafx.collections.ObservableList;
|
||||
|
||||
import java.time.Instant;
|
||||
import java.util.Arrays;
|
||||
import java.util.Comparator;
|
||||
import java.util.concurrent.CopyOnWriteArrayList;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class StoreViewState {
|
||||
|
||||
@@ -54,17 +56,19 @@ public class StoreViewState {
|
||||
|
||||
DataStorage.get().addListener(new StorageListener() {
|
||||
@Override
|
||||
public void onStoreAdd(DataStoreEntry entry) {
|
||||
public void onStoreAdd(DataStoreEntry... entry) {
|
||||
var l = Arrays.stream(entry).map(StoreEntryWrapper::new).toList();
|
||||
Platform.runLater(() -> {
|
||||
var sg = new StoreEntryWrapper(entry);
|
||||
allEntries.add(sg);
|
||||
allEntries.addAll(l);
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStoreRemove(DataStoreEntry entry) {
|
||||
public void onStoreRemove(DataStoreEntry... entry) {
|
||||
var a = Arrays.stream(entry).collect(Collectors.toSet());
|
||||
var l = StoreViewState.get().getAllEntries().stream().filter(storeEntryWrapper -> a.contains(storeEntryWrapper.getEntry())).toList();
|
||||
Platform.runLater(() -> {
|
||||
allEntries.removeIf(e -> e.getEntry().equals(entry));
|
||||
allEntries.removeAll(l);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
package io.xpipe.app.fxcomps;
|
||||
|
||||
import atlantafx.base.controls.Spacer;
|
||||
import io.xpipe.app.fxcomps.augment.Augment;
|
||||
import io.xpipe.app.fxcomps.augment.GrowAugment;
|
||||
import io.xpipe.app.fxcomps.impl.WrapperComp;
|
||||
import io.xpipe.app.fxcomps.util.Shortcuts;
|
||||
import io.xpipe.app.fxcomps.util.SimpleChangeListener;
|
||||
import javafx.beans.value.ObservableValue;
|
||||
import javafx.geometry.Insets;
|
||||
import javafx.geometry.Orientation;
|
||||
import javafx.scene.control.ButtonBase;
|
||||
import javafx.scene.control.Separator;
|
||||
import javafx.scene.control.Tooltip;
|
||||
@@ -26,19 +27,25 @@ public abstract class Comp<S extends CompStructure<?>> {
|
||||
|
||||
private List<Augment<S>> augments;
|
||||
|
||||
public static Comp<CompStructure<Region>> empty() {
|
||||
return of(() -> new Region());
|
||||
}
|
||||
|
||||
public static Comp<CompStructure<Spacer>> spacer(double size) {
|
||||
return of(() -> new Spacer(size));
|
||||
}
|
||||
|
||||
public static <R extends Region> Comp<CompStructure<R>> of(Supplier<R> r) {
|
||||
return new WrapperComp<>(() -> {
|
||||
var region = r.get();
|
||||
return () -> region;
|
||||
});
|
||||
return new Comp<>() {
|
||||
@Override
|
||||
public CompStructure<R> createBase() {
|
||||
return new SimpleCompStructure<>(r.get());
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public static Comp<CompStructure<Separator>> separator() {
|
||||
return Comp.of(() -> new Separator());
|
||||
}
|
||||
|
||||
public static <S extends CompStructure<?>> Comp<S> ofStructure(Supplier<S> r) {
|
||||
return new WrapperComp<>(r);
|
||||
return of(() -> new Separator(Orientation.HORIZONTAL));
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
|
||||
@@ -1,20 +0,0 @@
|
||||
package io.xpipe.app.fxcomps.impl;
|
||||
|
||||
import io.xpipe.app.fxcomps.Comp;
|
||||
import io.xpipe.app.fxcomps.CompStructure;
|
||||
|
||||
import java.util.function.Supplier;
|
||||
|
||||
public class WrapperComp<S extends CompStructure<?>> extends Comp<S> {
|
||||
|
||||
private final Supplier<S> structureSupplier;
|
||||
|
||||
public WrapperComp(Supplier<S> structureSupplier) {
|
||||
this.structureSupplier = structureSupplier;
|
||||
}
|
||||
|
||||
@Override
|
||||
public S createBase() {
|
||||
return structureSupplier.get();
|
||||
}
|
||||
}
|
||||
@@ -75,7 +75,10 @@ public abstract class DataStorage {
|
||||
try {
|
||||
deleteChildren(e, true);
|
||||
var newChildren = ((FixedHierarchyStore) e.getStore()).listChildren();
|
||||
newChildren.forEach((key, value) -> addStoreEntryIfNotPresent(key, value));
|
||||
addStoreEntries(newChildren.entrySet().stream()
|
||||
.map(stringDataStoreEntry -> DataStoreEntry.createNew(
|
||||
UUID.randomUUID(), stringDataStoreEntry.getKey(), stringDataStoreEntry.getValue()))
|
||||
.toArray(DataStoreEntry[]::new));
|
||||
return newChildren.size() > 0;
|
||||
} catch (Exception ex) {
|
||||
ErrorEvent.fromThrowable(ex).handle();
|
||||
@@ -88,12 +91,10 @@ public abstract class DataStorage {
|
||||
var ordered = getStoreChildren(e, false, deep);
|
||||
Collections.reverse(ordered);
|
||||
|
||||
ordered.forEach(entry -> {
|
||||
synchronized (this) {
|
||||
this.storeEntries.remove(entry);
|
||||
}
|
||||
this.listeners.forEach(l -> l.onStoreRemove(entry));
|
||||
});
|
||||
synchronized (this) {
|
||||
this.storeEntries.removeAll(ordered);
|
||||
this.listeners.forEach(l -> l.onStoreRemove(ordered.toArray(DataStoreEntry[]::new)));
|
||||
}
|
||||
save();
|
||||
}
|
||||
|
||||
@@ -103,22 +104,27 @@ public abstract class DataStorage {
|
||||
}
|
||||
|
||||
var provider = entry.getProvider();
|
||||
var parent = display ? provider.getDisplayParent(entry.getStore()) : provider.getLogicalParent(entry.getStore());
|
||||
var parent =
|
||||
display ? provider.getDisplayParent(entry.getStore()) : provider.getLogicalParent(entry.getStore());
|
||||
return parent != null ? getStoreEntryIfPresent(parent) : Optional.empty();
|
||||
}
|
||||
|
||||
public synchronized List<DataStoreEntry> getStoreChildren(DataStoreEntry entry, boolean display, boolean deep) {
|
||||
var children = new ArrayList<>(getStoreEntries().stream()
|
||||
.filter(other -> {
|
||||
if (!other.getState().isUsable()) {
|
||||
return false;
|
||||
}
|
||||
.filter(other -> {
|
||||
if (!other.getState().isUsable()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
var provider = other.getProvider();
|
||||
var parent = display ? provider.getDisplayParent(other.getStore()) : provider.getLogicalParent(other.getStore());
|
||||
return parent != null && entry.getStore().getClass().equals(parent.getClass()) && entry.getStore().equals(parent);
|
||||
})
|
||||
.toList());
|
||||
var provider = other.getProvider();
|
||||
var parent = display
|
||||
? provider.getDisplayParent(other.getStore())
|
||||
: provider.getLogicalParent(other.getStore());
|
||||
return parent != null
|
||||
&& entry.getStore().getClass().equals(parent.getClass())
|
||||
&& entry.getStore().equals(parent);
|
||||
})
|
||||
.toList());
|
||||
|
||||
if (deep) {
|
||||
for (DataStoreEntry dataStoreEntry : new ArrayList<>(children)) {
|
||||
@@ -179,7 +185,7 @@ public abstract class DataStorage {
|
||||
|
||||
public synchronized DataStoreEntry getStoreEntry(@NonNull DataStore store) {
|
||||
var entry = storeEntries.stream()
|
||||
.filter(n -> Objects.equals(store.getClass(), n.getStore().getClass()) && store.equals(n.getStore()))
|
||||
.filter(n -> n.getStore() != null && Objects.equals(store.getClass(), n.getStore().getClass()) && store.equals(n.getStore()))
|
||||
.findFirst()
|
||||
.orElseThrow(() -> new IllegalArgumentException("Store not found"));
|
||||
return entry;
|
||||
@@ -242,6 +248,18 @@ public abstract class DataStorage {
|
||||
this.listeners.forEach(l -> l.onStoreAdd(e));
|
||||
}
|
||||
|
||||
public void addStoreEntries(@NonNull DataStoreEntry... es) {
|
||||
synchronized (this) {
|
||||
for (DataStoreEntry e : es) {
|
||||
e.setDirectory(getStoresDir().resolve(e.getUuid().toString()));
|
||||
this.storeEntries.add(e);
|
||||
propagateUpdate(e);
|
||||
}
|
||||
this.listeners.forEach(l -> l.onStoreAdd(es));
|
||||
}
|
||||
save();
|
||||
}
|
||||
|
||||
public DataStoreEntry addStoreEntryIfNotPresent(@NonNull String name, DataStore store) {
|
||||
var found = getStoreEntryIfPresent(store);
|
||||
if (found.isPresent()) {
|
||||
|
||||
@@ -2,7 +2,7 @@ package io.xpipe.app.storage;
|
||||
|
||||
public interface StorageListener {
|
||||
|
||||
void onStoreAdd(DataStoreEntry entry);
|
||||
void onStoreAdd(DataStoreEntry... entry);
|
||||
|
||||
void onStoreRemove(DataStoreEntry entry);
|
||||
void onStoreRemove(DataStoreEntry... entry);
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
.bar {
|
||||
-fx-padding: 0.8em 1.0em 0.8em 1.0em;
|
||||
-fx-background-color: -color-neutral-subtle;
|
||||
-fx-background-color: -color-bg-subtle;
|
||||
-fx-border-color: -color-neutral-emphasis;
|
||||
}
|
||||
|
||||
|
||||
@@ -24,21 +24,29 @@
|
||||
}
|
||||
|
||||
.store-entry-grid {
|
||||
-fx-padding: 6px 6px 6px 0;
|
||||
-fx-padding: 6px 6px 6px 6px;
|
||||
}
|
||||
|
||||
.store-entry-grid.dense {
|
||||
-fx-padding: 1px 6px 1px 0;
|
||||
-fx-padding: 1px 6px 1px 6px;
|
||||
}
|
||||
|
||||
.store-entry-section-comp.top {
|
||||
.store-list-comp .top {
|
||||
-fx-border-width: 0 0 1em 0;
|
||||
-fx-background-insets: 0 0 1em 0;
|
||||
-fx-border-color: transparent;
|
||||
}
|
||||
|
||||
.store-entry-section-comp.top:odd {
|
||||
-fx-background-color: -color-neutral-subtle;
|
||||
.store-list-comp .top:odd .store-entry-section-comp {
|
||||
-fx-background-color: -color-bg-subtle;
|
||||
}
|
||||
|
||||
.store-list-comp .top:even .store-entry-section-comp {
|
||||
-fx-background-color: -color-bg-overlay;
|
||||
}
|
||||
|
||||
.store-list-comp .store-entry-section-comp {
|
||||
-fx-background-color: -color-bg-default;
|
||||
}
|
||||
|
||||
.store-entry-comp:hover {
|
||||
@@ -50,10 +58,26 @@
|
||||
}
|
||||
|
||||
.store-entry-comp .button-bar .button {
|
||||
-fx-padding: 8px;
|
||||
-fx-background-insets: 0;
|
||||
-fx-padding: 6px;
|
||||
}
|
||||
|
||||
.store-entry-section-comp .separator {
|
||||
-fx-padding: 0 0.5em 0 0.5em;
|
||||
-fx-border-insets: 0px;
|
||||
}
|
||||
|
||||
.store-entry-section-comp .separator .line {
|
||||
-fx-padding: 0;
|
||||
-fx-border-insets: 0px;
|
||||
}
|
||||
|
||||
.store-entry-section-comp * {
|
||||
-fx-spacing: 0.5em;
|
||||
}
|
||||
|
||||
.store-entry-section-comp:expanded {
|
||||
-fx-background-color: -color-bg-default;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -13,6 +13,10 @@
|
||||
-fx-padding: 1.2em;
|
||||
}
|
||||
|
||||
.layout {
|
||||
-fx-background-color: -color-bg-default;
|
||||
}
|
||||
|
||||
.text {
|
||||
-fx-font-smoothing-type: gray;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user