mirror of
https://github.com/xpipe-io/xpipe.git
synced 2024-11-25 00:50:31 +00:00
Store improvements
This commit is contained in:
parent
94f8a41dfb
commit
397fc785d6
12 changed files with 174 additions and 146 deletions
|
@ -170,10 +170,14 @@ final class BrowserBookmarkList extends SimpleComp {
|
|||
super.updateItem(item, empty);
|
||||
if (empty || item == null) {
|
||||
setText(null);
|
||||
|
||||
// Don't set image as that would trigger image comp update
|
||||
// and cells are emptied on each change, leading to unnecessary changes
|
||||
// img.set(null);
|
||||
setGraphic(null);
|
||||
|
||||
// Use opacity instead of visibility as visibility is kinda bugged with web views
|
||||
setOpacity(0.0);
|
||||
|
||||
setFocusTraversable(false);
|
||||
setAccessibleText(null);
|
||||
} else {
|
||||
|
@ -190,7 +194,7 @@ final class BrowserBookmarkList extends SimpleComp {
|
|||
img.set(item.getEntry()
|
||||
.getProvider()
|
||||
.getDisplayIconFileName(item.getEntry().getStore()));
|
||||
setGraphic(imageView);
|
||||
setOpacity(1.0);
|
||||
setFocusTraversable(true);
|
||||
setAccessibleText(
|
||||
item.getName() + " " + item.getEntry().getProvider().getDisplayName());
|
||||
|
|
|
@ -39,11 +39,11 @@ public class ListBoxViewComp<T> extends Comp<CompStructure<ScrollPane>> {
|
|||
VBox listView = new VBox();
|
||||
listView.setFocusTraversable(false);
|
||||
|
||||
refresh(listView, shown, cache, false);
|
||||
refresh(listView, shown, all, cache, false);
|
||||
listView.requestLayout();
|
||||
|
||||
shown.addListener((ListChangeListener<? super T>) (c) -> {
|
||||
refresh(listView, c.getList(), cache, true);
|
||||
refresh(listView, c.getList(), all, cache, true);
|
||||
});
|
||||
|
||||
all.addListener((ListChangeListener<? super T>) c -> {
|
||||
|
@ -57,9 +57,12 @@ public class ListBoxViewComp<T> extends Comp<CompStructure<ScrollPane>> {
|
|||
return new SimpleCompStructure<>(scroll);
|
||||
}
|
||||
|
||||
private void refresh(VBox listView, List<? extends T> c, Map<T, Region> cache, boolean asynchronous) {
|
||||
private void refresh(VBox listView, List<? extends T> shown, List<? extends T> all, Map<T, Region> cache, boolean asynchronous) {
|
||||
Runnable update = () -> {
|
||||
var newShown = c.stream()
|
||||
// Clear cache of unused values
|
||||
cache.keySet().removeIf(t -> !all.contains(t));
|
||||
|
||||
var newShown = shown.stream()
|
||||
.map(v -> {
|
||||
if (!cache.containsKey(v)) {
|
||||
cache.put(v, compFunction.apply(v).createRegion());
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
package io.xpipe.app.comp.storage.store;
|
||||
|
||||
import io.xpipe.app.comp.store.GuiDsStoreCreator;
|
||||
import io.xpipe.app.comp.storage.StorageFilter;
|
||||
import io.xpipe.app.comp.store.GuiDsStoreCreator;
|
||||
import io.xpipe.app.ext.ActionProvider;
|
||||
import io.xpipe.app.fxcomps.util.PlatformThread;
|
||||
import io.xpipe.app.issue.ErrorEvent;
|
||||
|
@ -181,7 +181,8 @@ public class StoreEntryWrapper implements StorageFilter.Filterable {
|
|||
public void executeDefaultAction() throws Exception {
|
||||
var found = getDefaultActionProvider().getValue();
|
||||
if (found != null) {
|
||||
if (entry.getState().equals(DataStoreEntry.State.COMPLETE_BUT_INVALID) || entry.getState().equals(DataStoreEntry.State.COMPLETE_NOT_VALIDATED)) {
|
||||
if (entry.getState().equals(DataStoreEntry.State.COMPLETE_BUT_INVALID)
|
||||
|| entry.getState().equals(DataStoreEntry.State.COMPLETE_NOT_VALIDATED)) {
|
||||
executeRefreshAction();
|
||||
}
|
||||
|
||||
|
|
|
@ -4,7 +4,6 @@ import io.xpipe.app.comp.storage.StorageFilter;
|
|||
import io.xpipe.app.fxcomps.Comp;
|
||||
import io.xpipe.app.fxcomps.util.BindingsHelper;
|
||||
import io.xpipe.app.storage.DataStorage;
|
||||
import io.xpipe.app.storage.DataStoreEntry;
|
||||
import javafx.collections.FXCollections;
|
||||
import javafx.collections.ObservableList;
|
||||
import lombok.Value;
|
||||
|
@ -28,7 +27,7 @@ public class StoreSection implements StorageFilter.Filterable {
|
|||
ObservableList<StoreSection> children;
|
||||
|
||||
private static final Comparator<StoreSection> COMPARATOR = Comparator.<StoreSection, Instant>comparing(
|
||||
o -> o.wrapper.getEntry().getState().equals(DataStoreEntry.State.COMPLETE_AND_VALID)
|
||||
o -> o.wrapper.getEntry().getState().isUsable()
|
||||
? o.wrapper.getEntry().getLastModified()
|
||||
: Instant.EPOCH)
|
||||
.reversed()
|
||||
|
@ -39,16 +38,9 @@ public class StoreSection implements StorageFilter.Filterable {
|
|||
var topLevel = BindingsHelper.mappedContentBinding(
|
||||
StoreViewState.get().getAllEntries(), storeEntryWrapper -> create(storeEntryWrapper));
|
||||
var filtered = BindingsHelper.filteredContentBinding(topLevel, section -> {
|
||||
if (!section.getWrapper().getEntry().getState().isUsable()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
var parent = section.getWrapper()
|
||||
.getEntry()
|
||||
.getProvider()
|
||||
.getDisplayParent(section.getWrapper().getEntry().getStore());
|
||||
return parent == null
|
||||
|| (DataStorage.get().getStoreEntryIfPresent(parent).isEmpty());
|
||||
return DataStorage.get()
|
||||
.getParent(section.getWrapper().getEntry(), true)
|
||||
.isEmpty();
|
||||
});
|
||||
var ordered = BindingsHelper.orderedContentBinding(filtered, COMPARATOR);
|
||||
return new StoreSection(null, ordered);
|
||||
|
@ -59,14 +51,13 @@ public class StoreSection implements StorageFilter.Filterable {
|
|||
return new StoreSection(e, FXCollections.observableArrayList());
|
||||
}
|
||||
|
||||
var filtered = BindingsHelper.filteredContentBinding(
|
||||
StoreViewState.get().getAllEntries(),
|
||||
other -> other.getEntry().getState().isUsable()
|
||||
&& e.getEntry()
|
||||
.getStore()
|
||||
.equals(other.getEntry()
|
||||
.getProvider()
|
||||
.getDisplayParent(other.getEntry().getStore())));
|
||||
var filtered =
|
||||
BindingsHelper.filteredContentBinding(StoreViewState.get().getAllEntries(), other -> {
|
||||
return DataStorage.get()
|
||||
.getParent(other.getEntry(), true)
|
||||
.map(found -> found.equals(e.getEntry()))
|
||||
.orElse(false);
|
||||
});
|
||||
var children = BindingsHelper.mappedContentBinding(filtered, entry1 -> create(entry1));
|
||||
var ordered = BindingsHelper.orderedContentBinding(children, COMPARATOR);
|
||||
return new StoreSection(e, ordered);
|
||||
|
|
|
@ -134,6 +134,10 @@ public interface DataStoreProvider {
|
|||
|
||||
String queryInformationString(DataStore store, int length) throws Exception;
|
||||
|
||||
default String queryInvalidInformationString(DataStore store, int length) throws Exception {
|
||||
return null;
|
||||
}
|
||||
|
||||
String toSummaryString(DataStore store, int length);
|
||||
|
||||
default String i18n(String key) {
|
||||
|
|
|
@ -6,15 +6,12 @@ import io.xpipe.app.fxcomps.util.PlatformThread;
|
|||
import io.xpipe.app.fxcomps.util.SimpleChangeListener;
|
||||
import javafx.beans.binding.Bindings;
|
||||
import javafx.beans.property.SimpleDoubleProperty;
|
||||
import javafx.beans.property.SimpleObjectProperty;
|
||||
import javafx.beans.property.SimpleStringProperty;
|
||||
import javafx.beans.value.ObservableValue;
|
||||
import javafx.geometry.Pos;
|
||||
import javafx.scene.Node;
|
||||
import javafx.scene.image.ImageView;
|
||||
import javafx.scene.layout.Region;
|
||||
import javafx.scene.layout.StackPane;
|
||||
import javafx.scene.web.WebView;
|
||||
|
||||
public class PrettyImageComp extends SimpleComp {
|
||||
|
||||
|
@ -31,6 +28,8 @@ public class PrettyImageComp extends SimpleComp {
|
|||
@Override
|
||||
protected Region createSimple() {
|
||||
var aspectRatioProperty = new SimpleDoubleProperty(1);
|
||||
var imageAspectRatioProperty = new SimpleDoubleProperty(1);
|
||||
var svgAspectRatioProperty = new SimpleDoubleProperty(1);
|
||||
var widthProperty = Bindings.createDoubleBinding(
|
||||
() -> {
|
||||
boolean widthLimited = width / height < aspectRatioProperty.doubleValue();
|
||||
|
@ -51,89 +50,84 @@ public class PrettyImageComp extends SimpleComp {
|
|||
}
|
||||
},
|
||||
aspectRatioProperty);
|
||||
|
||||
var image = new SimpleStringProperty();
|
||||
var currentNode = new SimpleObjectProperty<Node>();
|
||||
var stack = new StackPane();
|
||||
|
||||
{
|
||||
var svgImageContent = new SimpleStringProperty();
|
||||
var storeIcon = SvgView.create(svgImageContent);
|
||||
SimpleChangeListener.apply(image, newValue -> {
|
||||
if (AppImages.hasSvgImage(newValue)) {
|
||||
svgImageContent.set(AppImages.svgImage(newValue));
|
||||
}
|
||||
});
|
||||
var ar = Bindings.createDoubleBinding(
|
||||
() -> {
|
||||
return storeIcon.getWidth().getValue().doubleValue()
|
||||
/ storeIcon.getHeight().getValue().doubleValue();
|
||||
},
|
||||
storeIcon.getWidth(),
|
||||
storeIcon.getHeight());
|
||||
svgAspectRatioProperty.bind(ar);
|
||||
var node = storeIcon.createWebview();
|
||||
node.prefWidthProperty().bind(widthProperty);
|
||||
node.maxWidthProperty().bind(widthProperty);
|
||||
node.minWidthProperty().bind(widthProperty);
|
||||
node.prefHeightProperty().bind(heightProperty);
|
||||
node.maxHeightProperty().bind(heightProperty);
|
||||
node.minHeightProperty().bind(heightProperty);
|
||||
stack.getChildren().add(node);
|
||||
}
|
||||
|
||||
{
|
||||
var storeIcon = new ImageView();
|
||||
storeIcon.setFocusTraversable(false);
|
||||
storeIcon
|
||||
.imageProperty()
|
||||
.bind(Bindings.createObjectBinding(
|
||||
() -> {
|
||||
if (!AppImages.hasNormalImage(image.getValue())) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return AppImages.image(image.getValue());
|
||||
},
|
||||
image));
|
||||
var ar = Bindings.createDoubleBinding(
|
||||
() -> {
|
||||
if (storeIcon.getImage() == null) {
|
||||
return 1.0;
|
||||
}
|
||||
|
||||
return storeIcon.getImage().getWidth()
|
||||
/ storeIcon.getImage().getHeight();
|
||||
},
|
||||
storeIcon.imageProperty());
|
||||
imageAspectRatioProperty.bind(ar);
|
||||
storeIcon.fitWidthProperty().bind(widthProperty);
|
||||
storeIcon.fitHeightProperty().bind(heightProperty);
|
||||
storeIcon.setSmooth(true);
|
||||
stack.getChildren().add(storeIcon);
|
||||
}
|
||||
|
||||
SimpleChangeListener.apply(PlatformThread.sync(value), val -> {
|
||||
image.set(val);
|
||||
var requiresChange = val == null
|
||||
|| (val.endsWith(".svg") && !(currentNode.get() instanceof WebView)
|
||||
|| !(currentNode.get() instanceof ImageView));
|
||||
if (!requiresChange) {
|
||||
return;
|
||||
}
|
||||
|
||||
aspectRatioProperty.unbind();
|
||||
|
||||
if (val == null) {
|
||||
currentNode.set(new Region());
|
||||
stack.getChildren().get(0).setOpacity(0.0);
|
||||
stack.getChildren().get(1).setOpacity(0.0);
|
||||
} else if (val.endsWith(".svg")) {
|
||||
var storeIcon = SvgView.create(Bindings.createStringBinding(
|
||||
() -> {
|
||||
if (!AppImages.hasSvgImage(image.getValue())) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return AppImages.svgImage(image.getValue());
|
||||
},
|
||||
image));
|
||||
var ar = Bindings.createDoubleBinding(
|
||||
() -> {
|
||||
return storeIcon.getWidth().getValue().doubleValue()
|
||||
/ storeIcon.getHeight().getValue().doubleValue();
|
||||
},
|
||||
storeIcon.getWidth(),
|
||||
storeIcon.getHeight());
|
||||
aspectRatioProperty.bind(ar);
|
||||
var node = storeIcon.createWebview();
|
||||
node.prefWidthProperty().bind(widthProperty);
|
||||
node.maxWidthProperty().bind(widthProperty);
|
||||
node.minWidthProperty().bind(widthProperty);
|
||||
node.prefHeightProperty().bind(heightProperty);
|
||||
node.maxHeightProperty().bind(heightProperty);
|
||||
node.minHeightProperty().bind(heightProperty);
|
||||
currentNode.set(node);
|
||||
aspectRatioProperty.bind(svgAspectRatioProperty);
|
||||
stack.getChildren().get(0).setOpacity(1.0);
|
||||
stack.getChildren().get(1).setOpacity(0.0);
|
||||
} else {
|
||||
var storeIcon = new ImageView();
|
||||
storeIcon.setFocusTraversable(false);
|
||||
storeIcon
|
||||
.imageProperty()
|
||||
.bind(Bindings.createObjectBinding(
|
||||
() -> {
|
||||
if (!AppImages.hasNormalImage(image.getValue())) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return AppImages.image(image.getValue());
|
||||
},
|
||||
image));
|
||||
var ar = Bindings.createDoubleBinding(
|
||||
() -> {
|
||||
if (storeIcon.getImage() == null) {
|
||||
return 1.0;
|
||||
}
|
||||
|
||||
return storeIcon.getImage().getWidth()
|
||||
/ storeIcon.getImage().getHeight();
|
||||
},
|
||||
storeIcon.imageProperty());
|
||||
aspectRatioProperty.bind(ar);
|
||||
storeIcon.fitWidthProperty().bind(widthProperty);
|
||||
storeIcon.fitHeightProperty().bind(heightProperty);
|
||||
storeIcon.setSmooth(true);
|
||||
currentNode.set(storeIcon);
|
||||
aspectRatioProperty.bind(imageAspectRatioProperty);
|
||||
stack.getChildren().get(0).setOpacity(0.0);
|
||||
stack.getChildren().get(1).setOpacity(1.0);
|
||||
}
|
||||
});
|
||||
|
||||
var stack = new StackPane();
|
||||
SimpleChangeListener.apply(currentNode, val -> {
|
||||
if (val == null) {
|
||||
stack.getChildren().clear();
|
||||
return;
|
||||
}
|
||||
|
||||
stack.getChildren().setAll(val);
|
||||
});
|
||||
stack.setFocusTraversable(false);
|
||||
stack.setPrefWidth(width);
|
||||
stack.setMinWidth(width);
|
||||
|
|
|
@ -68,24 +68,14 @@ public abstract class DataStorage {
|
|||
}
|
||||
|
||||
public synchronized boolean refreshChildren(DataStoreEntry e) {
|
||||
var children = getLogicalStoreChildren(e, false);
|
||||
return refreshChildren(e, children);
|
||||
}
|
||||
|
||||
public synchronized boolean refreshChildren(DataStoreEntry e, List<DataStoreEntry> oldChildren) {
|
||||
if (!(e.getStore() instanceof FixedHierarchyStore)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
deleteChildren(e, true);
|
||||
var newChildren = ((FixedHierarchyStore) e.getStore()).listChildren();
|
||||
oldChildren.stream().filter(entry -> !newChildren.containsValue(entry.getStore())).forEach(entry -> {
|
||||
deleteChildren(entry, true);
|
||||
deleteStoreEntry(entry);
|
||||
});
|
||||
newChildren.entrySet().stream().filter(entry -> oldChildren.stream().noneMatch(old -> old.getStore().equals(entry.getValue()))).forEach(entry -> {
|
||||
addStoreEntryIfNotPresent(entry.getKey(), entry.getValue());
|
||||
});
|
||||
newChildren.forEach((key, value) -> addStoreEntryIfNotPresent(key, value));
|
||||
return newChildren.size() > 0;
|
||||
} catch (Exception ex) {
|
||||
ErrorEvent.fromThrowable(ex).handle();
|
||||
|
@ -95,29 +85,44 @@ public abstract class DataStorage {
|
|||
|
||||
public synchronized void deleteChildren(DataStoreEntry e, boolean deep) {
|
||||
// Reverse to delete deepest children first
|
||||
var ordered = getLogicalStoreChildren(e, deep);
|
||||
var ordered = getStoreChildren(e, false, deep);
|
||||
Collections.reverse(ordered);
|
||||
|
||||
ordered.forEach(entry -> {
|
||||
deleteStoreEntry(entry);
|
||||
synchronized (this) {
|
||||
this.storeEntries.remove(entry);
|
||||
}
|
||||
this.listeners.forEach(l -> l.onStoreRemove(entry));
|
||||
});
|
||||
save();
|
||||
}
|
||||
|
||||
public synchronized List<DataStoreEntry> getLogicalStoreChildren(DataStoreEntry entry, boolean deep) {
|
||||
var children = new ArrayList<>(getStoreEntries().stream()
|
||||
.filter(other -> {
|
||||
if (!other.getState().isUsable()) {
|
||||
return false;
|
||||
}
|
||||
public synchronized Optional<DataStoreEntry> getParent(DataStoreEntry entry, boolean display) {
|
||||
if (!entry.getState().isUsable()) {
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
var parent = other.getProvider().getLogicalParent(other.getStore());
|
||||
return Objects.equals(entry.getStore(), parent);
|
||||
})
|
||||
.toList());
|
||||
var provider = entry.getProvider();
|
||||
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;
|
||||
}
|
||||
|
||||
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)) {
|
||||
children.addAll(getLogicalStoreChildren(dataStoreEntry, true));
|
||||
children.addAll(getStoreChildren(dataStoreEntry, display, true));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -174,7 +179,7 @@ public abstract class DataStorage {
|
|||
|
||||
public synchronized DataStoreEntry getStoreEntry(@NonNull DataStore store) {
|
||||
var entry = storeEntries.stream()
|
||||
.filter(n -> store.equals(n.getStore()))
|
||||
.filter(n -> Objects.equals(store.getClass(), n.getStore().getClass()) && store.equals(n.getStore()))
|
||||
.findFirst()
|
||||
.orElseThrow(() -> new IllegalArgumentException("Store not found"));
|
||||
return entry;
|
||||
|
@ -195,13 +200,11 @@ public abstract class DataStorage {
|
|||
public void setAndRefreshAsync(DataStoreEntry entry, DataStore s) {
|
||||
ThreadHelper.runAsync(() -> {
|
||||
var old = entry.getStore();
|
||||
var children = getLogicalStoreChildren(entry, false);
|
||||
deleteChildren(entry, true);
|
||||
try {
|
||||
entry.setStoreInternal(s, false);
|
||||
entry.refresh(true);
|
||||
// Update old children
|
||||
children.forEach(entry1 -> propagateUpdate(entry1));
|
||||
DataStorage.get().refreshChildren(entry, children);
|
||||
DataStorage.get().refreshChildren(entry);
|
||||
} catch (Exception e) {
|
||||
entry.setStoreInternal(old, false);
|
||||
entry.simpleRefresh();
|
||||
|
@ -222,7 +225,7 @@ public abstract class DataStorage {
|
|||
}
|
||||
|
||||
void propagateUpdate(DataStoreEntry origin) {
|
||||
getLogicalStoreChildren(origin, false).forEach(entry -> {
|
||||
getStoreChildren(origin, false, false).forEach(entry -> {
|
||||
entry.simpleRefresh();
|
||||
propagateUpdate(entry);
|
||||
});
|
||||
|
|
|
@ -46,6 +46,9 @@ public class DataStoreEntry extends StorageElement {
|
|||
@NonFinal
|
||||
boolean expanded;
|
||||
|
||||
@NonFinal
|
||||
DataStoreProvider provider;
|
||||
|
||||
private DataStoreEntry(
|
||||
Path directory,
|
||||
UUID uuid,
|
||||
|
@ -65,6 +68,7 @@ public class DataStoreEntry extends StorageElement {
|
|||
this.state = state;
|
||||
this.configuration = configuration;
|
||||
this.expanded = expanded;
|
||||
this.provider = store != null ? DataStoreProviders.byStoreClass(store.getClass()).orElse(null) : null;
|
||||
}
|
||||
|
||||
@SneakyThrows
|
||||
|
@ -207,6 +211,7 @@ public class DataStoreEntry extends StorageElement {
|
|||
lastModified = Instant.now();
|
||||
information = e.information;
|
||||
dirty = true;
|
||||
provider = e.provider;
|
||||
simpleRefresh();
|
||||
}
|
||||
|
||||
|
@ -230,6 +235,7 @@ public class DataStoreEntry extends StorageElement {
|
|||
store = null;
|
||||
state = State.LOAD_FAILED;
|
||||
information = null;
|
||||
provider = null;
|
||||
dirty = dirty || oldStore != null;
|
||||
listeners.forEach(l -> l.onUpdate());
|
||||
} else {
|
||||
|
@ -241,6 +247,7 @@ public class DataStoreEntry extends StorageElement {
|
|||
|
||||
dirty = dirty || !nodesEqual;
|
||||
store = newStore;
|
||||
provider = DataStoreProviders.byStoreClass(newStore.getClass()).orElse(null);
|
||||
var complete = newStore.isComplete();
|
||||
|
||||
try {
|
||||
|
@ -261,13 +268,18 @@ public class DataStoreEntry extends StorageElement {
|
|||
? State.COMPLETE_NOT_VALIDATED
|
||||
: state;
|
||||
state = stateToUse;
|
||||
information = state == State.COMPLETE_AND_VALID
|
||||
? information
|
||||
: state == State.COMPLETE_BUT_INVALID
|
||||
? getProvider().queryInvalidInformationString(getStore(), 50)
|
||||
: null;
|
||||
} else {
|
||||
var stateToUse = state == State.LOAD_FAILED ? State.COMPLETE_BUT_INVALID : State.INCOMPLETE;
|
||||
state = stateToUse;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
state = store.isComplete() ? State.COMPLETE_BUT_INVALID : State.INCOMPLETE;
|
||||
information = null;
|
||||
state = State.COMPLETE_BUT_INVALID;
|
||||
information = getProvider().queryInvalidInformationString(getStore(), 50);
|
||||
throw e;
|
||||
} finally {
|
||||
propagateUpdate();
|
||||
|
@ -318,11 +330,7 @@ public class DataStoreEntry extends StorageElement {
|
|||
}
|
||||
|
||||
public DataStoreProvider getProvider() {
|
||||
if (store == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return DataStoreProviders.byStoreClass(store.getClass()).orElse(null);
|
||||
return provider;
|
||||
}
|
||||
|
||||
@Getter
|
||||
|
|
|
@ -121,8 +121,23 @@ public class FileBridge {
|
|||
return Optional.empty();
|
||||
}
|
||||
|
||||
public void openReadOnlyString(String input, Consumer<String> fileConsumer) {
|
||||
if (input == null) {
|
||||
input = "";
|
||||
}
|
||||
|
||||
var id = UUID.randomUUID();
|
||||
String s = input;
|
||||
openIO(
|
||||
id.toString(),
|
||||
id,
|
||||
() -> new ByteArrayInputStream(s.getBytes(StandardCharsets.UTF_8)),
|
||||
null,
|
||||
fileConsumer);
|
||||
}
|
||||
|
||||
public void openString(
|
||||
String keyName, Object key, String input, Consumer<String> output, Consumer<String> consumer) {
|
||||
String keyName, Object key, String input, Consumer<String> output, Consumer<String> fileConsumer) {
|
||||
if (input == null) {
|
||||
input = "";
|
||||
}
|
||||
|
@ -139,7 +154,7 @@ public class FileBridge {
|
|||
output.accept(new String(toByteArray(), StandardCharsets.UTF_8));
|
||||
}
|
||||
},
|
||||
consumer);
|
||||
fileConsumer);
|
||||
}
|
||||
|
||||
public void openIO(
|
||||
|
|
|
@ -83,6 +83,10 @@ public class FileOpener {
|
|||
}
|
||||
}
|
||||
|
||||
public static void openReadOnlyString(String input) {
|
||||
FileBridge.get().openReadOnlyString(input, s -> openInTextEditor(s));
|
||||
}
|
||||
|
||||
public static void openString(String keyName, Object key, String input, Consumer<String> output) {
|
||||
FileBridge.get().openString(keyName, key, input, output, file -> openInTextEditor(file));
|
||||
}
|
||||
|
|
|
@ -5,6 +5,7 @@ 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 io.xpipe.core.store.FixedHierarchyStore;
|
||||
import javafx.beans.value.ObservableValue;
|
||||
import lombok.Value;
|
||||
|
||||
|
@ -47,8 +48,8 @@ public class DeleteStoreChildrenAction implements ActionProvider {
|
|||
|
||||
@Override
|
||||
public boolean isApplicable(DataStore o) {
|
||||
return DataStorage.get()
|
||||
.getLogicalStoreChildren(DataStorage.get().getStoreEntry(o), true)
|
||||
return !(o instanceof FixedHierarchyStore) && DataStorage.get()
|
||||
.getStoreChildren(DataStorage.get().getStoreEntry(o), true, true)
|
||||
.size()
|
||||
> 1;
|
||||
}
|
||||
|
|
|
@ -24,7 +24,7 @@ tilda=Tilda
|
|||
copyShareLink=Copy share link
|
||||
selectStore=Select Store
|
||||
saveSource=Save for later
|
||||
deleteChildren=Delete children
|
||||
deleteChildren=Remove children
|
||||
selectSource=Select Source
|
||||
commandLineRead=Update
|
||||
commandLineWrite=Write
|
||||
|
|
Loading…
Reference in a new issue