Implement basic ordering

This commit is contained in:
crschnick 2024-05-28 12:05:22 +00:00
parent f3557bb715
commit 6f6b4a76d4
8 changed files with 170 additions and 43 deletions

View file

@ -108,6 +108,7 @@ run {
} }
workingDir = rootDir workingDir = rootDir
jvmArgs += ['-XX:+EnableDynamicAgentLoading']
} }
task runAttachedDebugger(type: JavaExec) { task runAttachedDebugger(type: JavaExec) {
@ -121,7 +122,7 @@ task runAttachedDebugger(type: JavaExec) {
"-javaagent:${System.getProperty("user.home")}/.attachme/attachme-agent-1.2.4.jar=port:7857,host:localhost".toString(), "-javaagent:${System.getProperty("user.home")}/.attachme/attachme-agent-1.2.4.jar=port:7857,host:localhost".toString(),
"-agentlib:jdwp=transport=dt_socket,server=y,suspend=y,address=127.0.0.1:0" "-agentlib:jdwp=transport=dt_socket,server=y,suspend=y,address=127.0.0.1:0"
) )
jvmArgs += '-XX:+EnableDynamicAgentLoading' jvmArgs += ['-XX:+EnableDynamicAgentLoading']
systemProperties run.systemProperties systemProperties run.systemProperties
} }

View file

@ -372,6 +372,14 @@ public abstract class StoreEntryComp extends SimpleComp {
contextMenu.getItems().add(new SeparatorMenuItem()); contextMenu.getItems().add(new SeparatorMenuItem());
} }
var notes = new MenuItem(AppI18n.get("addNotes"), new FontIcon("mdi2n-note-text"));
notes.setOnAction(event -> {
wrapper.getNotes().setValue(new StoreNotes(null, getDefaultNotes()));
event.consume();
});
notes.visibleProperty().bind(BindingsHelper.map(wrapper.getNotes(), s -> s.getCommited() == null));
contextMenu.getItems().add(notes);
if (AppPrefs.get().developerMode().getValue()) { if (AppPrefs.get().developerMode().getValue()) {
var browse = new MenuItem(AppI18n.get("browseInternalStorage"), new FontIcon("mdi2f-folder-open-outline")); var browse = new MenuItem(AppI18n.get("browseInternalStorage"), new FontIcon("mdi2f-folder-open-outline"));
browse.setOnAction( browse.setOnAction(
@ -379,6 +387,25 @@ public abstract class StoreEntryComp extends SimpleComp {
contextMenu.getItems().add(browse); contextMenu.getItems().add(browse);
} }
if (DataStorage.get().isRootEntry(wrapper.getEntry())) {
var color = new Menu(AppI18n.get("color"), new FontIcon("mdi2f-format-color-fill"));
var none = new MenuItem("None");
none.setOnAction(event -> {
wrapper.getEntry().setColor(null);
event.consume();
});
color.getItems().add(none);
Arrays.stream(DataStoreColor.values()).forEach(dataStoreColor -> {
MenuItem m = new MenuItem(DataStoreFormatter.capitalize(dataStoreColor.getId()));
m.setOnAction(event -> {
wrapper.getEntry().setColor(dataStoreColor);
event.consume();
});
color.getItems().add(m);
});
contextMenu.getItems().add(color);
}
if (wrapper.getEntry().getProvider() != null) { if (wrapper.getEntry().getProvider() != null) {
var move = new Menu(AppI18n.get("moveTo"), new FontIcon("mdi2f-folder-move-outline")); var move = new Menu(AppI18n.get("moveTo"), new FontIcon("mdi2f-folder-move-outline"));
StoreViewState.get() StoreViewState.get()
@ -399,32 +426,45 @@ public abstract class StoreEntryComp extends SimpleComp {
contextMenu.getItems().add(move); contextMenu.getItems().add(move);
} }
if (DataStorage.get().isRootEntry(wrapper.getEntry())) { var order = new Menu(AppI18n.get("order"), new FontIcon("mdal-bookmarks"));
var color = new Menu(AppI18n.get("color"), new FontIcon("mdi2f-format-color-fill")); var noOrder = new MenuItem("None");
var none = new MenuItem("None"); noOrder.setOnAction(event -> {
none.setOnAction(event -> { DataStorage.get().orderBefore(wrapper.getEntry(), null);
wrapper.getEntry().setColor(null);
event.consume();
});
color.getItems().add(none);
Arrays.stream(DataStoreColor.values()).forEach(dataStoreColor -> {
MenuItem m = new MenuItem(DataStoreFormatter.capitalize(dataStoreColor.getId()));
m.setOnAction(event -> {
wrapper.getEntry().setColor(dataStoreColor);
event.consume();
});
color.getItems().add(m);
});
contextMenu.getItems().add(color);
}
var notes = new MenuItem(AppI18n.get("addNotes"), new FontIcon("mdi2n-note-text"));
notes.setOnAction(event -> {
wrapper.getNotes().setValue(new StoreNotes(null, getDefaultNotes()));
event.consume(); event.consume();
}); });
notes.visibleProperty().bind(BindingsHelper.map(wrapper.getNotes(), s -> s.getCommited() == null)); if (wrapper.getEntry().getOrderBefore() == null) {
contextMenu.getItems().add(notes); noOrder.setDisable(true);
}
order.getItems().add(noOrder);
var stick = new MenuItem(AppI18n.get("stickToTop"));
stick.setOnAction(event -> {
DataStorage.get().orderBefore(wrapper.getEntry(), wrapper.getEntry());
event.consume();
});
if (wrapper.getEntry().getUuid().equals(wrapper.getEntry().getOrderBefore())) {
stick.setDisable(true);
}
order.getItems().add(stick);
order.getItems().add(new SeparatorMenuItem());
var section = StoreViewState.get().getParentSectionForWrapper(wrapper);
section.get().getAllChildren().forEach(other -> {
var ow = other.getWrapper();
var op = ow.getEntry().getProvider();
MenuItem m = new MenuItem(ow.getName().getValue(),
op != null ? PrettyImageHelper.ofFixedSizeSquare(op.getDisplayIconFileName(ow.getEntry().getStore()),
16).createRegion() : null);
if (ow.getEntry().getUuid().equals(wrapper.getEntry().getOrderBefore())) {
m.setDisable(true);
}
m.setOnAction(event -> {
wrapper.orderBefore(ow);
event.consume();
});
order.getItems().add(m);
});
contextMenu.getItems().add(order);
contextMenu.getItems().add(new SeparatorMenuItem());
var del = new MenuItem(AppI18n.get("remove"), new FontIcon("mdal-delete_outline")); var del = new MenuItem(AppI18n.get("remove"), new FontIcon("mdal-delete_outline"));
del.disableProperty() del.disableProperty()

View file

@ -71,6 +71,12 @@ public class StoreEntryWrapper {
}); });
} }
public void orderBefore(StoreEntryWrapper other) {
ThreadHelper.runAsync(() -> {
DataStorage.get().orderBefore(getEntry(),other.getEntry());
});
}
public boolean isInStorage() { public boolean isInStorage() {
return DataStorage.get().getStoreEntries().contains(entry); return DataStorage.get().getStoreEntries().contains(entry);
} }

View file

@ -65,8 +65,32 @@ public class StoreSection {
return list; return list;
} }
var c = Comparator.<StoreSection>comparingInt( var explicitOrderComp = new Comparator<StoreSection>() {
@Override
public int compare(StoreSection o1, StoreSection o2) {
var explicit1 = o1.getWrapper().getEntry().getOrderBefore();
var explicit2 = o2.getWrapper().getEntry().getOrderBefore();
if (explicit1 == null && explicit2 == null) {
return 0;
}
if (explicit1 != null && explicit2 == null) {
return -1;
}
if (explicit2 != null && explicit1 == null) {
return 1;
}
if (explicit1.equals(o2.getWrapper().getEntry().getUuid())) {
return -1;
}
if (explicit2.equals(o1.getWrapper().getEntry().getUuid())) {
return -1;
}
return 0;
}
};
var usableComp = Comparator.<StoreSection>comparingInt(
value -> value.getWrapper().getEntry().getValidity().isUsable() ? -1 : 1); value -> value.getWrapper().getEntry().getValidity().isUsable() ? -1 : 1);
var comp = explicitOrderComp.thenComparing(usableComp);
var mappedSortMode = BindingsHelper.flatMap( var mappedSortMode = BindingsHelper.flatMap(
category, category,
storeCategoryWrapper -> storeCategoryWrapper != null ? storeCategoryWrapper.getSortMode() : null); storeCategoryWrapper -> storeCategoryWrapper != null ? storeCategoryWrapper.getSortMode() : null);
@ -75,10 +99,10 @@ public class StoreSection {
(o1, o2) -> { (o1, o2) -> {
var current = mappedSortMode.getValue(); var current = mappedSortMode.getValue();
if (current != null) { if (current != null) {
return c.thenComparing(current.comparator()) return comp.thenComparing(current.comparator())
.compare(current.representative(o1), current.representative(o2)); .compare(current.representative(o1), current.representative(o2));
} else { } else {
return c.compare(o1, o2); return comp.compare(o1, o2);
} }
}, },
mappedSortMode); mappedSortMode);

View file

@ -240,6 +240,23 @@ public class StoreViewState {
}); });
} }
public Optional<StoreSection> getParentSectionForWrapper(StoreEntryWrapper wrapper) {
StoreSection current = getCurrentTopLevelSection();
while (true) {
var child = current.getAllChildren().stream().filter(section -> section.getWrapper().equals(wrapper)).findFirst();
if (child.isPresent()) {
return Optional.of(current);
}
var traverse = current.getAllChildren().stream().filter(section -> section.anyMatches(w -> w.equals(wrapper))).findFirst();
if (traverse.isPresent()) {
current = traverse.get();
} else {
return Optional.empty();
}
}
}
public ObservableList<StoreCategoryWrapper> getSortedCategories(StoreCategoryWrapper root) { public ObservableList<StoreCategoryWrapper> getSortedCategories(StoreCategoryWrapper root) {
Comparator<StoreCategoryWrapper> comparator = new Comparator<>() { Comparator<StoreCategoryWrapper> comparator = new Comparator<>() {
@Override @Override

View file

@ -329,17 +329,26 @@ public abstract class DataStorage {
} }
var children = getDeepStoreChildren(entry); var children = getDeepStoreChildren(entry);
var toRemove = Stream.concat(Stream.of(entry), children.stream()).toArray(DataStoreEntry[]::new); var arr = Stream.concat(Stream.of(entry), children.stream()).toArray(DataStoreEntry[]::new);
listeners.forEach(storageListener -> storageListener.onStoreRemove(toRemove)); listeners.forEach(storageListener -> storageListener.onStoreRemove(arr));
entry.setCategoryUuid(newCategory.getUuid()); entry.setCategoryUuid(newCategory.getUuid());
children.forEach(child -> child.setCategoryUuid(newCategory.getUuid())); children.forEach(child -> child.setCategoryUuid(newCategory.getUuid()));
var toAdd = Stream.concat(Stream.of(entry), children.stream()).toArray(DataStoreEntry[]::new); listeners.forEach(storageListener -> storageListener.onStoreAdd(arr));
listeners.forEach(storageListener -> storageListener.onStoreAdd(toAdd));
saveAsync(); saveAsync();
} }
public void orderBefore(DataStoreEntry entry, DataStoreEntry reference) {
var children = getDeepStoreChildren(entry);
var arr = Stream.concat(Stream.of(entry), children.stream()).toArray(DataStoreEntry[]::new);
listeners.forEach(storageListener -> storageListener.onStoreRemove(arr));
entry.setOrderBefore(reference != null ? reference.getUuid() : null);
listeners.forEach(storageListener -> storageListener.onStoreAdd(arr));
}
public boolean refreshChildren(DataStoreEntry e) { public boolean refreshChildren(DataStoreEntry e) {
if (!(e.getStore() instanceof FixedHierarchyStore)) { if (!(e.getStore() instanceof FixedHierarchyStore)) {
return false; return false;
@ -439,7 +448,7 @@ public abstract class DataStorage {
pair.getKey().setStoreInternal(merged, false); pair.getKey().setStoreInternal(merged, false);
} }
var mergedState = pair.getKey().getStorePersistentState().deepCopy(); var mergedState = pair.getKey().getStorePersistentState().copy();
mergedState.merge(pair.getValue().get().getStorePersistentState()); mergedState.merge(pair.getValue().get().getStorePersistentState());
pair.getKey().setStorePersistentState(mergedState); pair.getKey().setStorePersistentState(mergedState);
} }
@ -788,9 +797,7 @@ public abstract class DataStorage {
public Optional<DataStoreEntry> getStoreEntryIfPresent(@NonNull DataStore store, boolean identityOnly) { public Optional<DataStoreEntry> getStoreEntryIfPresent(@NonNull DataStore store, boolean identityOnly) {
return storeEntriesSet.stream() return storeEntriesSet.stream()
.filter(n -> n.getStore() == store .filter(n -> n.getStore() == store || (!identityOnly && (n.getStore() != null
|| (!identityOnly
&& (n.getStore() != null
&& Objects.equals( && Objects.equals(
store.getClass(), n.getStore().getClass()) store.getClass(), n.getStore().getClass())
&& store.equals(n.getStore())))) && store.equals(n.getStore()))))

View file

@ -72,6 +72,9 @@ public class DataStoreEntry extends StorageElement {
@NonFinal @NonFinal
String notes; String notes;
@NonFinal
UUID orderBefore;
private DataStoreEntry( private DataStoreEntry(
Path directory, Path directory,
UUID uuid, UUID uuid,
@ -86,7 +89,8 @@ public class DataStoreEntry extends StorageElement {
JsonNode storePersistentState, JsonNode storePersistentState,
boolean expanded, boolean expanded,
DataStoreColor color, DataStoreColor color,
String notes) { String notes, UUID orderBefore
) {
super(directory, uuid, name, lastUsed, lastModified, dirty); super(directory, uuid, name, lastUsed, lastModified, dirty);
this.categoryUuid = categoryUuid; this.categoryUuid = categoryUuid;
this.store = DataStorageParser.storeFromNode(storeNode); this.store = DataStorageParser.storeFromNode(storeNode);
@ -95,6 +99,7 @@ public class DataStoreEntry extends StorageElement {
this.configuration = configuration; this.configuration = configuration;
this.expanded = expanded; this.expanded = expanded;
this.color = color; this.color = color;
this.orderBefore = orderBefore;
this.provider = store != null this.provider = store != null
? DataStoreProviders.byStoreClass(store.getClass()).orElse(null) ? DataStoreProviders.byStoreClass(store.getClass()).orElse(null)
: null; : null;
@ -109,10 +114,12 @@ public class DataStoreEntry extends StorageElement {
String name, String name,
Instant lastUsed, Instant lastUsed,
Instant lastModified, Instant lastModified,
DataStore store) { DataStore store, UUID orderBefore
) {
super(directory, uuid, name, lastUsed, lastModified, false); super(directory, uuid, name, lastUsed, lastModified, false);
this.categoryUuid = categoryUuid; this.categoryUuid = categoryUuid;
this.store = store; this.store = store;
this.orderBefore = orderBefore;
this.storeNode = null; this.storeNode = null;
this.validity = Validity.INCOMPLETE; this.validity = Validity.INCOMPLETE;
this.configuration = Configuration.defaultConfiguration(); this.configuration = Configuration.defaultConfiguration();
@ -130,7 +137,8 @@ public class DataStoreEntry extends StorageElement {
UUID.randomUUID().toString(), UUID.randomUUID().toString(),
Instant.now(), Instant.now(),
Instant.now(), Instant.now(),
store); store,
null);
} }
public static DataStoreEntry createNew(@NonNull String name, @NonNull DataStore store) { public static DataStoreEntry createNew(@NonNull String name, @NonNull DataStore store) {
@ -159,6 +167,7 @@ public class DataStoreEntry extends StorageElement {
null, null,
false, false,
null, null,
null,
null); null);
return entry; return entry;
} }
@ -176,7 +185,8 @@ public class DataStoreEntry extends StorageElement {
JsonNode storePersistentState, JsonNode storePersistentState,
boolean expanded, boolean expanded,
DataStoreColor color, DataStoreColor color,
String notes) { String notes,
UUID orderBeforeEntry) {
return new DataStoreEntry( return new DataStoreEntry(
directory, directory,
uuid, uuid,
@ -191,7 +201,8 @@ public class DataStoreEntry extends StorageElement {
storePersistentState, storePersistentState,
expanded, expanded,
color, color,
notes); notes,
orderBeforeEntry);
} }
public static Optional<DataStoreEntry> fromDirectory(Path dir) throws Exception { public static Optional<DataStoreEntry> fromDirectory(Path dir) throws Exception {
@ -226,6 +237,15 @@ public class DataStoreEntry extends StorageElement {
.map(jsonNode -> jsonNode.textValue()) .map(jsonNode -> jsonNode.textValue())
.map(Instant::parse) .map(Instant::parse)
.orElse(Instant.EPOCH); .orElse(Instant.EPOCH);
var order = Optional.ofNullable(stateJson.get("orderBefore"))
.map(node -> {
try {
return mapper.treeToValue(node, UUID.class);
} catch (JsonProcessingException e) {
return null;
}
})
.orElse(null);
var configuration = Optional.ofNullable(json.get("configuration")) var configuration = Optional.ofNullable(json.get("configuration"))
.map(node -> { .map(node -> {
try { try {
@ -275,10 +295,19 @@ public class DataStoreEntry extends StorageElement {
persistentState, persistentState,
expanded, expanded,
color, color,
notes notes,
order
)); ));
} }
public void setOrderBefore(UUID uuid) {
var changed = !Objects.equals(orderBefore, uuid);
this.orderBefore = uuid;
if (changed) {
notifyUpdate(false, true);
}
}
@Override @Override
public int hashCode() { public int hashCode() {
return getUuid().hashCode(); return getUuid().hashCode();
@ -330,7 +359,7 @@ public class DataStoreEntry extends StorageElement {
storePersistentStateNode = JacksonMapper.getDefault().valueToTree(storePersistentState); storePersistentStateNode = JacksonMapper.getDefault().valueToTree(storePersistentState);
} }
} }
return (T) sds.getStateClass().cast(storePersistentState); return (T) storePersistentState;
} }
public void setStorePersistentState(DataStoreState value) { public void setStorePersistentState(DataStoreState value) {
@ -379,6 +408,7 @@ public class DataStoreEntry extends StorageElement {
stateObj.set("persistentState", storePersistentStateNode); stateObj.set("persistentState", storePersistentStateNode);
obj.set("configuration", mapper.valueToTree(configuration)); obj.set("configuration", mapper.valueToTree(configuration));
stateObj.put("expanded", expanded); stateObj.put("expanded", expanded);
stateObj.put("orderBefore", orderBefore.toString());
var entryString = mapper.writeValueAsString(obj); var entryString = mapper.writeValueAsString(obj);
var stateString = mapper.writeValueAsString(stateObj); var stateString = mapper.writeValueAsString(stateObj);

View file

@ -454,3 +454,5 @@ history=Browsing history
skipAll=Skip all skipAll=Skip all
notes=Notes notes=Notes
addNotes=Add notes addNotes=Add notes
#context: verb
order=Order ...