mirror of
https://github.com/xpipe-io/xpipe.git
synced 2024-11-22 07:30:24 +00:00
Rework wsl and k8s system
This commit is contained in:
parent
0b6aee858c
commit
9321af9998
26 changed files with 711 additions and 175 deletions
|
@ -7,6 +7,7 @@ import io.xpipe.app.fxcomps.SimpleCompStructure;
|
||||||
import io.xpipe.app.fxcomps.util.PlatformThread;
|
import io.xpipe.app.fxcomps.util.PlatformThread;
|
||||||
import io.xpipe.app.util.ThreadHelper;
|
import io.xpipe.app.util.ThreadHelper;
|
||||||
import javafx.application.Platform;
|
import javafx.application.Platform;
|
||||||
|
import javafx.beans.binding.Bindings;
|
||||||
import javafx.beans.value.ChangeListener;
|
import javafx.beans.value.ChangeListener;
|
||||||
import javafx.beans.value.ObservableValue;
|
import javafx.beans.value.ObservableValue;
|
||||||
import javafx.scene.layout.StackPane;
|
import javafx.scene.layout.StackPane;
|
||||||
|
@ -27,8 +28,6 @@ public class LoadingOverlayComp extends Comp<CompStructure<StackPane>> {
|
||||||
|
|
||||||
var loading = new RingProgressIndicator(0, false);
|
var loading = new RingProgressIndicator(0, false);
|
||||||
loading.setProgress(-1);
|
loading.setProgress(-1);
|
||||||
loading.setPrefWidth(50);
|
|
||||||
loading.setPrefHeight(50);
|
|
||||||
|
|
||||||
var loadingBg = new StackPane(loading);
|
var loadingBg = new StackPane(loading);
|
||||||
loadingBg.getStyleClass().add("loading-comp");
|
loadingBg.getStyleClass().add("loading-comp");
|
||||||
|
@ -69,7 +68,14 @@ public class LoadingOverlayComp extends Comp<CompStructure<StackPane>> {
|
||||||
};
|
};
|
||||||
PlatformThread.sync(showLoading).addListener(listener);
|
PlatformThread.sync(showLoading).addListener(listener);
|
||||||
|
|
||||||
var stack = new StackPane(compStruc.get(), loadingBg);
|
var r = compStruc.get();
|
||||||
|
var stack = new StackPane(r, loadingBg);
|
||||||
|
|
||||||
|
loading.prefWidthProperty().bind(Bindings.createDoubleBinding(() -> {
|
||||||
|
return Math.min(r.getHeight() - 20, 50);
|
||||||
|
}, r.heightProperty()));
|
||||||
|
loading.prefHeightProperty().bind(loading.prefWidthProperty());
|
||||||
|
|
||||||
return new SimpleCompStructure<>(stack);
|
return new SimpleCompStructure<>(stack);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,35 @@
|
||||||
|
package io.xpipe.app.comp.base;
|
||||||
|
|
||||||
|
import atlantafx.base.controls.ToggleSwitch;
|
||||||
|
import io.xpipe.app.fxcomps.SimpleComp;
|
||||||
|
import io.xpipe.app.fxcomps.util.PlatformThread;
|
||||||
|
import javafx.beans.property.BooleanProperty;
|
||||||
|
import javafx.beans.value.ObservableValue;
|
||||||
|
import javafx.scene.layout.Region;
|
||||||
|
|
||||||
|
public class NamedToggleComp extends SimpleComp {
|
||||||
|
|
||||||
|
private final BooleanProperty selected;
|
||||||
|
private final ObservableValue<String> name;
|
||||||
|
|
||||||
|
public NamedToggleComp(BooleanProperty selected, ObservableValue<String> name) {
|
||||||
|
this.selected = selected;
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Region createSimple() {
|
||||||
|
var s = new ToggleSwitch();
|
||||||
|
s.setSelected(selected.getValue());
|
||||||
|
s.selectedProperty().addListener((observable, oldValue, newValue) -> {
|
||||||
|
selected.set(newValue);
|
||||||
|
});
|
||||||
|
selected.addListener((observable, oldValue, newValue) -> {
|
||||||
|
PlatformThread.runLaterIfNeeded(() -> {
|
||||||
|
s.setSelected(newValue);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
s.textProperty().bind(PlatformThread.sync(name));
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
}
|
|
@ -50,7 +50,7 @@ public class DsStoreProviderChoiceComp extends Comp<CompStructure<ComboBox<Node>
|
||||||
var comboBox = new CustomComboBoxBuilder<>(provider, this::createGraphic, createDefaultNode(), v -> true);
|
var comboBox = new CustomComboBoxBuilder<>(provider, this::createGraphic, createDefaultNode(), v -> true);
|
||||||
comboBox.setAccessibleNames(dataStoreProvider -> dataStoreProvider.getDisplayName());
|
comboBox.setAccessibleNames(dataStoreProvider -> dataStoreProvider.getDisplayName());
|
||||||
getProviders().stream()
|
getProviders().stream()
|
||||||
.filter(p -> AppPrefs.get().developerShowHiddenProviders().get() || p.shouldShow())
|
.filter(p -> AppPrefs.get().developerShowHiddenProviders().get() || p.canManuallyCreate())
|
||||||
.forEach(comboBox::add);
|
.forEach(comboBox::add);
|
||||||
ComboBox<Node> cb = comboBox.build();
|
ComboBox<Node> cb = comboBox.build();
|
||||||
cb.getStyleClass().add("data-source-type");
|
cb.getStyleClass().add("data-source-type");
|
||||||
|
|
|
@ -7,7 +7,6 @@ import io.xpipe.app.fxcomps.augment.ContextMenuAugment;
|
||||||
import io.xpipe.app.issue.ErrorEvent;
|
import io.xpipe.app.issue.ErrorEvent;
|
||||||
import io.xpipe.app.prefs.AppPrefs;
|
import io.xpipe.app.prefs.AppPrefs;
|
||||||
import io.xpipe.app.storage.DataSourceEntry;
|
import io.xpipe.app.storage.DataSourceEntry;
|
||||||
import io.xpipe.app.storage.DataStorage;
|
|
||||||
import io.xpipe.app.util.DesktopHelper;
|
import io.xpipe.app.util.DesktopHelper;
|
||||||
import javafx.beans.binding.Bindings;
|
import javafx.beans.binding.Bindings;
|
||||||
import javafx.scene.control.ContextMenu;
|
import javafx.scene.control.ContextMenu;
|
||||||
|
@ -63,7 +62,6 @@ public class SourceEntryContextMenu<S extends CompStructure<?>> extends ContextM
|
||||||
|
|
||||||
var validate = new MenuItem(AppI18n.get("refresh"), new FontIcon("mdal-360"));
|
var validate = new MenuItem(AppI18n.get("refresh"), new FontIcon("mdal-360"));
|
||||||
validate.setOnAction(event -> {
|
validate.setOnAction(event -> {
|
||||||
DataStorage.get().refreshAsync(entry.getEntry(), true);
|
|
||||||
});
|
});
|
||||||
cm.getItems().add(validate);
|
cm.getItems().add(validate);
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,109 @@
|
||||||
|
package io.xpipe.app.comp.storage.store;
|
||||||
|
|
||||||
|
import atlantafx.base.controls.Spacer;
|
||||||
|
import com.jfoenix.controls.JFXButton;
|
||||||
|
import io.xpipe.app.comp.base.LoadingOverlayComp;
|
||||||
|
import io.xpipe.app.core.AppFont;
|
||||||
|
import io.xpipe.app.core.AppI18n;
|
||||||
|
import io.xpipe.app.fxcomps.Comp;
|
||||||
|
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.util.PlatformThread;
|
||||||
|
import io.xpipe.app.util.ThreadHelper;
|
||||||
|
import javafx.beans.binding.Bindings;
|
||||||
|
import javafx.geometry.HPos;
|
||||||
|
import javafx.scene.control.Label;
|
||||||
|
import javafx.scene.layout.*;
|
||||||
|
import lombok.SneakyThrows;
|
||||||
|
|
||||||
|
public class DenseStoreEntryComp extends StoreEntryComp {
|
||||||
|
|
||||||
|
private final boolean showIcon;
|
||||||
|
private final Comp<?> content;
|
||||||
|
|
||||||
|
public DenseStoreEntryComp(StoreEntryWrapper entry, boolean showIcon, Comp<?> content) {
|
||||||
|
super(entry);
|
||||||
|
this.showIcon = showIcon;
|
||||||
|
this.content = content;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected Region createContent() {
|
||||||
|
var name = createName().createRegion();
|
||||||
|
|
||||||
|
var size = createInformation();
|
||||||
|
|
||||||
|
var date = new Label();
|
||||||
|
date.textProperty().bind(AppI18n.readableDuration("usedDate", PlatformThread.sync(entry.lastAccessProperty())));
|
||||||
|
AppFont.small(date);
|
||||||
|
date.getStyleClass().add("date");
|
||||||
|
|
||||||
|
var grid = new GridPane();
|
||||||
|
|
||||||
|
if (showIcon) {
|
||||||
|
var storeIcon = createIcon(30, 25);
|
||||||
|
grid.getColumnConstraints().add(new ColumnConstraints(45));
|
||||||
|
grid.add(storeIcon, 0, 0);
|
||||||
|
GridPane.setHalignment(storeIcon, HPos.CENTER);
|
||||||
|
} else {
|
||||||
|
grid.add(new Region(), 0, 0);
|
||||||
|
grid.getColumnConstraints().add(new ColumnConstraints(5));
|
||||||
|
}
|
||||||
|
|
||||||
|
var fill = new ColumnConstraints();
|
||||||
|
fill.setHgrow(Priority.ALWAYS);
|
||||||
|
grid.getColumnConstraints().addAll(new ColumnConstraints(450), fill);
|
||||||
|
|
||||||
|
grid.add(name, 1, 0);
|
||||||
|
|
||||||
|
var c = content != null ? content.createRegion() : new Region();
|
||||||
|
grid.add(c, 2, 0);
|
||||||
|
GridPane.setHalignment(c, HPos.CENTER);
|
||||||
|
|
||||||
|
grid.add(createButtonBar().createRegion(), 3, 0, 1, 1);
|
||||||
|
GrowAugment.create(true, false).augment(grid);
|
||||||
|
|
||||||
|
AppFont.small(size);
|
||||||
|
AppFont.small(date);
|
||||||
|
|
||||||
|
grid.getStyleClass().add("store-entry-grid");
|
||||||
|
|
||||||
|
applyState(grid);
|
||||||
|
|
||||||
|
var button = new JFXButton();
|
||||||
|
button.setGraphic(grid);
|
||||||
|
GrowAugment.create(true, false).augment(new SimpleCompStructure<>(grid));
|
||||||
|
button.getStyleClass().add("store-entry-comp");
|
||||||
|
button.getStyleClass().add("condensed-store-entry-comp");
|
||||||
|
button.setMaxWidth(2000);
|
||||||
|
button.setFocusTraversable(true);
|
||||||
|
button.accessibleTextProperty()
|
||||||
|
.bind(Bindings.createStringBinding(
|
||||||
|
() -> {
|
||||||
|
return entry.getName();
|
||||||
|
},
|
||||||
|
entry.nameProperty()));
|
||||||
|
button.accessibleHelpProperty().bind(entry.getInformation());
|
||||||
|
button.setOnAction(event -> {
|
||||||
|
event.consume();
|
||||||
|
ThreadHelper.runFailableAsync(() -> {
|
||||||
|
entry.refreshIfNeeded();
|
||||||
|
entry.executeDefaultAction();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
HBox.setHgrow(button, Priority.ALWAYS);
|
||||||
|
|
||||||
|
new ContextMenuAugment<>(() -> DenseStoreEntryComp.this.createContextMenu())
|
||||||
|
.augment(new SimpleCompStructure<>(button));
|
||||||
|
|
||||||
|
return new HBox(button, new Spacer(25));
|
||||||
|
}
|
||||||
|
|
||||||
|
@SneakyThrows
|
||||||
|
@Override
|
||||||
|
protected Region createSimple() {
|
||||||
|
var loading = new LoadingOverlayComp(Comp.of(() -> createContent()), entry.getLoading());
|
||||||
|
var region = loading.createRegion();
|
||||||
|
return region;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,304 @@
|
||||||
|
package io.xpipe.app.comp.storage.store;
|
||||||
|
|
||||||
|
import com.jfoenix.controls.JFXButton;
|
||||||
|
import io.xpipe.app.comp.base.LoadingOverlayComp;
|
||||||
|
import io.xpipe.app.core.AppFont;
|
||||||
|
import io.xpipe.app.core.AppI18n;
|
||||||
|
import io.xpipe.app.ext.ActionProvider;
|
||||||
|
import io.xpipe.app.fxcomps.Comp;
|
||||||
|
import io.xpipe.app.fxcomps.SimpleComp;
|
||||||
|
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.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 javafx.beans.binding.Bindings;
|
||||||
|
import javafx.beans.property.SimpleStringProperty;
|
||||||
|
import javafx.css.PseudoClass;
|
||||||
|
import javafx.geometry.HPos;
|
||||||
|
import javafx.geometry.Insets;
|
||||||
|
import javafx.geometry.Pos;
|
||||||
|
import javafx.scene.Node;
|
||||||
|
import javafx.scene.control.*;
|
||||||
|
import javafx.scene.input.MouseButton;
|
||||||
|
import javafx.scene.layout.ColumnConstraints;
|
||||||
|
import javafx.scene.layout.GridPane;
|
||||||
|
import javafx.scene.layout.Region;
|
||||||
|
import lombok.SneakyThrows;
|
||||||
|
import org.kordamp.ikonli.javafx.FontIcon;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
|
||||||
|
public class StandardStoreEntryComp extends SimpleComp {
|
||||||
|
|
||||||
|
public static Comp<?> customSection(StoreEntryWrapper e) {
|
||||||
|
var prov = e.getEntry().getProvider();
|
||||||
|
if (prov != null) {
|
||||||
|
return prov.customDisplay(e);
|
||||||
|
} else {
|
||||||
|
return new StandardStoreEntryComp(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final double NAME_WIDTH = 0.30;
|
||||||
|
private static final double STORE_TYPE_WIDTH = 0.08;
|
||||||
|
private static final double DETAILS_WIDTH = 0.52;
|
||||||
|
private static final double BUTTONS_WIDTH = 0.1;
|
||||||
|
private static final PseudoClass FAILED = PseudoClass.getPseudoClass("failed");
|
||||||
|
private static final PseudoClass INCOMPLETE = PseudoClass.getPseudoClass("incomplete");
|
||||||
|
private final StoreEntryWrapper entry;
|
||||||
|
|
||||||
|
public StandardStoreEntryComp(StoreEntryWrapper entry) {
|
||||||
|
this.entry = entry;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Label createInformation() {
|
||||||
|
var information = new Label();
|
||||||
|
information.textProperty().bind(PlatformThread.sync(entry.getInformation()));
|
||||||
|
information.getStyleClass().add("information");
|
||||||
|
AppFont.header(information);
|
||||||
|
return information;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Label createSummary() {
|
||||||
|
var summary = new Label();
|
||||||
|
summary.textProperty().bind(PlatformThread.sync(entry.getSummary()));
|
||||||
|
summary.getStyleClass().add("summary");
|
||||||
|
AppFont.small(summary);
|
||||||
|
return summary;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void applyState(Node node) {
|
||||||
|
SimpleChangeListener.apply(PlatformThread.sync(entry.getState()), val -> {
|
||||||
|
switch (val) {
|
||||||
|
case LOAD_FAILED -> {
|
||||||
|
node.pseudoClassStateChanged(FAILED, true);
|
||||||
|
node.pseudoClassStateChanged(INCOMPLETE, false);
|
||||||
|
}
|
||||||
|
case INCOMPLETE -> {
|
||||||
|
node.pseudoClassStateChanged(FAILED, false);
|
||||||
|
node.pseudoClassStateChanged(INCOMPLETE, true);
|
||||||
|
}
|
||||||
|
default -> {
|
||||||
|
node.pseudoClassStateChanged(FAILED, false);
|
||||||
|
node.pseudoClassStateChanged(INCOMPLETE, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private Comp<?> createName() {
|
||||||
|
var name = new LabelComp(entry.nameProperty())
|
||||||
|
.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()));
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Node createIcon() {
|
||||||
|
var img = entry.isDisabled()
|
||||||
|
? "disabled_icon.png"
|
||||||
|
: entry.getEntry()
|
||||||
|
.getProvider()
|
||||||
|
.getDisplayIconFileName(entry.getEntry().getStore());
|
||||||
|
var imageComp = new PrettyImageComp(new SimpleStringProperty(img), 55, 45);
|
||||||
|
var storeIcon = imageComp.createRegion();
|
||||||
|
storeIcon.getStyleClass().add("icon");
|
||||||
|
if (entry.getState().getValue().isUsable()) {
|
||||||
|
new FancyTooltipAugment<>(new SimpleStringProperty(
|
||||||
|
entry.getEntry().getProvider().getDisplayName()))
|
||||||
|
.augment(storeIcon);
|
||||||
|
}
|
||||||
|
return storeIcon;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected Region createContent() {
|
||||||
|
var name = createName().createRegion();
|
||||||
|
|
||||||
|
var size = createInformation();
|
||||||
|
|
||||||
|
var date = new Label();
|
||||||
|
date.textProperty().bind(AppI18n.readableDuration("usedDate", PlatformThread.sync(entry.lastAccessProperty())));
|
||||||
|
AppFont.small(date);
|
||||||
|
date.getStyleClass().add("date");
|
||||||
|
|
||||||
|
var grid = new GridPane();
|
||||||
|
|
||||||
|
var storeIcon = createIcon();
|
||||||
|
|
||||||
|
grid.getColumnConstraints()
|
||||||
|
.addAll(
|
||||||
|
createShareConstraint(grid, STORE_TYPE_WIDTH), createShareConstraint(grid, NAME_WIDTH),
|
||||||
|
createShareConstraint(grid, DETAILS_WIDTH), createShareConstraint(grid, BUTTONS_WIDTH));
|
||||||
|
grid.add(storeIcon, 0, 0, 1, 2);
|
||||||
|
grid.add(name, 1, 0);
|
||||||
|
grid.add(date, 1, 1);
|
||||||
|
grid.add(createSummary(), 2, 1);
|
||||||
|
grid.add(createInformation(), 2, 0);
|
||||||
|
grid.add(createButtonBar().createRegion(), 3, 0, 1, 2);
|
||||||
|
grid.setVgap(5);
|
||||||
|
GridPane.setHalignment(storeIcon, HPos.CENTER);
|
||||||
|
|
||||||
|
AppFont.small(size);
|
||||||
|
AppFont.small(date);
|
||||||
|
|
||||||
|
grid.getStyleClass().add("store-entry-grid");
|
||||||
|
|
||||||
|
applyState(grid);
|
||||||
|
|
||||||
|
var button = new JFXButton();
|
||||||
|
button.setGraphic(grid);
|
||||||
|
GrowAugment.create(true, false).augment(new SimpleCompStructure<>(grid));
|
||||||
|
button.getStyleClass().add("store-entry-comp");
|
||||||
|
button.setMaxWidth(2000);
|
||||||
|
button.setFocusTraversable(true);
|
||||||
|
button.accessibleTextProperty()
|
||||||
|
.bind(Bindings.createStringBinding(
|
||||||
|
() -> {
|
||||||
|
return entry.getName();
|
||||||
|
},
|
||||||
|
entry.nameProperty()));
|
||||||
|
button.accessibleHelpProperty().bind(entry.getInformation());
|
||||||
|
button.setOnAction(event -> {
|
||||||
|
event.consume();
|
||||||
|
ThreadHelper.runFailableAsync(() -> {
|
||||||
|
entry.refreshIfNeeded();
|
||||||
|
entry.executeDefaultAction();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
new ContextMenuAugment<>(() -> StandardStoreEntryComp.this.createContextMenu())
|
||||||
|
.augment(new SimpleCompStructure<>(button));
|
||||||
|
|
||||||
|
return button;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected Comp<?> createButtonBar() {
|
||||||
|
var list = new ArrayList<Comp<?>>();
|
||||||
|
for (var p : entry.getActionProviders().entrySet()) {
|
||||||
|
var actionProvider = p.getKey().getDataStoreCallSite();
|
||||||
|
if (!actionProvider.isMajor()
|
||||||
|
|| p.getKey().equals(entry.getDefaultActionProvider().getValue())) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
var button = new IconButtonComp(
|
||||||
|
actionProvider.getIcon(entry.getEntry().getStore().asNeeded()), () -> {
|
||||||
|
ThreadHelper.runFailableAsync(() -> {
|
||||||
|
var action = actionProvider.createAction(
|
||||||
|
entry.getEntry().getStore().asNeeded());
|
||||||
|
action.execute();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
button.apply(new FancyTooltipAugment<>(
|
||||||
|
actionProvider.getName(entry.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) {
|
||||||
|
button.disable(Bindings.not(p.getValue()));
|
||||||
|
}
|
||||||
|
list.add(button);
|
||||||
|
}
|
||||||
|
|
||||||
|
var settingsButton = createSettingsButton();
|
||||||
|
list.add(settingsButton);
|
||||||
|
return new HorizontalComp(list)
|
||||||
|
.apply(struc -> struc.get().setAlignment(Pos.CENTER_RIGHT))
|
||||||
|
.apply(struc -> {
|
||||||
|
for (Node child : struc.get().getChildren()) {
|
||||||
|
((Region) child)
|
||||||
|
.prefWidthProperty()
|
||||||
|
.bind((struc.get().heightProperty().divide(1.7)));
|
||||||
|
((Region) child).prefHeightProperty().bind((struc.get().heightProperty()));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
protected Comp<?> createSettingsButton() {
|
||||||
|
var settingsButton = new IconButtonComp("mdomz-settings");
|
||||||
|
settingsButton.styleClass("settings");
|
||||||
|
settingsButton.accessibleText("Settings");
|
||||||
|
settingsButton.apply(new ContextMenuAugment<>(
|
||||||
|
event -> event.getButton() == MouseButton.PRIMARY, () -> StandardStoreEntryComp.this.createContextMenu()));
|
||||||
|
settingsButton.apply(GrowAugment.create(false, true));
|
||||||
|
settingsButton.apply(s -> {
|
||||||
|
s.get().prefWidthProperty().bind(Bindings.divide(s.get().heightProperty(), 1.35));
|
||||||
|
});
|
||||||
|
settingsButton.apply(new FancyTooltipAugment<>("more"));
|
||||||
|
return settingsButton;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected ContextMenu createContextMenu() {
|
||||||
|
var contextMenu = new ContextMenu();
|
||||||
|
AppFont.normal(contextMenu.getStyleableNode());
|
||||||
|
|
||||||
|
for (var p : entry.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 item = new MenuItem(null, new FontIcon(icon));
|
||||||
|
item.setOnAction(event -> {
|
||||||
|
ThreadHelper.runFailableAsync(() -> {
|
||||||
|
var action = actionProvider.createAction(
|
||||||
|
entry.getEntry().getStore().asNeeded());
|
||||||
|
action.execute();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
item.textProperty().bind(name);
|
||||||
|
if (actionProvider.activeType() == ActionProvider.DataStoreCallSite.ActiveType.ONLY_SHOW_IF_ENABLED) {
|
||||||
|
item.visibleProperty().bind(p.getValue());
|
||||||
|
} else if (actionProvider.activeType() == ActionProvider.DataStoreCallSite.ActiveType.ALWAYS_SHOW) {
|
||||||
|
item.disableProperty().bind(Bindings.not(p.getValue()));
|
||||||
|
}
|
||||||
|
contextMenu.getItems().add(item);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (entry.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()));
|
||||||
|
contextMenu.getItems().add(browse);
|
||||||
|
}
|
||||||
|
|
||||||
|
var refresh = new MenuItem(AppI18n.get("refresh"), new FontIcon("mdal-360"));
|
||||||
|
refresh.disableProperty().bind(entry.getRefreshable().not());
|
||||||
|
refresh.setOnAction(event -> {
|
||||||
|
DataStorage.get().refreshAsync(entry.getEntry(), true);
|
||||||
|
});
|
||||||
|
contextMenu.getItems().add(refresh);
|
||||||
|
|
||||||
|
var del = new MenuItem(AppI18n.get("delete"), new FontIcon("mdal-delete_outline"));
|
||||||
|
del.disableProperty().bind(entry.getDeletable().not());
|
||||||
|
del.setOnAction(event -> entry.delete());
|
||||||
|
contextMenu.getItems().add(del);
|
||||||
|
|
||||||
|
return contextMenu;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected ColumnConstraints createShareConstraint(Region r, double share) {
|
||||||
|
var cc = new ColumnConstraints();
|
||||||
|
cc.prefWidthProperty().bind(Bindings.createDoubleBinding(() -> r.getWidth() * share, r.widthProperty()));
|
||||||
|
return cc;
|
||||||
|
}
|
||||||
|
|
||||||
|
@SneakyThrows
|
||||||
|
@Override
|
||||||
|
protected Region createSimple() {
|
||||||
|
var loading = new LoadingOverlayComp(Comp.of(() -> createContent()), entry.getLoading());
|
||||||
|
var region = loading.createRegion();
|
||||||
|
return region;
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,54 +1,59 @@
|
||||||
package io.xpipe.app.comp.storage.store;
|
package io.xpipe.app.comp.storage.store;
|
||||||
|
|
||||||
import com.jfoenix.controls.JFXButton;
|
import atlantafx.base.theme.Styles;
|
||||||
import io.xpipe.app.comp.base.LoadingOverlayComp;
|
|
||||||
import io.xpipe.app.core.AppFont;
|
import io.xpipe.app.core.AppFont;
|
||||||
import io.xpipe.app.core.AppI18n;
|
import io.xpipe.app.core.AppI18n;
|
||||||
import io.xpipe.app.ext.ActionProvider;
|
import io.xpipe.app.ext.ActionProvider;
|
||||||
import io.xpipe.app.fxcomps.Comp;
|
import io.xpipe.app.fxcomps.Comp;
|
||||||
import io.xpipe.app.fxcomps.SimpleComp;
|
import io.xpipe.app.fxcomps.SimpleComp;
|
||||||
import io.xpipe.app.fxcomps.SimpleCompStructure;
|
|
||||||
import io.xpipe.app.fxcomps.augment.ContextMenuAugment;
|
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.impl.*;
|
||||||
|
import io.xpipe.app.fxcomps.util.BindingsHelper;
|
||||||
import io.xpipe.app.fxcomps.util.PlatformThread;
|
import io.xpipe.app.fxcomps.util.PlatformThread;
|
||||||
import io.xpipe.app.fxcomps.util.SimpleChangeListener;
|
import io.xpipe.app.fxcomps.util.SimpleChangeListener;
|
||||||
import io.xpipe.app.prefs.AppPrefs;
|
import io.xpipe.app.prefs.AppPrefs;
|
||||||
import io.xpipe.app.storage.DataStorage;
|
import io.xpipe.app.storage.DataStorage;
|
||||||
import io.xpipe.app.util.DesktopHelper;
|
import io.xpipe.app.util.DesktopHelper;
|
||||||
import io.xpipe.app.util.ThreadHelper;
|
import io.xpipe.app.util.ThreadHelper;
|
||||||
|
import io.xpipe.core.store.FixedHierarchyStore;
|
||||||
import javafx.beans.binding.Bindings;
|
import javafx.beans.binding.Bindings;
|
||||||
import javafx.beans.property.SimpleStringProperty;
|
import javafx.beans.property.SimpleStringProperty;
|
||||||
import javafx.css.PseudoClass;
|
import javafx.css.PseudoClass;
|
||||||
import javafx.geometry.HPos;
|
|
||||||
import javafx.geometry.Insets;
|
import javafx.geometry.Insets;
|
||||||
import javafx.geometry.Pos;
|
import javafx.geometry.Pos;
|
||||||
import javafx.scene.Node;
|
import javafx.scene.Node;
|
||||||
import javafx.scene.control.*;
|
import javafx.scene.control.*;
|
||||||
import javafx.scene.input.MouseButton;
|
import javafx.scene.input.MouseButton;
|
||||||
import javafx.scene.layout.ColumnConstraints;
|
import javafx.scene.layout.ColumnConstraints;
|
||||||
import javafx.scene.layout.GridPane;
|
|
||||||
import javafx.scene.layout.Region;
|
import javafx.scene.layout.Region;
|
||||||
import lombok.SneakyThrows;
|
|
||||||
import org.kordamp.ikonli.javafx.FontIcon;
|
import org.kordamp.ikonli.javafx.FontIcon;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
|
||||||
public class StoreEntryComp extends SimpleComp {
|
public abstract class StoreEntryComp extends SimpleComp {
|
||||||
|
|
||||||
private static final double NAME_WIDTH = 0.30;
|
public static Comp<?> customSection(StoreEntryWrapper e) {
|
||||||
private static final double STORE_TYPE_WIDTH = 0.08;
|
var prov = e.getEntry().getProvider();
|
||||||
private static final double DETAILS_WIDTH = 0.52;
|
if (prov != null) {
|
||||||
private static final double BUTTONS_WIDTH = 0.1;
|
return prov.customDisplay(e);
|
||||||
private static final PseudoClass FAILED = PseudoClass.getPseudoClass("failed");
|
} else {
|
||||||
private static final PseudoClass INCOMPLETE = PseudoClass.getPseudoClass("incomplete");
|
return new StandardStoreEntryComp(e);
|
||||||
private final StoreEntryWrapper entry;
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static final double NAME_WIDTH = 0.30;
|
||||||
|
public static final double STORE_TYPE_WIDTH = 0.08;
|
||||||
|
public static final double DETAILS_WIDTH = 0.52;
|
||||||
|
public static final double BUTTONS_WIDTH = 0.1;
|
||||||
|
public static final PseudoClass FAILED = PseudoClass.getPseudoClass("failed");
|
||||||
|
public static final PseudoClass INCOMPLETE = PseudoClass.getPseudoClass("incomplete");
|
||||||
|
protected final StoreEntryWrapper entry;
|
||||||
|
|
||||||
public StoreEntryComp(StoreEntryWrapper entry) {
|
public StoreEntryComp(StoreEntryWrapper entry) {
|
||||||
this.entry = entry;
|
this.entry = entry;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Label createInformation() {
|
protected Label createInformation() {
|
||||||
var information = new Label();
|
var information = new Label();
|
||||||
information.textProperty().bind(PlatformThread.sync(entry.getInformation()));
|
information.textProperty().bind(PlatformThread.sync(entry.getInformation()));
|
||||||
information.getStyleClass().add("information");
|
information.getStyleClass().add("information");
|
||||||
|
@ -56,7 +61,7 @@ public class StoreEntryComp extends SimpleComp {
|
||||||
return information;
|
return information;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Label createSummary() {
|
protected Label createSummary() {
|
||||||
var summary = new Label();
|
var summary = new Label();
|
||||||
summary.textProperty().bind(PlatformThread.sync(entry.getSummary()));
|
summary.textProperty().bind(PlatformThread.sync(entry.getSummary()));
|
||||||
summary.getStyleClass().add("summary");
|
summary.getStyleClass().add("summary");
|
||||||
|
@ -64,7 +69,7 @@ public class StoreEntryComp extends SimpleComp {
|
||||||
return summary;
|
return summary;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void applyState(Node node) {
|
protected void applyState(Node node) {
|
||||||
SimpleChangeListener.apply(PlatformThread.sync(entry.getState()), val -> {
|
SimpleChangeListener.apply(PlatformThread.sync(entry.getState()), val -> {
|
||||||
switch (val) {
|
switch (val) {
|
||||||
case LOAD_FAILED -> {
|
case LOAD_FAILED -> {
|
||||||
|
@ -83,21 +88,41 @@ public class StoreEntryComp extends SimpleComp {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private Comp<?> createName() {
|
protected Comp<?> createName() {
|
||||||
var name = new LabelComp(entry.nameProperty())
|
var filtered = BindingsHelper.filteredContentBinding(
|
||||||
.apply(struc -> struc.get().setTextOverrun(OverrunStyle.CENTER_ELLIPSIS))
|
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()
|
||||||
|
+ (entry.getInformation().get() != null
|
||||||
|
? " [" + entry.getInformation().get() + "]"
|
||||||
|
: "")
|
||||||
|
+ (filtered.size() > 0 && entry.getEntry().getStore() instanceof FixedHierarchyStore
|
||||||
|
? " (" + filtered.size() + ")"
|
||||||
|
: "");
|
||||||
|
},
|
||||||
|
entry.nameProperty(),
|
||||||
|
entry.getInformation(),
|
||||||
|
filtered));
|
||||||
|
name.apply(struc -> struc.get().setTextOverrun(OverrunStyle.CENTER_ELLIPSIS))
|
||||||
.apply(struc -> struc.get().setPadding(new Insets(5, 5, 5, 0)));
|
.apply(struc -> struc.get().setPadding(new Insets(5, 5, 5, 0)));
|
||||||
name.apply(s -> AppFont.header(s.get()));
|
name.apply(s -> AppFont.header(s.get()));
|
||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Node createIcon() {
|
protected Node createIcon(int w, int h) {
|
||||||
var img = entry.isDisabled()
|
var img = entry.isDisabled()
|
||||||
? "disabled_icon.png"
|
? "disabled_icon.png"
|
||||||
: entry.getEntry()
|
: entry.getEntry()
|
||||||
.getProvider()
|
.getProvider()
|
||||||
.getDisplayIconFileName(entry.getEntry().getStore());
|
.getDisplayIconFileName(entry.getEntry().getStore());
|
||||||
var imageComp = new PrettyImageComp(new SimpleStringProperty(img), 55, 45);
|
var imageComp = new PrettyImageComp(new SimpleStringProperty(img), w, h);
|
||||||
var storeIcon = imageComp.createRegion();
|
var storeIcon = imageComp.createRegion();
|
||||||
storeIcon.getStyleClass().add("icon");
|
storeIcon.getStyleClass().add("icon");
|
||||||
if (entry.getState().getValue().isUsable()) {
|
if (entry.getState().getValue().isUsable()) {
|
||||||
|
@ -108,68 +133,7 @@ public class StoreEntryComp extends SimpleComp {
|
||||||
return storeIcon;
|
return storeIcon;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected Region createContent() {
|
protected Comp<?> createButtonBar() {
|
||||||
var name = createName().createRegion();
|
|
||||||
|
|
||||||
var size = createInformation();
|
|
||||||
|
|
||||||
var date = new Label();
|
|
||||||
date.textProperty().bind(AppI18n.readableDuration("usedDate", PlatformThread.sync(entry.lastAccessProperty())));
|
|
||||||
AppFont.small(date);
|
|
||||||
date.getStyleClass().add("date");
|
|
||||||
|
|
||||||
var grid = new GridPane();
|
|
||||||
|
|
||||||
var storeIcon = createIcon();
|
|
||||||
|
|
||||||
grid.getColumnConstraints()
|
|
||||||
.addAll(
|
|
||||||
createShareConstraint(grid, STORE_TYPE_WIDTH), createShareConstraint(grid, NAME_WIDTH),
|
|
||||||
createShareConstraint(grid, DETAILS_WIDTH), createShareConstraint(grid, BUTTONS_WIDTH));
|
|
||||||
grid.add(storeIcon, 0, 0, 1, 2);
|
|
||||||
grid.add(name, 1, 0);
|
|
||||||
grid.add(date, 1, 1);
|
|
||||||
grid.add(createSummary(), 2, 1);
|
|
||||||
grid.add(createInformation(), 2, 0);
|
|
||||||
grid.add(createButtonBar().createRegion(), 3, 0, 1, 2);
|
|
||||||
grid.setVgap(5);
|
|
||||||
GridPane.setHalignment(storeIcon, HPos.CENTER);
|
|
||||||
|
|
||||||
AppFont.small(size);
|
|
||||||
AppFont.small(date);
|
|
||||||
|
|
||||||
grid.getStyleClass().add("store-entry-grid");
|
|
||||||
|
|
||||||
applyState(grid);
|
|
||||||
|
|
||||||
var button = new JFXButton();
|
|
||||||
button.setGraphic(grid);
|
|
||||||
GrowAugment.create(true, false).augment(new SimpleCompStructure<>(grid));
|
|
||||||
button.getStyleClass().add("store-entry-comp");
|
|
||||||
button.setMaxWidth(2000);
|
|
||||||
button.setFocusTraversable(true);
|
|
||||||
button.accessibleTextProperty()
|
|
||||||
.bind(Bindings.createStringBinding(
|
|
||||||
() -> {
|
|
||||||
return entry.getName();
|
|
||||||
},
|
|
||||||
entry.nameProperty()));
|
|
||||||
button.accessibleHelpProperty().bind(entry.getInformation());
|
|
||||||
button.setOnAction(event -> {
|
|
||||||
event.consume();
|
|
||||||
ThreadHelper.runFailableAsync(() -> {
|
|
||||||
entry.refreshIfNeeded();
|
|
||||||
entry.executeDefaultAction();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
new ContextMenuAugment<>(() -> StoreEntryComp.this.createContextMenu())
|
|
||||||
.augment(new SimpleCompStructure<>(button));
|
|
||||||
|
|
||||||
return button;
|
|
||||||
}
|
|
||||||
|
|
||||||
private Comp<?> createButtonBar() {
|
|
||||||
var list = new ArrayList<Comp<?>>();
|
var list = new ArrayList<Comp<?>>();
|
||||||
for (var p : entry.getActionProviders().entrySet()) {
|
for (var p : entry.getActionProviders().entrySet()) {
|
||||||
var actionProvider = p.getKey().getDataStoreCallSite();
|
var actionProvider = p.getKey().getDataStoreCallSite();
|
||||||
|
@ -198,33 +162,35 @@ public class StoreEntryComp extends SimpleComp {
|
||||||
|
|
||||||
var settingsButton = createSettingsButton();
|
var settingsButton = createSettingsButton();
|
||||||
list.add(settingsButton);
|
list.add(settingsButton);
|
||||||
|
if (list.size() > 1) {
|
||||||
|
list.get(0).styleClass(Styles.LEFT_PILL);
|
||||||
|
for (int i = 1; i < list.size() - 1; i++) {
|
||||||
|
list.get(i).styleClass(Styles.CENTER_PILL);
|
||||||
|
}
|
||||||
|
list.get(list.size() - 1).styleClass(Styles.RIGHT_PILL);
|
||||||
|
}
|
||||||
|
list.forEach(comp -> {
|
||||||
|
comp.apply(struc -> struc.get().getStyleClass().remove(Styles.FLAT));
|
||||||
|
});
|
||||||
return new HorizontalComp(list)
|
return new HorizontalComp(list)
|
||||||
.apply(struc -> struc.get().setAlignment(Pos.CENTER_RIGHT))
|
|
||||||
.apply(struc -> {
|
.apply(struc -> {
|
||||||
for (Node child : struc.get().getChildren()) {
|
struc.get().setAlignment(Pos.CENTER_RIGHT);
|
||||||
((Region) child)
|
struc.get().setPadding(new Insets(5));
|
||||||
.prefWidthProperty()
|
})
|
||||||
.bind((struc.get().heightProperty().divide(1.7)));
|
.styleClass("button-bar");
|
||||||
((Region) child).prefHeightProperty().bind((struc.get().heightProperty()));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private Comp<?> createSettingsButton() {
|
protected Comp<?> createSettingsButton() {
|
||||||
var settingsButton = new IconButtonComp("mdomz-settings");
|
var settingsButton = new IconButtonComp("mdomz-settings");
|
||||||
settingsButton.styleClass("settings");
|
settingsButton.styleClass("settings");
|
||||||
settingsButton.accessibleText("Settings");
|
settingsButton.accessibleText("Settings");
|
||||||
settingsButton.apply(new ContextMenuAugment<>(
|
settingsButton.apply(new ContextMenuAugment<>(
|
||||||
event -> event.getButton() == MouseButton.PRIMARY, () -> StoreEntryComp.this.createContextMenu()));
|
event -> event.getButton() == MouseButton.PRIMARY, () -> StoreEntryComp.this.createContextMenu()));
|
||||||
settingsButton.apply(GrowAugment.create(false, true));
|
|
||||||
settingsButton.apply(s -> {
|
|
||||||
s.get().prefWidthProperty().bind(Bindings.divide(s.get().heightProperty(), 1.35));
|
|
||||||
});
|
|
||||||
settingsButton.apply(new FancyTooltipAugment<>("more"));
|
settingsButton.apply(new FancyTooltipAugment<>("more"));
|
||||||
return settingsButton;
|
return settingsButton;
|
||||||
}
|
}
|
||||||
|
|
||||||
private ContextMenu createContextMenu() {
|
protected ContextMenu createContextMenu() {
|
||||||
var contextMenu = new ContextMenu();
|
var contextMenu = new ContextMenu();
|
||||||
AppFont.normal(contextMenu.getStyleableNode());
|
AppFont.normal(contextMenu.getStyleableNode());
|
||||||
|
|
||||||
|
@ -279,17 +245,9 @@ public class StoreEntryComp extends SimpleComp {
|
||||||
return contextMenu;
|
return contextMenu;
|
||||||
}
|
}
|
||||||
|
|
||||||
private ColumnConstraints createShareConstraint(Region r, double share) {
|
protected ColumnConstraints createShareConstraint(Region r, double share) {
|
||||||
var cc = new ColumnConstraints();
|
var cc = new ColumnConstraints();
|
||||||
cc.prefWidthProperty().bind(Bindings.createDoubleBinding(() -> r.getWidth() * share, r.widthProperty()));
|
cc.prefWidthProperty().bind(Bindings.createDoubleBinding(() -> r.getWidth() * share, r.widthProperty()));
|
||||||
return cc;
|
return cc;
|
||||||
}
|
}
|
||||||
|
|
||||||
@SneakyThrows
|
|
||||||
@Override
|
|
||||||
protected Region createSimple() {
|
|
||||||
var loading = new LoadingOverlayComp(Comp.of(() -> createContent()), entry.getLoading());
|
|
||||||
var region = loading.createRegion();
|
|
||||||
return region;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,7 +23,7 @@ public class StoreEntryListComp extends SimpleComp {
|
||||||
.getFilterString()
|
.getFilterString()
|
||||||
.map(s -> (storeEntrySection -> storeEntrySection.shouldShow(s))));
|
.map(s -> (storeEntrySection -> storeEntrySection.shouldShow(s))));
|
||||||
var content = new ListBoxViewComp<>(filtered, topLevel.getChildren(), (StoreSection e) -> {
|
var content = new ListBoxViewComp<>(filtered, topLevel.getChildren(), (StoreSection e) -> {
|
||||||
return new StoreEntrySection(e);
|
return StoreSection.customSection(e);
|
||||||
});
|
});
|
||||||
return content.styleClass("store-list-comp").styleClass(Styles.STRIPED);
|
return content.styleClass("store-list-comp").styleClass(Styles.STRIPED);
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,17 +14,17 @@ import javafx.scene.paint.Color;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
public class StoreEntrySection extends Comp<CompStructure<VBox>> {
|
public class StoreEntrySectionComp extends Comp<CompStructure<VBox>> {
|
||||||
|
|
||||||
private final StoreSection section;
|
private final StoreSection section;
|
||||||
|
|
||||||
public StoreEntrySection(StoreSection section) {
|
public StoreEntrySectionComp(StoreSection section) {
|
||||||
this.section = section;
|
this.section = section;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public CompStructure<VBox> createBase() {
|
public CompStructure<VBox> createBase() {
|
||||||
var root = new StoreEntryComp(section.getWrapper()).apply(struc -> HBox.setHgrow(struc.get(), Priority.ALWAYS));
|
var root = StandardStoreEntryComp.customSection(section.getWrapper()).apply(struc -> HBox.setHgrow(struc.get(), Priority.ALWAYS));
|
||||||
var button = new IconButtonComp(
|
var button = new IconButtonComp(
|
||||||
Bindings.createStringBinding(
|
Bindings.createStringBinding(
|
||||||
() -> section.getWrapper().getExpanded().get()
|
() -> section.getWrapper().getExpanded().get()
|
||||||
|
@ -51,7 +51,7 @@ public class StoreEntrySection extends Comp<CompStructure<VBox>> {
|
||||||
.getFilterString()
|
.getFilterString()
|
||||||
.map(s -> (storeEntrySection -> storeEntrySection.shouldShow(s))));
|
.map(s -> (storeEntrySection -> storeEntrySection.shouldShow(s))));
|
||||||
var content = new ListBoxViewComp<>(shown, all, (StoreSection e) -> {
|
var content = new ListBoxViewComp<>(shown, all, (StoreSection e) -> {
|
||||||
return new StoreEntrySection(e).apply(GrowAugment.create(true, false));
|
return StoreSection.customSection(e).apply(GrowAugment.create(true, false));
|
||||||
})
|
})
|
||||||
.apply(struc -> HBox.setHgrow(struc.get(), Priority.ALWAYS))
|
.apply(struc -> HBox.setHgrow(struc.get(), Priority.ALWAYS))
|
||||||
.apply(struc -> struc.get().backgroundProperty().set(Background.fill(Color.color(0, 0, 0, 0.01))));
|
.apply(struc -> struc.get().backgroundProperty().set(Background.fill(Color.color(0, 0, 0, 0.01))));
|
||||||
|
@ -62,7 +62,8 @@ public class StoreEntrySection extends Comp<CompStructure<VBox>> {
|
||||||
return padding;
|
return padding;
|
||||||
});
|
});
|
||||||
return new VerticalComp(List.of(
|
return new VerticalComp(List.of(
|
||||||
new HorizontalComp(topEntryList),
|
new HorizontalComp(topEntryList)
|
||||||
|
.apply(struc -> struc.get().setFillHeight(true)),
|
||||||
new HorizontalComp(List.of(spacer, content))
|
new HorizontalComp(List.of(spacer, content))
|
||||||
.apply(struc -> struc.get().setFillHeight(true))
|
.apply(struc -> struc.get().setFillHeight(true))
|
||||||
.hide(BindingsHelper.persist(Bindings.or(
|
.hide(BindingsHelper.persist(Bindings.or(
|
|
@ -8,6 +8,7 @@ import io.xpipe.app.issue.ErrorEvent;
|
||||||
import io.xpipe.app.prefs.AppPrefs;
|
import io.xpipe.app.prefs.AppPrefs;
|
||||||
import io.xpipe.app.storage.DataStorage;
|
import io.xpipe.app.storage.DataStorage;
|
||||||
import io.xpipe.app.storage.DataStoreEntry;
|
import io.xpipe.app.storage.DataStoreEntry;
|
||||||
|
import io.xpipe.core.store.FixedHierarchyStore;
|
||||||
import javafx.beans.property.*;
|
import javafx.beans.property.*;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
|
|
||||||
|
@ -94,10 +95,7 @@ public class StoreEntryWrapper implements StorageFilter.Filterable {
|
||||||
disabled.setValue(entry.isDisabled());
|
disabled.setValue(entry.isDisabled());
|
||||||
state.setValue(entry.getState());
|
state.setValue(entry.getState());
|
||||||
expanded.setValue(entry.isExpanded());
|
expanded.setValue(entry.isExpanded());
|
||||||
information.setValue(
|
information.setValue(entry.getInformation());
|
||||||
entry.getInformation() != null
|
|
||||||
? entry.getInformation()
|
|
||||||
: entry.isDisabled() ? null : entry.getProvider().getDisplayName());
|
|
||||||
|
|
||||||
loading.setValue(entry.getState() == DataStoreEntry.State.VALIDATING);
|
loading.setValue(entry.getState() == DataStoreEntry.State.VALIDATING);
|
||||||
if (entry.getState().isUsable()) {
|
if (entry.getState().isUsable()) {
|
||||||
|
@ -178,6 +176,8 @@ public class StoreEntryWrapper implements StorageFilter.Filterable {
|
||||||
if (found != null) {
|
if (found != null) {
|
||||||
entry.updateLastUsed();
|
entry.updateLastUsed();
|
||||||
found.createAction(entry.getStore().asNeeded()).execute();
|
found.createAction(entry.getStore().asNeeded()).execute();
|
||||||
|
} else if (getEntry().getStore() instanceof FixedHierarchyStore) {
|
||||||
|
DataStorage.get().refreshChildren(entry);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package io.xpipe.app.comp.storage.store;
|
package io.xpipe.app.comp.storage.store;
|
||||||
|
|
||||||
import io.xpipe.app.comp.storage.StorageFilter;
|
import io.xpipe.app.comp.storage.StorageFilter;
|
||||||
|
import io.xpipe.app.fxcomps.Comp;
|
||||||
import io.xpipe.app.fxcomps.util.BindingsHelper;
|
import io.xpipe.app.fxcomps.util.BindingsHelper;
|
||||||
import io.xpipe.app.storage.DataStorage;
|
import io.xpipe.app.storage.DataStorage;
|
||||||
import io.xpipe.app.storage.DataStoreEntry;
|
import io.xpipe.app.storage.DataStoreEntry;
|
||||||
|
@ -14,6 +15,15 @@ import java.util.Comparator;
|
||||||
@Value
|
@Value
|
||||||
public class StoreSection implements StorageFilter.Filterable {
|
public class StoreSection implements StorageFilter.Filterable {
|
||||||
|
|
||||||
|
public static Comp<?> customSection(StoreSection e) {
|
||||||
|
var prov = e.getWrapper().getEntry().getProvider();
|
||||||
|
if (prov != null) {
|
||||||
|
return prov.customContainer(e);
|
||||||
|
} else {
|
||||||
|
return new StoreEntrySectionComp(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
StoreEntryWrapper wrapper;
|
StoreEntryWrapper wrapper;
|
||||||
ObservableList<StoreSection> children;
|
ObservableList<StoreSection> children;
|
||||||
|
|
||||||
|
@ -36,7 +46,7 @@ public class StoreSection implements StorageFilter.Filterable {
|
||||||
var parent = section.getWrapper()
|
var parent = section.getWrapper()
|
||||||
.getEntry()
|
.getEntry()
|
||||||
.getProvider()
|
.getProvider()
|
||||||
.getParent(section.getWrapper().getEntry().getStore());
|
.getLogicalParent(section.getWrapper().getEntry().getStore());
|
||||||
return parent == null
|
return parent == null
|
||||||
|| (DataStorage.get().getStoreEntryIfPresent(parent).isEmpty());
|
|| (DataStorage.get().getStoreEntryIfPresent(parent).isEmpty());
|
||||||
});
|
});
|
||||||
|
@ -56,7 +66,7 @@ public class StoreSection implements StorageFilter.Filterable {
|
||||||
.getStore()
|
.getStore()
|
||||||
.equals(other.getEntry()
|
.equals(other.getEntry()
|
||||||
.getProvider()
|
.getProvider()
|
||||||
.getParent(other.getEntry().getStore())));
|
.getLogicalParent(other.getEntry().getStore())));
|
||||||
var children = BindingsHelper.mappedContentBinding(filtered, entry1 -> create(entry1));
|
var children = BindingsHelper.mappedContentBinding(filtered, entry1 -> create(entry1));
|
||||||
var ordered = BindingsHelper.orderedContentBinding(children, COMPARATOR);
|
var ordered = BindingsHelper.orderedContentBinding(children, COMPARATOR);
|
||||||
return new StoreSection(e, ordered);
|
return new StoreSection(e, ordered);
|
||||||
|
|
|
@ -15,7 +15,7 @@ public class ListStoresExchangeImpl extends ListStoresExchange
|
||||||
public Response handleRequest(BeaconHandler handler, Request msg) {
|
public Response handleRequest(BeaconHandler handler, Request msg) {
|
||||||
DataStorage s = DataStorage.get();
|
DataStorage s = DataStorage.get();
|
||||||
var e = s.getStoreEntries().stream()
|
var e = s.getStoreEntries().stream()
|
||||||
.filter(entry -> !entry.isDisabled() && entry.getProvider().shouldShow())
|
.filter(entry -> !entry.isDisabled() && entry.getProvider().canManuallyCreate())
|
||||||
.sorted(Comparator.comparing(dataStoreEntry -> dataStoreEntry.getLastUsed()))
|
.sorted(Comparator.comparing(dataStoreEntry -> dataStoreEntry.getLastUsed()))
|
||||||
.map(col -> StoreListEntry.builder()
|
.map(col -> StoreListEntry.builder()
|
||||||
.name(col.getName())
|
.name(col.getName())
|
||||||
|
|
|
@ -24,7 +24,7 @@ public class StoreProviderListExchangeImpl extends StoreProviderListExchange
|
||||||
.map(p -> ProviderEntry.builder()
|
.map(p -> ProviderEntry.builder()
|
||||||
.id(p.getId())
|
.id(p.getId())
|
||||||
.description(p.getDisplayDescription())
|
.description(p.getDisplayDescription())
|
||||||
.hidden(!p.shouldShow())
|
.hidden(!p.canManuallyCreate())
|
||||||
.build())
|
.build())
|
||||||
.toList()));
|
.toList()));
|
||||||
|
|
||||||
|
|
|
@ -1,13 +1,14 @@
|
||||||
package io.xpipe.app.ext;
|
package io.xpipe.app.ext;
|
||||||
|
|
||||||
import io.xpipe.app.comp.base.MarkdownComp;
|
import io.xpipe.app.comp.base.MarkdownComp;
|
||||||
|
import io.xpipe.app.comp.storage.store.StandardStoreEntryComp;
|
||||||
|
import io.xpipe.app.comp.storage.store.StoreEntrySectionComp;
|
||||||
|
import io.xpipe.app.comp.storage.store.StoreEntryWrapper;
|
||||||
|
import io.xpipe.app.comp.storage.store.StoreSection;
|
||||||
import io.xpipe.app.core.AppI18n;
|
import io.xpipe.app.core.AppI18n;
|
||||||
import io.xpipe.app.fxcomps.Comp;
|
import io.xpipe.app.fxcomps.Comp;
|
||||||
import io.xpipe.core.dialog.Dialog;
|
import io.xpipe.core.dialog.Dialog;
|
||||||
import io.xpipe.core.store.DataStore;
|
import io.xpipe.core.store.*;
|
||||||
import io.xpipe.core.store.FileSystem;
|
|
||||||
import io.xpipe.core.store.ShellStore;
|
|
||||||
import io.xpipe.core.store.StreamDataStore;
|
|
||||||
import io.xpipe.core.util.JacksonizedValue;
|
import io.xpipe.core.util.JacksonizedValue;
|
||||||
import javafx.beans.binding.Bindings;
|
import javafx.beans.binding.Bindings;
|
||||||
import javafx.beans.property.Property;
|
import javafx.beans.property.Property;
|
||||||
|
@ -31,6 +32,14 @@ public interface DataStoreProvider {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
default Comp<?> customDisplay(StoreEntryWrapper w) {
|
||||||
|
return new StandardStoreEntryComp(w);
|
||||||
|
}
|
||||||
|
|
||||||
|
default Comp<?> customContainer(StoreSection section) {
|
||||||
|
return new StoreEntrySectionComp(section);
|
||||||
|
}
|
||||||
|
|
||||||
default Comp<?> createInsightsComp(ObservableValue<DataStore> store) {
|
default Comp<?> createInsightsComp(ObservableValue<DataStore> store) {
|
||||||
var content = Bindings.createStringBinding(
|
var content = Bindings.createStringBinding(
|
||||||
() -> {
|
() -> {
|
||||||
|
@ -77,10 +86,14 @@ public interface DataStoreProvider {
|
||||||
return DisplayCategory.OTHER;
|
return DisplayCategory.OTHER;
|
||||||
}
|
}
|
||||||
|
|
||||||
default DataStore getParent(DataStore store) {
|
default DataStore getLogicalParent(DataStore store) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
default DataStore getDisplayParent(DataStore store) {
|
||||||
|
return getLogicalParent(store);
|
||||||
|
}
|
||||||
|
|
||||||
default GuiDialog guiDialog(Property<DataStore> store) {
|
default GuiDialog guiDialog(Property<DataStore> store) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
@ -129,7 +142,13 @@ public interface DataStoreProvider {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
DataStore defaultStore();
|
default boolean requiresFrequentRefresh() {
|
||||||
|
return getStoreClasses().stream().anyMatch(aClass -> FixedHierarchyStore.class.isAssignableFrom(aClass));
|
||||||
|
}
|
||||||
|
|
||||||
|
default DataStore defaultStore() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
List<String> getPossibleNames();
|
List<String> getPossibleNames();
|
||||||
|
|
||||||
|
@ -139,7 +158,7 @@ public interface DataStoreProvider {
|
||||||
|
|
||||||
List<Class<?>> getStoreClasses();
|
List<Class<?>> getStoreClasses();
|
||||||
|
|
||||||
default boolean shouldShow() {
|
default boolean canManuallyCreate() {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
package io.xpipe.app.fxcomps.impl;
|
package io.xpipe.app.fxcomps.impl;
|
||||||
|
|
||||||
import com.jfoenix.controls.JFXButton;
|
import atlantafx.base.theme.Styles;
|
||||||
import io.xpipe.app.fxcomps.Comp;
|
import io.xpipe.app.fxcomps.Comp;
|
||||||
import io.xpipe.app.fxcomps.CompStructure;
|
import io.xpipe.app.fxcomps.CompStructure;
|
||||||
import io.xpipe.app.fxcomps.SimpleCompStructure;
|
import io.xpipe.app.fxcomps.SimpleCompStructure;
|
||||||
|
@ -9,9 +9,10 @@ import javafx.beans.property.SimpleObjectProperty;
|
||||||
import javafx.beans.value.ObservableValue;
|
import javafx.beans.value.ObservableValue;
|
||||||
import javafx.css.Size;
|
import javafx.css.Size;
|
||||||
import javafx.css.SizeUnits;
|
import javafx.css.SizeUnits;
|
||||||
|
import javafx.scene.control.Button;
|
||||||
import org.kordamp.ikonli.javafx.FontIcon;
|
import org.kordamp.ikonli.javafx.FontIcon;
|
||||||
|
|
||||||
public class IconButtonComp extends Comp<CompStructure<JFXButton>> {
|
public class IconButtonComp extends Comp<CompStructure<Button>> {
|
||||||
|
|
||||||
private final ObservableValue<String> icon;
|
private final ObservableValue<String> icon;
|
||||||
private final Runnable listener;
|
private final Runnable listener;
|
||||||
|
@ -30,8 +31,9 @@ public class IconButtonComp extends Comp<CompStructure<JFXButton>> {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public CompStructure<JFXButton> createBase() {
|
public CompStructure<Button> createBase() {
|
||||||
var button = new JFXButton();
|
var button = new Button();
|
||||||
|
button.getStyleClass().add(Styles.FLAT);
|
||||||
|
|
||||||
var fi = new FontIcon(icon.getValue());
|
var fi = new FontIcon(icon.getValue());
|
||||||
fi.setFocusTraversable(false);
|
fi.setFocusTraversable(false);
|
||||||
|
|
|
@ -97,19 +97,23 @@ public abstract class DataStorage {
|
||||||
}
|
}
|
||||||
|
|
||||||
public synchronized void refreshChildren(DataStoreEntry e) {
|
public synchronized void refreshChildren(DataStoreEntry e) {
|
||||||
|
refreshChildren(e, List.of());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public synchronized void refreshChildren(DataStoreEntry e, List<DataStoreEntry> oldChildren) {
|
||||||
if (!(e.getStore() instanceof FixedHierarchyStore)) {
|
if (!(e.getStore() instanceof FixedHierarchyStore)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
var newChildren = ((FixedHierarchyStore) e.getStore()).listChildren();
|
var newChildren = ((FixedHierarchyStore) e.getStore()).listChildren();
|
||||||
deleteChildren(e, true);
|
oldChildren.stream().filter(entry -> !newChildren.containsValue(entry.getStore())).forEach(entry -> {
|
||||||
newChildren.forEach((key, value) -> {
|
deleteChildren(entry, true);
|
||||||
try {
|
deleteStoreEntry(entry);
|
||||||
addStoreEntry(key, value);
|
});
|
||||||
} catch (Exception ex) {
|
newChildren.entrySet().stream().filter(entry -> oldChildren.stream().noneMatch(old -> old.getStore().equals(entry.getValue()))).forEach(entry -> {
|
||||||
throw new RuntimeException(ex);
|
addStoreEntryIfNotPresent(entry.getKey(), entry.getValue());
|
||||||
}
|
|
||||||
});
|
});
|
||||||
} catch (Exception ex) {
|
} catch (Exception ex) {
|
||||||
ErrorEvent.fromThrowable(ex).handle();
|
ErrorEvent.fromThrowable(ex).handle();
|
||||||
|
@ -133,8 +137,8 @@ public abstract class DataStorage {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
var parent = other.getProvider().getParent(other.getStore());
|
var parent = other.getProvider().getLogicalParent(other.getStore());
|
||||||
return entry.getStore().equals(parent);
|
return Objects.equals(entry.getStore(), parent);
|
||||||
})
|
})
|
||||||
.toList());
|
.toList());
|
||||||
|
|
||||||
|
@ -386,11 +390,28 @@ public abstract class DataStorage {
|
||||||
latest = e;
|
latest = e;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void refreshAsync(StorageElement element, boolean deep) {
|
public void setAndRefreshAsync(DataStoreEntry entry, DataStore s) {
|
||||||
|
ThreadHelper.runAsync(() -> {
|
||||||
|
var old = entry.getStore();
|
||||||
|
var children = getStoreChildren(entry, false);
|
||||||
|
try {
|
||||||
|
entry.setStoreInternal(s);
|
||||||
|
entry.refresh(true);
|
||||||
|
// Update old children
|
||||||
|
children.forEach(entry1 -> propagateUpdate(entry1));
|
||||||
|
DataStorage.get().refreshChildren(entry, children);
|
||||||
|
} catch (Exception e) {
|
||||||
|
entry.setStoreInternal(old);
|
||||||
|
entry.simpleRefresh();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public void refreshAsync(DataStoreEntry element, boolean deep) {
|
||||||
ThreadHelper.runAsync(() -> {
|
ThreadHelper.runAsync(() -> {
|
||||||
try {
|
try {
|
||||||
element.refresh(deep);
|
element.refresh(deep);
|
||||||
propagateUpdate();
|
propagateUpdate(element);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
ErrorEvent.fromThrowable(e).reportable(false).handle();
|
ErrorEvent.fromThrowable(e).reportable(false).handle();
|
||||||
}
|
}
|
||||||
|
@ -398,14 +419,11 @@ public abstract class DataStorage {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private void propagateUpdate() {
|
void propagateUpdate(DataStoreEntry origin) {
|
||||||
for (DataStoreEntry dataStoreEntry : getStoreEntries()) {
|
getStoreChildren(origin, false).forEach(entry -> {
|
||||||
dataStoreEntry.simpleRefresh();
|
entry.simpleRefresh();
|
||||||
}
|
propagateUpdate(entry);
|
||||||
|
});
|
||||||
for (var e : getSourceEntries()) {
|
|
||||||
e.simpleRefresh();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void addStoreEntry(@NonNull DataStoreEntry e) {
|
public void addStoreEntry(@NonNull DataStoreEntry e) {
|
||||||
|
@ -417,19 +435,21 @@ public abstract class DataStorage {
|
||||||
e.setDirectory(getStoresDir().resolve(e.getUuid().toString()));
|
e.setDirectory(getStoresDir().resolve(e.getUuid().toString()));
|
||||||
this.storeEntries.add(e);
|
this.storeEntries.add(e);
|
||||||
}
|
}
|
||||||
propagateUpdate();
|
propagateUpdate(e);
|
||||||
save();
|
save();
|
||||||
|
|
||||||
this.listeners.forEach(l -> l.onStoreAdd(e));
|
this.listeners.forEach(l -> l.onStoreAdd(e));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void addStoreEntryIfNotPresent(@NonNull String name, DataStore store) {
|
public DataStoreEntry addStoreEntryIfNotPresent(@NonNull String name, DataStore store) {
|
||||||
if (getStoreEntryIfPresent(store).isPresent()) {
|
var found = getStoreEntryIfPresent(store);
|
||||||
return;
|
if (found.isPresent()) {
|
||||||
|
return found.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
var e = DataStoreEntry.createNew(UUID.randomUUID(), createUniqueStoreEntryName(name), store);
|
var e = DataStoreEntry.createNew(UUID.randomUUID(), createUniqueStoreEntryName(name), store);
|
||||||
addStoreEntry(e);
|
addStoreEntry(e);
|
||||||
|
return e;
|
||||||
}
|
}
|
||||||
|
|
||||||
public DataStoreEntry addStoreEntry(@NonNull String name, DataStore store) {
|
public DataStoreEntry addStoreEntry(@NonNull String name, DataStore store) {
|
||||||
|
@ -446,7 +466,7 @@ public abstract class DataStorage {
|
||||||
synchronized (this) {
|
synchronized (this) {
|
||||||
this.storeEntries.remove(store);
|
this.storeEntries.remove(store);
|
||||||
}
|
}
|
||||||
propagateUpdate();
|
propagateUpdate(store);
|
||||||
save();
|
save();
|
||||||
this.listeners.forEach(l -> l.onStoreRemove(store));
|
this.listeners.forEach(l -> l.onStoreRemove(store));
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,7 +10,6 @@ import io.xpipe.app.ext.DataStoreProvider;
|
||||||
import io.xpipe.app.ext.DataStoreProviders;
|
import io.xpipe.app.ext.DataStoreProviders;
|
||||||
import io.xpipe.app.issue.ErrorEvent;
|
import io.xpipe.app.issue.ErrorEvent;
|
||||||
import io.xpipe.core.store.DataStore;
|
import io.xpipe.core.store.DataStore;
|
||||||
import io.xpipe.core.store.FixedHierarchyStore;
|
|
||||||
import io.xpipe.core.util.JacksonMapper;
|
import io.xpipe.core.util.JacksonMapper;
|
||||||
import lombok.*;
|
import lombok.*;
|
||||||
import lombok.experimental.NonFinal;
|
import lombok.experimental.NonFinal;
|
||||||
|
@ -204,6 +203,13 @@ public class DataStoreEntry extends StorageElement {
|
||||||
simpleRefresh();
|
simpleRefresh();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void setStoreInternal(DataStore store) {
|
||||||
|
this.store = store;
|
||||||
|
this.storeNode = DataStorageWriter.storeToNode(store);
|
||||||
|
lastModified = Instant.now();
|
||||||
|
dirty = true;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
TODO: Implement singular change functions
|
TODO: Implement singular change functions
|
||||||
*/
|
*/
|
||||||
|
@ -244,11 +250,6 @@ public class DataStoreEntry extends StorageElement {
|
||||||
state = State.VALIDATING;
|
state = State.VALIDATING;
|
||||||
listeners.forEach(l -> l.onUpdate());
|
listeners.forEach(l -> l.onUpdate());
|
||||||
store.validate();
|
store.validate();
|
||||||
|
|
||||||
if (store instanceof FixedHierarchyStore) {
|
|
||||||
DataStorage.get().refreshChildren(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
state = State.COMPLETE_AND_VALID;
|
state = State.COMPLETE_AND_VALID;
|
||||||
information = getProvider().queryInformationString(getStore(), 50);
|
information = getProvider().queryInformationString(getStore(), 50);
|
||||||
dirty = true;
|
dirty = true;
|
||||||
|
|
|
@ -40,6 +40,7 @@ open module io.xpipe.app {
|
||||||
exports io.xpipe.app.browser.action;
|
exports io.xpipe.app.browser.action;
|
||||||
exports io.xpipe.app.browser;
|
exports io.xpipe.app.browser;
|
||||||
exports io.xpipe.app.browser.icon;
|
exports io.xpipe.app.browser.icon;
|
||||||
|
exports io.xpipe.app.comp.storage.store;
|
||||||
|
|
||||||
requires com.sun.jna;
|
requires com.sun.jna;
|
||||||
requires com.sun.jna.platform;
|
requires com.sun.jna.platform;
|
||||||
|
|
|
@ -27,6 +27,10 @@
|
||||||
-fx-padding: 6px 6px 6px 0;
|
-fx-padding: 6px 6px 6px 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.condensed-store-entry-comp {
|
||||||
|
-fx-padding: 1px 6px 1px 0;
|
||||||
|
}
|
||||||
|
|
||||||
.store-entry-comp:hover {
|
.store-entry-comp:hover {
|
||||||
-fx-background-color: -color-neutral-muted;
|
-fx-background-color: -color-neutral-muted;
|
||||||
}
|
}
|
||||||
|
@ -35,6 +39,10 @@
|
||||||
-fx-background-color: -color-neutral-muted;
|
-fx-background-color: -color-neutral-muted;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.store-entry-comp .button-bar .button {
|
||||||
|
-fx-padding: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -17,7 +17,7 @@ import java.util.List;
|
||||||
public class FileStoreProvider implements DataStoreProvider {
|
public class FileStoreProvider implements DataStoreProvider {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean shouldShow() {
|
public boolean canManuallyCreate() {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -19,7 +19,7 @@ import java.util.List;
|
||||||
public class InMemoryStoreProvider implements DataStoreProvider {
|
public class InMemoryStoreProvider implements DataStoreProvider {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean shouldShow() {
|
public boolean canManuallyCreate() {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -11,7 +11,7 @@ import java.util.List;
|
||||||
public class InternalStreamProvider implements DataStoreProvider {
|
public class InternalStreamProvider implements DataStoreProvider {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean shouldShow() {
|
public boolean canManuallyCreate() {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -42,7 +42,7 @@ public class SinkDrainStoreProvider implements DataStoreProvider {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean shouldShow() {
|
public boolean canManuallyCreate() {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,64 @@
|
||||||
|
package io.xpipe.ext.base.actions;
|
||||||
|
|
||||||
|
import io.xpipe.app.core.AppI18n;
|
||||||
|
import io.xpipe.app.ext.ActionProvider;
|
||||||
|
import io.xpipe.app.storage.DataStorage;
|
||||||
|
import io.xpipe.app.storage.DataStoreEntry;
|
||||||
|
import io.xpipe.core.store.DataStore;
|
||||||
|
import javafx.beans.value.ObservableValue;
|
||||||
|
import lombok.Value;
|
||||||
|
|
||||||
|
public class RefreshStoreAction implements ActionProvider {
|
||||||
|
|
||||||
|
@Value
|
||||||
|
static class Action implements ActionProvider.Action {
|
||||||
|
|
||||||
|
DataStoreEntry store;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean requiresJavaFXPlatform() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void execute() throws Exception {
|
||||||
|
store.refresh(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ActionProvider.DataStoreCallSite<?> getDataStoreCallSite() {
|
||||||
|
return new ActionProvider.DataStoreCallSite<>() {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isMajor() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ActiveType activeType() {
|
||||||
|
return ActiveType.ALWAYS_ENABLE;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ActionProvider.Action createAction(DataStore store) {
|
||||||
|
return new Action(DataStorage.get().getStoreEntry(store));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Class<DataStore> getApplicableClass() {
|
||||||
|
return DataStore.class;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ObservableValue<String> getName(DataStore store) {
|
||||||
|
return AppI18n.observable("base.refresh");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getIcon(DataStore store) {
|
||||||
|
return "mdal-edit";
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
|
@ -12,7 +12,7 @@ import org.kordamp.ikonli.javafx.FontIcon;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
public class RefreshAction implements LeafAction {
|
public class RefreshDirectoryAction implements LeafAction {
|
||||||
|
|
||||||
public String getId() {
|
public String getId() {
|
||||||
return "refresh";
|
return "refresh";
|
|
@ -31,7 +31,7 @@ open module io.xpipe.ext.base {
|
||||||
FollowLinkAction,
|
FollowLinkAction,
|
||||||
BackAction,
|
BackAction,
|
||||||
ForwardAction,
|
ForwardAction,
|
||||||
RefreshAction,
|
RefreshDirectoryAction,
|
||||||
OpenFileDefaultAction,
|
OpenFileDefaultAction,
|
||||||
OpenFileWithAction,
|
OpenFileWithAction,
|
||||||
OpenDirectoryAction,
|
OpenDirectoryAction,
|
||||||
|
|
Loading…
Reference in a new issue