From c1886cc9cde4259ebef7db9f72b095f5a332aad6 Mon Sep 17 00:00:00 2001 From: crschnick Date: Wed, 3 May 2023 16:08:01 +0000 Subject: [PATCH] Fix file browser connection list not updating --- .../io/xpipe/app/browser/BookmarkList.java | 62 ++++++++----------- .../comp/source/store/GuiDsStoreCreator.java | 2 +- ...ava => StoreEntryFlatMiniSectionComp.java} | 38 +++++++----- .../storage/store/StoreEntryListComp.java | 6 +- .../comp/storage/store/StoreEntrySection.java | 10 ++- .../comp/storage/store/StoreIntroComp.java | 2 +- ...toreViewSection.java => StoreSection.java} | 26 ++++---- .../app/fxcomps/impl/DataStoreChoiceComp.java | 20 +++--- .../java/io/xpipe/app/util/ScanAlert.java | 14 +++-- 9 files changed, 89 insertions(+), 91 deletions(-) rename app/src/main/java/io/xpipe/app/comp/storage/store/{StoreEntryFlatMiniSection.java => StoreEntryFlatMiniSectionComp.java} (51%) rename app/src/main/java/io/xpipe/app/comp/storage/store/{StoreViewSection.java => StoreSection.java} (69%) diff --git a/app/src/main/java/io/xpipe/app/browser/BookmarkList.java b/app/src/main/java/io/xpipe/app/browser/BookmarkList.java index 955572fb..480aa147 100644 --- a/app/src/main/java/io/xpipe/app/browser/BookmarkList.java +++ b/app/src/main/java/io/xpipe/app/browser/BookmarkList.java @@ -1,21 +1,21 @@ package io.xpipe.app.browser; -import io.xpipe.app.comp.storage.store.StoreEntryFlatMiniSection; -import io.xpipe.app.comp.storage.store.StoreEntryWrapper; +import io.xpipe.app.comp.base.ListBoxViewComp; +import io.xpipe.app.comp.storage.store.StoreEntryFlatMiniSectionComp; +import io.xpipe.app.fxcomps.Comp; import io.xpipe.app.fxcomps.SimpleComp; import io.xpipe.app.fxcomps.SimpleCompStructure; import io.xpipe.app.fxcomps.augment.DragPseudoClassAugment; +import io.xpipe.app.fxcomps.augment.GrowAugment; +import io.xpipe.app.fxcomps.util.BindingsHelper; import io.xpipe.core.store.DataStore; import io.xpipe.core.store.ShellStore; import javafx.application.Platform; import javafx.geometry.Point2D; import javafx.scene.control.Button; -import javafx.scene.control.ScrollPane; import javafx.scene.input.DragEvent; import javafx.scene.layout.Region; -import javafx.scene.layout.VBox; -import java.util.Map; import java.util.Timer; import java.util.TimerTask; @@ -33,39 +33,29 @@ final class BookmarkList extends SimpleComp { @Override protected Region createSimple() { - var map = StoreEntryFlatMiniSection.createMap(); - var list = new VBox(); - for (Map.Entry e : map.entrySet()) { - if (!(e.getKey().getEntry().getStore() instanceof ShellStore)) { - continue; - } + var observableList = BindingsHelper.filteredContentBinding(StoreEntryFlatMiniSectionComp.ALL, e -> e.getEntry().getStore() instanceof ShellStore); + var list = new ListBoxViewComp<>(observableList, observableList, e -> { + return Comp.of(() -> { + var button = new Button(null, e.createRegion()); + button.setOnAction(event -> { + var fileSystem = ((ShellStore) e.getEntry().getStore()); + model.openFileSystem(fileSystem); + event.consume(); + }); + GrowAugment.create(true, false).augment(new SimpleCompStructure<>(button)); + DragPseudoClassAugment.create().augment(new SimpleCompStructure<>(button)); - var button = new Button(null, e.getValue()); - button.setOnAction(event -> { - var fileSystem = ((ShellStore) e.getKey().getEntry().getStore()); - model.openFileSystem(fileSystem); - event.consume(); + button.addEventHandler( + DragEvent.DRAG_OVER, + mouseEvent -> handleHoverTimer(e.getEntry().getStore(), mouseEvent)); + button.addEventHandler( + DragEvent.DRAG_EXITED, + mouseEvent -> activeTask = null); + + return button; }); - button.prefWidthProperty().bind(list.widthProperty()); - DragPseudoClassAugment.create().augment(new SimpleCompStructure<>(button)); - - button.addEventHandler( - DragEvent.DRAG_OVER, - mouseEvent -> handleHoverTimer(e.getKey().getEntry().getStore(), mouseEvent)); - button.addEventHandler( - DragEvent.DRAG_EXITED, - mouseEvent -> activeTask = null); - - list.getChildren().add(button); - } - list.setFillWidth(true); - list.getStyleClass().add("bookmark-list"); - - var sp = new ScrollPane(list); - sp.setFitToWidth(true); - sp.setHbarPolicy(ScrollPane.ScrollBarPolicy.NEVER); - - return sp; + }).styleClass("bookmark-list").createRegion(); + return list; } private void handleHoverTimer(DataStore store, DragEvent event) { diff --git a/app/src/main/java/io/xpipe/app/comp/source/store/GuiDsStoreCreator.java b/app/src/main/java/io/xpipe/app/comp/source/store/GuiDsStoreCreator.java index 595b09df..c59fe1e3 100644 --- a/app/src/main/java/io/xpipe/app/comp/source/store/GuiDsStoreCreator.java +++ b/app/src/main/java/io/xpipe/app/comp/source/store/GuiDsStoreCreator.java @@ -109,7 +109,7 @@ public class GuiDsStoreCreator extends MultiStepComp.Step> { show(null, null, null, filter, e -> { try { DataStorage.get().addStoreEntry(e); - ScanAlert.show(e.getStore(), true); + ScanAlert.showAsync(e.getStore(), true); } catch (Exception ex) { ErrorEvent.fromThrowable(ex).handle(); } diff --git a/app/src/main/java/io/xpipe/app/comp/storage/store/StoreEntryFlatMiniSection.java b/app/src/main/java/io/xpipe/app/comp/storage/store/StoreEntryFlatMiniSectionComp.java similarity index 51% rename from app/src/main/java/io/xpipe/app/comp/storage/store/StoreEntryFlatMiniSection.java rename to app/src/main/java/io/xpipe/app/comp/storage/store/StoreEntryFlatMiniSectionComp.java index f7e5a4ca..7caa3648 100644 --- a/app/src/main/java/io/xpipe/app/comp/storage/store/StoreEntryFlatMiniSection.java +++ b/app/src/main/java/io/xpipe/app/comp/storage/store/StoreEntryFlatMiniSectionComp.java @@ -5,6 +5,9 @@ import io.xpipe.app.fxcomps.SimpleComp; import io.xpipe.app.fxcomps.impl.PrettyImageComp; import io.xpipe.app.storage.DataStoreEntry; import javafx.beans.property.SimpleStringProperty; +import javafx.collections.FXCollections; +import javafx.collections.ListChangeListener; +import javafx.collections.ObservableList; import javafx.geometry.Orientation; import javafx.scene.control.Label; import javafx.scene.layout.HBox; @@ -12,27 +15,34 @@ import javafx.scene.layout.Region; import lombok.EqualsAndHashCode; import lombok.Value; -import java.util.LinkedHashMap; -import java.util.Map; - @Value @EqualsAndHashCode(callSuper = true) -public class StoreEntryFlatMiniSection extends SimpleComp { +public class StoreEntryFlatMiniSectionComp extends SimpleComp { + + public static final ObservableList ALL = FXCollections.observableArrayList(); + + static { + var topLevel = StoreSection.createTopLevels(); + + topLevel.addListener((ListChangeListener) c -> { + ALL.clear(); + var depth = 0; + for (StoreSection v : topLevel) { + System.out.println(v.getWrapper().getEntry().getName() + " " + v.getChildren().size()); + add(depth, v); + } + }); - public static Map createMap() { - var map = new LinkedHashMap(); - var topLevel = StoreViewSection.createTopLevels(); var depth = 0; - for (StoreViewSection v : topLevel) { - add(depth, v, map); + for (StoreSection v : topLevel) { + add(depth, v); } - return map; } - private static void add(int depth, StoreViewSection section, Map map) { - map.put(section.getWrapper(), new StoreEntryFlatMiniSection(depth, section.getWrapper().getEntry()).createRegion()); - for (StoreViewSection child : section.getChildren()) { - add(depth + 1, child, map); + private static void add(int depth, StoreSection section) { + ALL.add(new StoreEntryFlatMiniSectionComp(depth, section.getWrapper().getEntry())); + for (StoreSection child : section.getChildren()) { + add(depth + 1, child); } } diff --git a/app/src/main/java/io/xpipe/app/comp/storage/store/StoreEntryListComp.java b/app/src/main/java/io/xpipe/app/comp/storage/store/StoreEntryListComp.java index dc1a1d76..5ea1076b 100644 --- a/app/src/main/java/io/xpipe/app/comp/storage/store/StoreEntryListComp.java +++ b/app/src/main/java/io/xpipe/app/comp/storage/store/StoreEntryListComp.java @@ -15,14 +15,14 @@ import java.util.LinkedHashMap; public class StoreEntryListComp extends SimpleComp { private Comp createList() { - var topLevel = StoreViewSection.createTopLevels(); + var topLevel = StoreSection.createTopLevels(); var filtered = BindingsHelper.filteredContentBinding( topLevel, StoreViewState.get() .getFilterString() .map(s -> (storeEntrySection -> storeEntrySection.shouldShow(s)))); - var content = new ListBoxViewComp<>(filtered, topLevel, (StoreViewSection e) -> { - return new StoreEntrySection(e, true); + var content = new ListBoxViewComp<>(filtered, topLevel, (StoreSection e) -> { + return new StoreEntrySection(e); }); return content.styleClass("store-list-comp").styleClass(Styles.STRIPED); } diff --git a/app/src/main/java/io/xpipe/app/comp/storage/store/StoreEntrySection.java b/app/src/main/java/io/xpipe/app/comp/storage/store/StoreEntrySection.java index 739ac456..c1d03af2 100644 --- a/app/src/main/java/io/xpipe/app/comp/storage/store/StoreEntrySection.java +++ b/app/src/main/java/io/xpipe/app/comp/storage/store/StoreEntrySection.java @@ -16,12 +16,10 @@ import java.util.List; public class StoreEntrySection extends Comp> { - private final StoreViewSection section; - private final boolean top; + private final StoreSection section; - public StoreEntrySection(StoreViewSection section, boolean top) { + public StoreEntrySection(StoreSection section) { this.section = section; - this.top = top; } @Override @@ -49,8 +47,8 @@ public class StoreEntrySection extends Comp> { StoreViewState.get() .getFilterString() .map(s -> (storeEntrySection -> storeEntrySection.shouldShow(s)))); - var content = new ListBoxViewComp<>(shown, all, (StoreViewSection e) -> { - return new StoreEntrySection(e, false).apply(GrowAugment.create(true, false)); + var content = new ListBoxViewComp<>(shown, all, (StoreSection e) -> { + return new StoreEntrySection(e).apply(GrowAugment.create(true, false)); }) .apply(struc -> HBox.setHgrow(struc.get(), Priority.ALWAYS)) .apply(struc -> struc.get().backgroundProperty().set(Background.fill(Color.color(0, 0, 0, 0.01)))); diff --git a/app/src/main/java/io/xpipe/app/comp/storage/store/StoreIntroComp.java b/app/src/main/java/io/xpipe/app/comp/storage/store/StoreIntroComp.java index a4f67f99..430c25e7 100644 --- a/app/src/main/java/io/xpipe/app/comp/storage/store/StoreIntroComp.java +++ b/app/src/main/java/io/xpipe/app/comp/storage/store/StoreIntroComp.java @@ -35,7 +35,7 @@ public class StoreIntroComp extends SimpleComp { }); var scanButton = new Button(AppI18n.get("detectConnections"), new FontIcon("mdi2m-magnify")); - scanButton.setOnAction(event -> ScanAlert.show(new LocalStore(), false)); + scanButton.setOnAction(event -> ScanAlert.showAsync(new LocalStore(), false)); var scanPane = new StackPane(scanButton); scanPane.setAlignment(Pos.CENTER); diff --git a/app/src/main/java/io/xpipe/app/comp/storage/store/StoreViewSection.java b/app/src/main/java/io/xpipe/app/comp/storage/store/StoreSection.java similarity index 69% rename from app/src/main/java/io/xpipe/app/comp/storage/store/StoreViewSection.java rename to app/src/main/java/io/xpipe/app/comp/storage/store/StoreSection.java index 17940a52..090f4e89 100644 --- a/app/src/main/java/io/xpipe/app/comp/storage/store/StoreViewSection.java +++ b/app/src/main/java/io/xpipe/app/comp/storage/store/StoreSection.java @@ -12,42 +12,42 @@ import java.time.Instant; import java.util.Comparator; @Value -public class StoreViewSection implements StorageFilter.Filterable { +public class StoreSection implements StorageFilter.Filterable { StoreEntryWrapper wrapper; - ObservableList children; + ObservableList children; - private static final Comparator COMPARATOR = Comparator.comparing( + private static final Comparator COMPARATOR = Comparator.comparing( o -> o.wrapper.getEntry().getState().equals(DataStoreEntry.State.COMPLETE_AND_VALID) ? o.wrapper.getEntry().getLastAccess() : Instant.EPOCH).reversed() .thenComparing( storeEntrySection -> storeEntrySection.wrapper.getEntry().getName()); - public static ObservableList createTopLevels() { + public static ObservableList createTopLevels() { + var topLevel = BindingsHelper.mappedContentBinding(StoreViewState.get().getAllEntries(), storeEntryWrapper -> create(storeEntryWrapper)); var filtered = - BindingsHelper.filteredContentBinding(StoreViewState.get().getAllEntries(), storeEntryWrapper -> { - if (!storeEntryWrapper.getEntry().getState().isUsable()) { + BindingsHelper.filteredContentBinding(topLevel, section -> { + if (!section.getWrapper().getEntry().getState().isUsable()) { return true; } - var parent = storeEntryWrapper + var parent = section.getWrapper() .getEntry() .getProvider() - .getParent(storeEntryWrapper.getEntry().getStore()); + .getParent(section.getWrapper().getEntry().getStore()); return parent == null || (DataStorage.get().getStoreEntryIfPresent(parent).isEmpty()); }); - var topLevel = BindingsHelper.mappedContentBinding(filtered, storeEntryWrapper -> create(storeEntryWrapper)); var ordered = BindingsHelper.orderedContentBinding( - topLevel, + filtered, COMPARATOR); return ordered; } - public static StoreViewSection create(StoreEntryWrapper e) { + private static StoreSection create(StoreEntryWrapper e) { if (!e.getEntry().getState().isUsable()) { - return new StoreViewSection(e, FXCollections.observableArrayList()); + return new StoreSection(e, FXCollections.observableArrayList()); } var filtered = BindingsHelper.filteredContentBinding( @@ -62,7 +62,7 @@ public class StoreViewSection implements StorageFilter.Filterable { var ordered = BindingsHelper.orderedContentBinding( children, COMPARATOR); - return new StoreViewSection(e, ordered); + return new StoreSection(e, ordered); } @Override diff --git a/app/src/main/java/io/xpipe/app/fxcomps/impl/DataStoreChoiceComp.java b/app/src/main/java/io/xpipe/app/fxcomps/impl/DataStoreChoiceComp.java index 6be8c656..3c7ed824 100644 --- a/app/src/main/java/io/xpipe/app/fxcomps/impl/DataStoreChoiceComp.java +++ b/app/src/main/java/io/xpipe/app/fxcomps/impl/DataStoreChoiceComp.java @@ -1,7 +1,6 @@ package io.xpipe.app.fxcomps.impl; -import io.xpipe.app.comp.storage.store.StoreEntryFlatMiniSection; -import io.xpipe.app.comp.storage.store.StoreEntryWrapper; +import io.xpipe.app.comp.storage.store.StoreEntryFlatMiniSectionComp; import io.xpipe.app.core.AppI18n; import io.xpipe.app.ext.DataStoreProviders; import io.xpipe.app.fxcomps.SimpleComp; @@ -19,7 +18,6 @@ import javafx.scene.control.Label; import javafx.scene.layout.Region; import lombok.AllArgsConstructor; -import java.util.Map; import java.util.Optional; import java.util.function.Predicate; @@ -82,25 +80,25 @@ public class DataStoreChoiceComp extends SimpleComp { @Override @SuppressWarnings("unchecked") protected Region createSimple() { - var map = StoreEntryFlatMiniSection.createMap(); + var list = StoreEntryFlatMiniSectionComp.ALL; var comboBox = new CustomComboBoxBuilder( selected, - t -> map.entrySet().stream() - .filter(e -> t.equals(e.getKey().getEntry().getStore())) + t -> list.stream() + .filter(e -> t.equals(e.getEntry().getStore())) .findFirst() .orElseThrow() - .getValue(), + .createRegion(), new Label(AppI18n.get("none")), n -> true); comboBox.setSelectedDisplay(t -> createGraphic(t)); comboBox.setUnknownNode(t -> createGraphic(t)); - for (Map.Entry e : map.entrySet()) { - if (e.getKey().getEntry().getStore() == self) { + for (var e : list) { + if (e.getEntry().getStore() == self) { continue; } - var s = e.getKey().getEntry().getStore(); + var s = e.getEntry().getStore(); if (!storeClass.isAssignableFrom(s.getClass()) || !applicableCheck.test((T) s)) { continue; } @@ -109,7 +107,7 @@ public class DataStoreChoiceComp extends SimpleComp { continue; } - comboBox.add((T) e.getKey().getEntry().getStore()); + comboBox.add((T) e.getEntry().getStore()); } ComboBox cb = comboBox.build(); diff --git a/app/src/main/java/io/xpipe/app/util/ScanAlert.java b/app/src/main/java/io/xpipe/app/util/ScanAlert.java index 464a12d2..7475d7b1 100644 --- a/app/src/main/java/io/xpipe/app/util/ScanAlert.java +++ b/app/src/main/java/io/xpipe/app/util/ScanAlert.java @@ -20,12 +20,14 @@ import java.util.List; public class ScanAlert { - public static void show(DataStore store, boolean automatic) { - if (store instanceof ShellStore) { - showForShellStore(store.asNeeded(), automatic); - } else { - showForOtherStore(store, automatic); - } + public static void showAsync(DataStore store, boolean automatic) { + ThreadHelper.runAsync(() -> { + if (store instanceof ShellStore) { + showForShellStore(store.asNeeded(), automatic); + } else { + showForOtherStore(store, automatic); + } + }); } private static void showForOtherStore(DataStore store, boolean automatic) {