Fix file browser connection list not updating

This commit is contained in:
crschnick 2023-05-03 16:08:01 +00:00
parent 758f721690
commit c1886cc9cd
9 changed files with 89 additions and 91 deletions

View file

@ -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<StoreEntryWrapper, Region> 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) {

View file

@ -109,7 +109,7 @@ public class GuiDsStoreCreator extends MultiStepComp.Step<CompStructure<?>> {
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();
}

View file

@ -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<StoreEntryFlatMiniSectionComp> ALL = FXCollections.observableArrayList();
static {
var topLevel = StoreSection.createTopLevels();
topLevel.addListener((ListChangeListener<? super StoreSection>) 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<StoreEntryWrapper, Region> createMap() {
var map = new LinkedHashMap<StoreEntryWrapper, Region>();
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<StoreEntryWrapper, Region> 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);
}
}

View file

@ -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);
}

View file

@ -16,12 +16,10 @@ import java.util.List;
public class StoreEntrySection extends Comp<CompStructure<VBox>> {
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<CompStructure<VBox>> {
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))));

View file

@ -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);

View file

@ -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<StoreViewSection> children;
ObservableList<StoreSection> children;
private static final Comparator<StoreViewSection> COMPARATOR = Comparator.<StoreViewSection, Instant>comparing(
private static final Comparator<StoreSection> COMPARATOR = Comparator.<StoreSection, Instant>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<StoreViewSection> createTopLevels() {
public static ObservableList<StoreSection> 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

View file

@ -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<T extends DataStore> extends SimpleComp {
@Override
@SuppressWarnings("unchecked")
protected Region createSimple() {
var map = StoreEntryFlatMiniSection.createMap();
var list = StoreEntryFlatMiniSectionComp.ALL;
var comboBox = new CustomComboBoxBuilder<T>(
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<StoreEntryWrapper, Region> 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<T extends DataStore> extends SimpleComp {
continue;
}
comboBox.add((T) e.getKey().getEntry().getStore());
comboBox.add((T) e.getEntry().getStore());
}
ComboBox<Node> cb = comboBox.build();

View file

@ -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) {