diff --git a/app/src/main/java/io/xpipe/app/comp/storage/store/StoreSection.java b/app/src/main/java/io/xpipe/app/comp/storage/store/StoreSection.java index fc1bc6c8..e0d0bc01 100644 --- a/app/src/main/java/io/xpipe/app/comp/storage/store/StoreSection.java +++ b/app/src/main/java/io/xpipe/app/comp/storage/store/StoreSection.java @@ -57,7 +57,7 @@ public class StoreSection implements StorageFilter.Filterable { storeEntrySection -> storeEntrySection.wrapper.getEntry().getName()); public static StoreSection createTopLevel() { - var topLevel = BindingsHelper.mappedContentBinding( + var topLevel = BindingsHelper.cachedMappedContentBinding( StoreViewState.get().getAllEntries(), storeEntryWrapper -> create(storeEntryWrapper, 1)); var filtered = BindingsHelper.filteredContentBinding(topLevel, section -> { return DataStorage.get() @@ -80,7 +80,7 @@ public class StoreSection implements StorageFilter.Filterable { .map(found -> found.equals(e.getEntry())) .orElse(false); }); - var children = BindingsHelper.mappedContentBinding(filtered, entry1 -> create(entry1, depth + 1)); + var children = BindingsHelper.cachedMappedContentBinding(filtered, entry1 -> create(entry1, depth + 1)); var ordered = BindingsHelper.orderedContentBinding(children, COMPARATOR); return new StoreSection(e, ordered, depth); } diff --git a/app/src/main/java/io/xpipe/app/fxcomps/util/BindingsHelper.java b/app/src/main/java/io/xpipe/app/fxcomps/util/BindingsHelper.java index 73d8526f..cd8af802 100644 --- a/app/src/main/java/io/xpipe/app/fxcomps/util/BindingsHelper.java +++ b/app/src/main/java/io/xpipe/app/fxcomps/util/BindingsHelper.java @@ -119,6 +119,29 @@ public class BindingsHelper { return l1; } + public static ObservableList cachedMappedContentBinding(ObservableList l2, Function map) { + var cache = new HashMap(); + + ObservableList l1 = FXCollections.observableList(new ArrayList<>()); + Runnable runnable = () -> { + cache.keySet().removeIf(t -> !l2.contains(t)); + setContent(l1, l2.stream() + .map(v -> { + if (!cache.containsKey(v)) { + cache.put(v, map.apply(v)); + } + + return cache.get(v); + }).toList()); + }; + runnable.run(); + l2.addListener((ListChangeListener) c -> { + runnable.run(); + }); + linkPersistently(l2, l1); + return l1; + } + public static ObservableList orderedContentBinding(ObservableList l2, Comparator comp) { ObservableList l1 = FXCollections.observableList(new ArrayList<>()); Runnable runnable = () -> { diff --git a/app/src/main/java/io/xpipe/app/storage/DataStorage.java b/app/src/main/java/io/xpipe/app/storage/DataStorage.java index 183cdd63..f2e6389e 100644 --- a/app/src/main/java/io/xpipe/app/storage/DataStorage.java +++ b/app/src/main/java/io/xpipe/app/storage/DataStorage.java @@ -16,6 +16,7 @@ import lombok.NonNull; import java.nio.file.Path; import java.util.*; +import java.util.stream.Stream; public abstract class DataStorage { @@ -329,11 +330,26 @@ public abstract class DataStorage { } public void updateEntry(DataStoreEntry entry, DataStoreEntry newEntry) { + var oldParent = DataStorage.get().getParent(entry, false); + var newParent = DataStorage.get().getParent(newEntry, false); + propagateUpdate( () -> { newEntry.finalizeEntry(); + + var children = getStoreChildren(entry, false, true); + if (!Objects.equals(oldParent, newParent)) { + var toRemove = Stream.concat(Stream.of(entry), children.stream()).toArray(DataStoreEntry[]::new); + listeners.forEach(storageListener -> storageListener.onStoreRemove(toRemove)); + } + entry.applyChanges(newEntry); entry.initializeEntry(); + + if (!Objects.equals(oldParent, newParent)) { + var toAdd = Stream.concat(Stream.of(entry), children.stream()).toArray(DataStoreEntry[]::new); + listeners.forEach(storageListener -> storageListener.onStoreAdd(toAdd)); + } }, entry); }