From f6162db82ec94ea2990b4bd387641974b7894b69 Mon Sep 17 00:00:00 2001 From: Starlight220 <53231611+Starlight220@users.noreply.github.com> Date: Wed, 29 Mar 2023 14:57:57 +0300 Subject: [PATCH 1/3] add DataSource.preferredWidget --- .../wpi/first/shuffleboard/api/sources/DataSource.java | 10 ++++++++++ .../first/shuffleboard/app/WidgetPaneDragHandler.java | 6 ++++-- .../plugin/networktables/TabGenerator.java | 5 +++-- 3 files changed, 17 insertions(+), 4 deletions(-) diff --git a/api/src/main/java/edu/wpi/first/shuffleboard/api/sources/DataSource.java b/api/src/main/java/edu/wpi/first/shuffleboard/api/sources/DataSource.java index acf4a6b61..db316bbe6 100644 --- a/api/src/main/java/edu/wpi/first/shuffleboard/api/sources/DataSource.java +++ b/api/src/main/java/edu/wpi/first/shuffleboard/api/sources/DataSource.java @@ -7,6 +7,8 @@ import javafx.beans.property.Property; import javafx.beans.property.StringProperty; +import java.util.Optional; + /** * A data source provides some kind of data that widgets can display and manipulate. It can be * active or inactive; active sources may update at any time, while inactive sources are guaranteed @@ -161,4 +163,12 @@ default String getId() { */ void removeClient(Sourced client); + /** + * Preferred widget for the source. + * + * @return optionally a string identifier of the preferred widget type. + */ + default Optional preferredWidget() { + return Optional.empty(); + } } diff --git a/app/src/main/java/edu/wpi/first/shuffleboard/app/WidgetPaneDragHandler.java b/app/src/main/java/edu/wpi/first/shuffleboard/app/WidgetPaneDragHandler.java index f8cf19d0e..b43ea2ec9 100644 --- a/app/src/main/java/edu/wpi/first/shuffleboard/app/WidgetPaneDragHandler.java +++ b/app/src/main/java/edu/wpi/first/shuffleboard/app/WidgetPaneDragHandler.java @@ -140,7 +140,8 @@ private boolean previewSource(GridPoint point, Dragboard dragboard) { } SourceEntry entry = DeserializationHelper.sourceFromDrag(dragboard.getContent(DataFormats.source)); DataSource source = entry.get(); - Optional componentName = Components.getDefault().pickComponentNameFor(source.getDataType()); + Optional componentName = source.preferredWidget() + .or(() -> Components.getDefault().pickComponentNameFor(source.getDataType())); Optional> dummySource = DummySource.forTypes(source.getDataType()); if (componentName.isPresent() && dummySource.isPresent()) { if (tilePreviewSize == null) { @@ -290,7 +291,8 @@ private void handleDragDropped(DragEvent event) { * @param point the point to place the widget for the source */ private void dropSource(DataSource source, GridPoint point) { - Components.getDefault().pickComponentNameFor(source.getDataType()) + source.preferredWidget() + .or(() -> Components.getDefault().pickComponentNameFor(source.getDataType())) .flatMap(name -> Components.getDefault().createComponent(name, source)) .filter(widget -> pane.isOpen(point, pane.sizeOfWidget(widget), n -> widget.getView() == n)) .map(pane::addComponentToTile) diff --git a/plugins/networktables/src/main/java/edu/wpi/first/shuffleboard/plugin/networktables/TabGenerator.java b/plugins/networktables/src/main/java/edu/wpi/first/shuffleboard/plugin/networktables/TabGenerator.java index 48852314a..a8f09c94f 100644 --- a/plugins/networktables/src/main/java/edu/wpi/first/shuffleboard/plugin/networktables/TabGenerator.java +++ b/plugins/networktables/src/main/java/edu/wpi/first/shuffleboard/plugin/networktables/TabGenerator.java @@ -354,8 +354,9 @@ private void updateWidget(ParentModel parent, String path) { preferredComponent( path, sourceSupplier - .map(DataSource::getDataType) - .map(componentRegistry::defaultComponentNameFor) + .map(source -> source.preferredWidget() + .or(() -> componentRegistry.defaultComponentNameFor(source.getDataType())) + ) .map(Optional::orElseThrow) ), properties(path)); From 3eb0daa1c8503ce2c4e332899f0a1e429e2ebf8c Mon Sep 17 00:00:00 2001 From: Starlight220 <53231611+Starlight220@users.noreply.github.com> Date: Wed, 29 Mar 2023 15:07:44 +0300 Subject: [PATCH 2/3] implement DataSource.preferredWidget for NT sources --- .../plugin/networktables/TabGenerator.java | 22 ++++++++++++ .../sources/CompositeNetworkTableSource.java | 14 ++++++++ .../sources/SingleKeyNetworkTableSource.java | 34 +++++++++++++++++++ 3 files changed, 70 insertions(+) diff --git a/plugins/networktables/src/main/java/edu/wpi/first/shuffleboard/plugin/networktables/TabGenerator.java b/plugins/networktables/src/main/java/edu/wpi/first/shuffleboard/plugin/networktables/TabGenerator.java index a8f09c94f..433828ac2 100644 --- a/plugins/networktables/src/main/java/edu/wpi/first/shuffleboard/plugin/networktables/TabGenerator.java +++ b/plugins/networktables/src/main/java/edu/wpi/first/shuffleboard/plugin/networktables/TabGenerator.java @@ -1,5 +1,7 @@ package edu.wpi.first.shuffleboard.plugin.networktables; +import com.google.gson.JsonParser; +import com.google.gson.JsonPrimitive; import edu.wpi.first.shuffleboard.api.sources.DataSource; import edu.wpi.first.shuffleboard.api.sources.SourceTypes; import edu.wpi.first.shuffleboard.api.tab.model.ComponentModel; @@ -337,6 +339,26 @@ private Map properties(String realPath) { props.put(k, propsTable.getEntry(k).getValue().getValue()); } } + if (!inst.getTopic(realPath).exists()) { + var propsTable = inst.getTable(realPath); + for (String k : propsTable.getKeys()) { + props.put(k, propsTable.getEntry(k).getValue().getValue()); + } + } else { + String metadata = inst.getTopic(realPath).getProperties(); + JsonParser parser = new JsonParser(); + var obj = parser.parse(metadata).getAsJsonObject(); + obj.entrySet().forEach(entry -> { + JsonPrimitive primitive = entry.getValue().getAsJsonPrimitive(); + if (primitive.isBoolean()) { + props.put(entry.getKey(), primitive.getAsBoolean()); + } else if (primitive.isNumber()) { + props.put(entry.getKey(), primitive.getAsNumber()); + } else { + props.put(entry.getKey(), primitive.getAsString()); + } + }); + } return props; } diff --git a/plugins/networktables/src/main/java/edu/wpi/first/shuffleboard/plugin/networktables/sources/CompositeNetworkTableSource.java b/plugins/networktables/src/main/java/edu/wpi/first/shuffleboard/plugin/networktables/sources/CompositeNetworkTableSource.java index 1276908d0..d4bc5c72b 100644 --- a/plugins/networktables/src/main/java/edu/wpi/first/shuffleboard/plugin/networktables/sources/CompositeNetworkTableSource.java +++ b/plugins/networktables/src/main/java/edu/wpi/first/shuffleboard/plugin/networktables/sources/CompositeNetworkTableSource.java @@ -1,5 +1,6 @@ package edu.wpi.first.shuffleboard.plugin.networktables.sources; +import edu.wpi.first.networktables.NetworkTableValue; import edu.wpi.first.shuffleboard.api.data.ComplexData; import edu.wpi.first.shuffleboard.api.data.ComplexDataType; import edu.wpi.first.shuffleboard.api.data.IncompleteDataException; @@ -14,6 +15,7 @@ import java.util.HashMap; import java.util.Map; import java.util.Objects; +import java.util.Optional; import java.util.logging.Level; import java.util.logging.Logger; @@ -28,6 +30,8 @@ public class CompositeNetworkTableSource> extends Netwo private static final Logger log = Logger.getLogger(CompositeNetworkTableSource.class.getName()); + private Optional preferredWidget; + private final Map backingMap = new HashMap<>(); private final ComplexDataType dataType; @@ -44,6 +48,7 @@ public CompositeNetworkTableSource(String tableName, ComplexDataType dataType this.dataType = dataType; String path = NetworkTable.normalizeKey(tableName, false); NetworkTable table = NetworkTableInstance.getDefault().getTable(path); + preferredWidget = loadWidgetFromWidgetEntry(table); setData(dataType.getDefaultValue()); setTableListener((key, event) -> { @@ -91,4 +96,13 @@ public ComplexDataType getDataType() { protected boolean isSingular() { return false; } + + @Override + public Optional preferredWidget() { + return preferredWidget; + } + + private static Optional loadWidgetFromWidgetEntry(NetworkTable table) { + return Optional.ofNullable(table.getValue(".widget")).filter(NetworkTableValue::isString).map(NetworkTableValue::getString); + } } diff --git a/plugins/networktables/src/main/java/edu/wpi/first/shuffleboard/plugin/networktables/sources/SingleKeyNetworkTableSource.java b/plugins/networktables/src/main/java/edu/wpi/first/shuffleboard/plugin/networktables/sources/SingleKeyNetworkTableSource.java index d2951d39f..7b9d6a2b5 100644 --- a/plugins/networktables/src/main/java/edu/wpi/first/shuffleboard/plugin/networktables/sources/SingleKeyNetworkTableSource.java +++ b/plugins/networktables/src/main/java/edu/wpi/first/shuffleboard/plugin/networktables/sources/SingleKeyNetworkTableSource.java @@ -1,5 +1,10 @@ package edu.wpi.first.shuffleboard.plugin.networktables.sources; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.JsonParser; +import edu.wpi.first.networktables.NetworkTableEvent.Kind; +import edu.wpi.first.networktables.Topic; import edu.wpi.first.shuffleboard.api.data.DataType; import edu.wpi.first.shuffleboard.api.data.DataTypes; import edu.wpi.first.shuffleboard.api.sources.Sources; @@ -9,6 +14,8 @@ import edu.wpi.first.networktables.NetworkTableEntry; import edu.wpi.first.networktables.NetworkTableEvent; +import java.util.Optional; + /** * A data source backed by a single key-value pair in a network table. */ @@ -21,6 +28,8 @@ public class SingleKeyNetworkTableSource extends NetworkTableSource { */ private volatile boolean initialUpdate = true; + private Optional preferredWidget; + /** * Creates a single-key network table source backed by the value in the given table * associated with the given key. @@ -33,6 +42,7 @@ public class SingleKeyNetworkTableSource extends NetworkTableSource { public SingleKeyNetworkTableSource(NetworkTable table, String key, DataType dataType) { super(key, dataType); setName(key); + preferredWidget = loadWidgetFromTopicProps(table.getTopic(key)); setTableListener((__, event) -> { if (event.is(NetworkTableEvent.Kind.kUnpublish)) { setActive(false); @@ -49,6 +59,8 @@ public SingleKeyNetworkTableSource(NetworkTable table, String key, DataType data if (isActive()) { setData((T) value); } + } else if (event.is(Kind.kProperties)) { + preferredWidget = loadWidgetFromTopicProps(table.getTopic(key)); } }); @@ -83,4 +95,26 @@ public SingleKeyNetworkTableSource(NetworkTable table, String key, DataType data protected boolean isSingular() { return true; } + + @Override + public Optional preferredWidget() { + return preferredWidget; + } + + private static Optional loadWidgetFromTopicProps(Topic topic) { + String metadata = topic.getProperties(); + JsonParser parser = new JsonParser(); + try { + JsonObject obj = parser.parse(metadata).getAsJsonObject(); + JsonElement widgetProp = obj.get("widget"); + if (widgetProp == null || !widgetProp.isJsonPrimitive()) { + System.err.println("Metadata widget field for topic `" + topic.getName() + "` doesn't exist or isn't primitive!"); + return Optional.empty(); + } + return Optional.of(widgetProp.getAsString()); + } catch (Exception e) { + e.printStackTrace(); + return Optional.empty(); + } + } } From 806afc7627872328aaf798fa181bc96723868707 Mon Sep 17 00:00:00 2001 From: Starlight220 <53231611+Starlight220@users.noreply.github.com> Date: Wed, 29 Mar 2023 23:53:15 +0300 Subject: [PATCH 3/3] fmt --- .../networktables/sources/CompositeNetworkTableSource.java | 4 +++- .../networktables/sources/SingleKeyNetworkTableSource.java | 3 ++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/plugins/networktables/src/main/java/edu/wpi/first/shuffleboard/plugin/networktables/sources/CompositeNetworkTableSource.java b/plugins/networktables/src/main/java/edu/wpi/first/shuffleboard/plugin/networktables/sources/CompositeNetworkTableSource.java index d4bc5c72b..7a90cd880 100644 --- a/plugins/networktables/src/main/java/edu/wpi/first/shuffleboard/plugin/networktables/sources/CompositeNetworkTableSource.java +++ b/plugins/networktables/src/main/java/edu/wpi/first/shuffleboard/plugin/networktables/sources/CompositeNetworkTableSource.java @@ -103,6 +103,8 @@ public Optional preferredWidget() { } private static Optional loadWidgetFromWidgetEntry(NetworkTable table) { - return Optional.ofNullable(table.getValue(".widget")).filter(NetworkTableValue::isString).map(NetworkTableValue::getString); + return Optional.ofNullable(table.getValue(".widget")) + .filter(NetworkTableValue::isString) + .map(NetworkTableValue::getString); } } diff --git a/plugins/networktables/src/main/java/edu/wpi/first/shuffleboard/plugin/networktables/sources/SingleKeyNetworkTableSource.java b/plugins/networktables/src/main/java/edu/wpi/first/shuffleboard/plugin/networktables/sources/SingleKeyNetworkTableSource.java index 7b9d6a2b5..ca6e571ee 100644 --- a/plugins/networktables/src/main/java/edu/wpi/first/shuffleboard/plugin/networktables/sources/SingleKeyNetworkTableSource.java +++ b/plugins/networktables/src/main/java/edu/wpi/first/shuffleboard/plugin/networktables/sources/SingleKeyNetworkTableSource.java @@ -108,7 +108,8 @@ private static Optional loadWidgetFromTopicProps(Topic topic) { JsonObject obj = parser.parse(metadata).getAsJsonObject(); JsonElement widgetProp = obj.get("widget"); if (widgetProp == null || !widgetProp.isJsonPrimitive()) { - System.err.println("Metadata widget field for topic `" + topic.getName() + "` doesn't exist or isn't primitive!"); + System.err.println("Metadata widget field for topic `" + topic.getName() + + "` doesn't exist or isn't primitive!"); return Optional.empty(); } return Optional.of(widgetProp.getAsString());