From a852a60fd4384f8dc7bc9eb7caa0b9785c24c191 Mon Sep 17 00:00:00 2001 From: "Blake J. Harnden" Date: Mon, 24 Sep 2018 09:50:26 -0700 Subject: [PATCH] (rest) - fixed editing link api (gui) - added link update in link details panel --- corefx/src/main/java/com/core/Controller.java | 2 +- .../java/com/core/client/ICoreClient.java | 2 + .../com/core/client/rest/CoreRestClient.java | 6 ++ .../src/main/java/com/core/data/CoreLink.java | 1 + .../main/java/com/core/ui/LinkDetails.java | 100 ++++++++++++++++-- .../main/java/com/core/ui/NodeDetails.java | 38 ++++--- .../com/core/ui/textfields/DoubleFilter.java | 15 +++ corefx/src/main/resources/css/main.css | 18 ++-- .../src/main/resources/fxml/link_details.fxml | 2 +- .../src/main/resources/fxml/node_details.fxml | 2 +- daemon/core/emulator/coreemu.py | 6 ++ webapp/link_routes.py | 12 +-- 12 files changed, 161 insertions(+), 43 deletions(-) create mode 100644 corefx/src/main/java/com/core/ui/textfields/DoubleFilter.java diff --git a/corefx/src/main/java/com/core/Controller.java b/corefx/src/main/java/com/core/Controller.java index fc6e6a93..37487f0f 100644 --- a/corefx/src/main/java/com/core/Controller.java +++ b/corefx/src/main/java/com/core/Controller.java @@ -63,7 +63,7 @@ public class Controller implements Initializable { private NetworkGraph networkGraph = new NetworkGraph(this); private AnnotationToolbar annotationToolbar = new AnnotationToolbar(networkGraph); private NodeDetails nodeDetails = new NodeDetails(this); - private LinkDetails linkDetails = new LinkDetails(networkGraph); + private LinkDetails linkDetails = new LinkDetails(this); private GraphToolbar graphToolbar = new GraphToolbar(this); private MobilityPlayer mobilityPlayer = new MobilityPlayer(this); diff --git a/corefx/src/main/java/com/core/client/ICoreClient.java b/corefx/src/main/java/com/core/client/ICoreClient.java index 1e8796f7..335d107f 100644 --- a/corefx/src/main/java/com/core/client/ICoreClient.java +++ b/corefx/src/main/java/com/core/client/ICoreClient.java @@ -64,6 +64,8 @@ public interface ICoreClient { boolean createLink(CoreLink link) throws IOException; + boolean editLink(CoreLink link) throws IOException; + boolean createHook(Hook hook) throws IOException; GetHooks getHooks() throws IOException; diff --git a/corefx/src/main/java/com/core/client/rest/CoreRestClient.java b/corefx/src/main/java/com/core/client/rest/CoreRestClient.java index 651e555c..08ad19d5 100644 --- a/corefx/src/main/java/com/core/client/rest/CoreRestClient.java +++ b/corefx/src/main/java/com/core/client/rest/CoreRestClient.java @@ -345,6 +345,12 @@ public class CoreRestClient implements ICoreClient { return WebUtils.postJson(url, link); } + @Override + public boolean editLink(CoreLink link) throws IOException { + String url = getUrl(String.format("sessions/%s/links", sessionId)); + return WebUtils.putJson(url, link); + } + @Override public boolean createHook(Hook hook) throws IOException { String url = getUrl(String.format("sessions/%s/hooks", sessionId)); diff --git a/corefx/src/main/java/com/core/data/CoreLink.java b/corefx/src/main/java/com/core/data/CoreLink.java index 67c2f8a5..99a284a2 100644 --- a/corefx/src/main/java/com/core/data/CoreLink.java +++ b/corefx/src/main/java/com/core/data/CoreLink.java @@ -12,6 +12,7 @@ import lombok.NoArgsConstructor; public class CoreLink { @EqualsAndHashCode.Include private Integer id; + @JsonIgnore private Float weight = 1.0f; @JsonIgnore diff --git a/corefx/src/main/java/com/core/ui/LinkDetails.java b/corefx/src/main/java/com/core/ui/LinkDetails.java index e70a462e..5a0c78d0 100644 --- a/corefx/src/main/java/com/core/ui/LinkDetails.java +++ b/corefx/src/main/java/com/core/ui/LinkDetails.java @@ -1,34 +1,49 @@ package com.core.ui; +import com.core.Controller; +import com.core.client.ICoreClient; import com.core.data.CoreInterface; import com.core.data.CoreLink; +import com.core.data.CoreLinkOptions; import com.core.data.CoreNode; import com.core.graph.NetworkGraph; +import com.core.ui.textfields.DoubleFilter; import com.core.utils.FxmlUtils; +import com.jfoenix.controls.JFXButton; import com.jfoenix.controls.JFXTextField; +import javafx.event.ActionEvent; +import javafx.event.EventHandler; import javafx.fxml.FXML; import javafx.geometry.Insets; import javafx.geometry.Orientation; import javafx.scene.control.Label; import javafx.scene.control.ScrollPane; import javafx.scene.control.Separator; +import javafx.scene.control.TextFormatter; import javafx.scene.layout.GridPane; +import javafx.util.converter.DoubleStringConverter; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; +import java.io.IOException; + public class LinkDetails extends ScrollPane { private static final Logger logger = LogManager.getLogger(); private static final int START_INDEX = 1; - private NetworkGraph graph; + private final Controller controller; private int index = START_INDEX; @FXML private GridPane gridPane; - public LinkDetails(NetworkGraph graph) { - this.graph = graph; + public LinkDetails(Controller controller) { + this.controller = controller; FxmlUtils.loadRootController(this, "/fxml/link_details.fxml"); + setPrefWidth(400); } public void setLink(CoreLink link) { + NetworkGraph graph = controller.getNetworkGraph(); + ICoreClient coreClient = controller.getCoreClient(); + clear(); addSeparator(); @@ -38,19 +53,68 @@ public class LinkDetails extends ScrollPane { if (interfaceOne != null) { addInterface(interfaceOne); } - addSeparator(); + addSeparator(); CoreNode nodeTwo = graph.getVertex(link.getNodeTwo()); CoreInterface interfaceTwo = link.getInterfaceTwo(); addLabel(nodeTwo.getName()); if (interfaceTwo != null) { addInterface(interfaceTwo); } + + addSeparator(); + addLabel("Properties"); + JFXTextField bandwidthField = addRow("Bandwidth (bps)", link.getOptions().getBandwidth()); + JFXTextField delayField = addRow("Delay (us)", link.getOptions().getDelay()); + JFXTextField jitterField = addRow("Jitter (us)", link.getOptions().getJitter()); + JFXTextField lossField = addRow("Loss (%)", link.getOptions().getPer()); + JFXTextField dupsField = addRow("Duplicate (%)", link.getOptions().getDup()); + addButton("Update", event -> { + CoreLinkOptions options = link.getOptions(); + options.setBandwidth(getDouble(bandwidthField)); + options.setDelay(getDouble(delayField)); + options.setJitter(getDouble(jitterField)); + options.setPer(getDouble(lossField)); + options.setDup(getDouble(dupsField)); + + if (coreClient.isRunning()) { + try { + coreClient.editLink(link); + Toast.info("Link updated!"); + } catch (IOException ex) { + Toast.error("Failure to update link", ex); + } + } + }); + } + + private Double getDouble(JFXTextField textField) { + if (textField.getText() == null) { + return null; + } + + Double value = null; + try { + logger.info("double field text: {}", textField.getText()); + value = Double.parseDouble(textField.getText()); + } catch (NumberFormatException ex) { + logger.error("error getting double value", ex); + } + return value; + } + + private void addButton(String text, EventHandler handler) { + JFXButton button = new JFXButton(text); + button.getStyleClass().add("core-button"); + button.setMaxWidth(Double.MAX_VALUE); + button.setOnAction(handler); + gridPane.add(button, 0, index++, 2, 1); + GridPane.setMargin(button, new Insets(10, 0, 0, 0)); } private void addLabel(String text) { Label label = new Label(text); - label.getStyleClass().add("details-title"); + label.getStyleClass().add("details-label"); gridPane.add(label, 0, index++, 2, 1); } @@ -61,32 +125,48 @@ public class LinkDetails extends ScrollPane { } private void addInterface(CoreInterface coreInterface) { - addRow("Interface", coreInterface.getName()); + addRow("Interface", coreInterface.getName(), true); if (coreInterface.getMac() != null) { - addRow("MAC", coreInterface.getMac()); + addRow("MAC", coreInterface.getMac(), true); } addIp4Address(coreInterface.getIp4(), coreInterface.getIp4Mask()); addIp6Address(coreInterface.getIp6(), coreInterface.getIp6Mask()); } - private void addRow(String labelText, String value) { + private void addRow(String labelText, String value, boolean disabled) { Label label = new Label(labelText); JFXTextField textField = new JFXTextField(value); + textField.setDisable(disabled); gridPane.addRow(index++, label, textField); } + private JFXTextField addRow(String labelText, Double value) { + Label label = new Label(labelText); + String doubleString = null; + if (value != null) { + doubleString = value.toString(); + } + JFXTextField textField = new JFXTextField(); + TextFormatter formatter = new TextFormatter<>( + new DoubleStringConverter(), null, new DoubleFilter()); + textField.setTextFormatter(formatter); + textField.setText(doubleString); + gridPane.addRow(index++, label, textField); + return textField; + } + private void addIp4Address(String ip, Integer mask) { if (ip == null) { return; } - addRow("IP4", String.format("%s/%s", ip, mask)); + addRow("IP4", String.format("%s/%s", ip, mask), true); } private void addIp6Address(String ip, String mask) { if (ip == null) { return; } - addRow("IP6", String.format("%s/%s", ip, mask)); + addRow("IP6", String.format("%s/%s", ip, mask), true); } private void clear() { diff --git a/corefx/src/main/java/com/core/ui/NodeDetails.java b/corefx/src/main/java/com/core/ui/NodeDetails.java index 0c4efcea..fa3059dd 100644 --- a/corefx/src/main/java/com/core/ui/NodeDetails.java +++ b/corefx/src/main/java/com/core/ui/NodeDetails.java @@ -26,6 +26,7 @@ public class NodeDetails extends ScrollPane { private static final Logger logger = LogManager.getLogger(); private static final int START_INDEX = 1; private final Controller controller; + @FXML private Label title; @FXML private ScrollPane scrollPane; @FXML private GridPane gridPane; private int index = START_INDEX; @@ -33,32 +34,36 @@ public class NodeDetails extends ScrollPane { public NodeDetails(Controller controller) { this.controller = controller; FxmlUtils.loadRootController(this, "/fxml/node_details.fxml"); - setPrefWidth(500); + setPrefWidth(400); } public void setNode(CoreNode node) { clear(); - addSeparator(); + title.setText(node.getName()); - addRow("Name", node.getName()); + addSeparator(); + addLabel("Properties"); if (node.getType() == NodeType.DEFAULT) { - addRow("Model", node.getModel()); + addRow("Model", node.getModel(), true); } else { - addRow("Type", node.getNodeType().getDisplay()); + addRow("Type", node.getNodeType().getDisplay(), true); } + if (node.getEmane() != null) { - addRow("EMANE", node.getEmane()); + addRow("EMANE", node.getEmane(), true); } addSeparator(); - + addLabel("Position"); if (node.getPosition().getX() != null) { - addRow("X", node.getPosition().getX().toString()); + addRow("X", node.getPosition().getX().toString(), true); } if (node.getPosition().getY() != null) { - addRow("Y", node.getPosition().getY().toString()); + addRow("Y", node.getPosition().getY().toString(), true); } + addSeparator(); + addLabel("Interfaces"); for (CoreLink link : controller.getNetworkGraph().getGraph().getIncidentEdges(node)) { CoreNode linkedNode; CoreInterface coreInterface; @@ -121,7 +126,7 @@ public class NodeDetails extends ScrollPane { private void addLabel(String text) { Label label = new Label(text); - label.getStyleClass().add("details-title"); + label.getStyleClass().add("details-label"); gridPane.add(label, 0, index++, 2, 1); } @@ -132,18 +137,19 @@ public class NodeDetails extends ScrollPane { } private void addInterface(CoreInterface coreInterface, CoreNode linkedNode) { - addRow("Linked To", linkedNode.getName()); - addRow("Interface", coreInterface.getName()); + addRow("Linked To", linkedNode.getName(), true); + addRow("Interface", coreInterface.getName(), true); if (coreInterface.getMac() != null) { - addRow("MAC", coreInterface.getMac()); + addRow("MAC", coreInterface.getMac(), true); } addIp4Address(coreInterface.getIp4(), coreInterface.getIp4Mask()); addIp6Address(coreInterface.getIp6(), coreInterface.getIp6Mask()); } - private void addRow(String labelText, String value) { + private void addRow(String labelText, String value, boolean disabled) { Label label = new Label(labelText); JFXTextField textField = new JFXTextField(value); + textField.setDisable(disabled); gridPane.addRow(index++, label, textField); } @@ -151,14 +157,14 @@ public class NodeDetails extends ScrollPane { if (ip == null) { return; } - addRow("IP4", String.format("%s/%s", ip, mask)); + addRow("IP4", String.format("%s/%s", ip, mask), true); } private void addIp6Address(String ip, String mask) { if (ip == null) { return; } - addRow("IP6", String.format("%s/%s", ip, mask)); + addRow("IP6", String.format("%s/%s", ip, mask), true); } private void clear() { diff --git a/corefx/src/main/java/com/core/ui/textfields/DoubleFilter.java b/corefx/src/main/java/com/core/ui/textfields/DoubleFilter.java new file mode 100644 index 00000000..c9e1ee36 --- /dev/null +++ b/corefx/src/main/java/com/core/ui/textfields/DoubleFilter.java @@ -0,0 +1,15 @@ +package com.core.ui.textfields; + +import javafx.scene.control.TextFormatter; + +import java.util.function.UnaryOperator; +import java.util.regex.Pattern; + +public class DoubleFilter implements UnaryOperator { + private static final Pattern DIGIT_PATTERN = Pattern.compile("\\d*\\.?\\d*"); + + @Override + public TextFormatter.Change apply(TextFormatter.Change change) { + return DIGIT_PATTERN.matcher(change.getText()).matches() ? change : null; + } +} diff --git a/corefx/src/main/resources/css/main.css b/corefx/src/main/resources/css/main.css index 91886483..f7585fd4 100644 --- a/corefx/src/main/resources/css/main.css +++ b/corefx/src/main/resources/css/main.css @@ -12,6 +12,15 @@ } .details-label { + -fx-background-color: slategrey; + -fx-pref-width: Infinity; + -fx-text-fill: white; + -fx-alignment: center; + -fx-padding: 5; + -fx-background-radius: 5; +} + +.details-title { -fx-background-color: olivedrab; -fx-pref-width: Infinity; -fx-text-fill: white; @@ -20,13 +29,6 @@ -fx-background-radius: 5; } -.details-title { - -fx-pref-width: Infinity; - -fx-alignment: center; - -fx-padding: 10; - -fx-font-size: 17; -} - .code { -fx-text-fill: lime; -fx-font-family: monospaced; @@ -111,4 +113,4 @@ -fx-text-fill: red; -fx-background-color: white; -fx-font-weight: bold; -} \ No newline at end of file +} diff --git a/corefx/src/main/resources/fxml/link_details.fxml b/corefx/src/main/resources/fxml/link_details.fxml index fb27ae8d..5d6a8bd3 100644 --- a/corefx/src/main/resources/fxml/link_details.fxml +++ b/corefx/src/main/resources/fxml/link_details.fxml @@ -23,7 +23,7 @@ -