gui - initial icon edit support

This commit is contained in:
Blake J. Harnden 2018-09-18 13:52:02 -07:00
parent c25003c693
commit 670ed96167
9 changed files with 263 additions and 23 deletions

View file

@ -76,6 +76,7 @@ public class Controller implements Initializable {
private HooksDialog hooksDialog = new HooksDialog(this);
private MobilityDialog mobilityDialog = new MobilityDialog(this);
private ChartDialog chartDialog = new ChartDialog(this);
private NodeTypesDialog nodeTypesDialog = new NodeTypesDialog(this);
public Controller() {
// load configuration
@ -139,6 +140,12 @@ public class Controller implements Initializable {
nodeEmaneDialog.setOwner(window);
configDialog.setOwner(window);
mobilityDialog.setOwner(window);
nodeTypesDialog.setOwner(window);
}
@FXML
private void onOptionsMenuNodeTypes(ActionEvent event) {
nodeTypesDialog.showDialog();
}
@FXML

View file

@ -42,13 +42,22 @@ public class CoreNode {
this.loaded = false;
}
public LayeredIcon getGraphIcon() {
if (graphIcon == null) {
graphIcon = IconUtils.getIcon(icon);
graphIcon.add(radioIcon);
}
// public void setExternalIcon(String iconPath) {
// icon = iconPath;
// graphIcon = IconUtils.getExternalLayeredIcon(icon);
// graphIcon.add(radioIcon);
// }
return graphIcon;
public void setNodeType(NodeType nodeType) {
type = nodeType.getValue();
model = nodeType.getModel();
icon = nodeType.getIcon();
if (icon.startsWith("file:")) {
graphIcon = IconUtils.getExternalLayeredIcon(icon);
} else {
graphIcon = IconUtils.getLayeredIcon(icon);
}
graphIcon.add(radioIcon);
}
@JsonIgnore

View file

@ -19,9 +19,9 @@ public class NodeType {
private static final Map<String, NodeType> LOOKUP = new HashMap<>();
private static final Map<Integer, String> DISPLAY_MAP = new HashMap<>();
private final int value;
private final String display;
private final String model;
private final String icon;
private String display;
private String model;
private String icon;
// PHYSICAL = 1
// RJ45 = 7

View file

@ -305,9 +305,7 @@ public class NetworkGraph {
private void handleVertexAdded(GraphEvent.Vertex<CoreNode, CoreLink> vertexEvent) {
CoreNode node = vertexEvent.getVertex();
if (!node.isLoaded()) {
node.setType(nodeType.getValue());
node.setModel(nodeType.getModel());
node.setIcon(nodeType.getIcon());
node.setNodeType(nodeType);
if (node.getType() == NodeType.EMANE) {
String emaneModel = controller.getNodeEmaneDialog().getModels().get(0);
node.setEmane(emaneModel);

View file

@ -62,7 +62,8 @@ public class GraphToolbar extends VBox {
private SVGGlyph stopIcon;
private JFXListView<Label> nodesList = new JFXListView<>();
private JFXListView<Label> devicesList = new JFXListView<>();
private Map<Label, NodeType> labelMap = new HashMap<>();
private Map<String, NodeType> nodeTypeMap = new HashMap<>();
private Map<String, Label> labelMap = new HashMap<>();
private JFXButton selectedEditButton;
private NodeType selectedNodeType;
private boolean isEditing = false;
@ -149,7 +150,8 @@ public class GraphToolbar extends VBox {
icon.setFitWidth(NODES_ICON_SIZE);
icon.setFitHeight(NODES_ICON_SIZE);
Label label = new Label(nodeType.getDisplay(), icon);
labelMap.put(label, nodeType);
nodeTypeMap.put(nodeType.getDisplay(), nodeType);
labelMap.put(nodeType.getDisplay(), label);
if (nodeType.getValue() == NodeType.DEFAULT) {
nodesList.getItems().add(label);
@ -165,7 +167,7 @@ public class GraphToolbar extends VBox {
// initial node
nodesList.getSelectionModel().selectFirst();
Label selectedNodeLabel = nodesList.getSelectionModel().getSelectedItem();
selectedNodeType = labelMap.get(selectedNodeLabel);
selectedNodeType = nodeTypeMap.get(selectedNodeLabel.getText());
selectedEditButton = nodesButton;
controller.getNetworkGraph().setNodeType(selectedNodeType);
updateButtonValues(nodesButton, selectedNodeLabel);
@ -198,7 +200,7 @@ public class GraphToolbar extends VBox {
}
updateButtonValues(nodesButton, current);
selectedNodeType = labelMap.get(current);
selectedNodeType = nodeTypeMap.get(current.getText());
setSelectedEditButton(nodesButton);
devicesList.getSelectionModel().clearSelection();
controller.getNetworkGraph().setNodeType(selectedNodeType);
@ -218,7 +220,7 @@ public class GraphToolbar extends VBox {
}
updateButtonValues(devicesButton, current);
selectedNodeType = labelMap.get(current);
selectedNodeType = nodeTypeMap.get(current.getText());
controller.getNetworkGraph().setNodeType(selectedNodeType);
setSelectedEditButton(devicesButton);
nodesList.getSelectionModel().clearSelection();
@ -239,6 +241,18 @@ public class GraphToolbar extends VBox {
}
}
public void updateNodeType(String display, String uri) {
Label label = labelMap.get(display);
ImageView icon = new ImageView(uri);
icon.setFitWidth(NODES_ICON_SIZE);
icon.setFitHeight(NODES_ICON_SIZE);
label.setGraphic(icon);
if (selectedNodeType.getDisplay().equals(display)) {
updateButtonValues(nodesButton, label);
}
}
private void setSelected(boolean isSelected, JFXButton... others) {
Arrays.stream(others)
.forEach(x -> x.pseudoClassStateChanged(SELECTED_CLASS, isSelected));

View file

@ -0,0 +1,114 @@
package com.core.ui;
import com.core.Controller;
import com.core.data.CoreNode;
import com.core.data.NodeType;
import com.jfoenix.controls.JFXButton;
import com.jfoenix.controls.JFXListView;
import com.jfoenix.controls.JFXTextField;
import javafx.fxml.FXML;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.stage.FileChooser;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import java.io.File;
import java.util.HashMap;
import java.util.Map;
public class NodeTypesDialog extends StageDialog {
private static final Logger logger = LogManager.getLogger();
private final Map<String, NodeType> nodeTypeMap = new HashMap<>();
private NodeType selectedNodeType;
@FXML
private JFXListView<String> listView;
@FXML
private JFXTextField modelTextField;
@FXML
private JFXTextField displayTextField;
@FXML
private JFXTextField iconTextField;
@FXML
private JFXButton iconButton;
@FXML
private ImageView iconImage;
@FXML
private JFXButton saveButton;
@FXML
private JFXButton addButton;
@FXML
private JFXButton deleteButton;
public NodeTypesDialog(Controller controller) {
super(controller, "/fxml/node_types_dialog.fxml");
setTitle("Node Configuration");
addCancelButton();
listView.getSelectionModel().selectedItemProperty().addListener((ov, prev, current) -> {
if (current == null) {
return;
}
NodeType nodeType = nodeTypeMap.get(current);
modelTextField.setText(nodeType.getModel());
displayTextField.setText(nodeType.getDisplay());
iconTextField.setText(nodeType.getIcon());
iconImage.setImage(new Image(nodeType.getIcon()));
selectedNodeType = nodeType;
});
iconButton.setOnAction(event -> {
FileChooser fileChooser = new FileChooser();
fileChooser.setTitle("Select Icon");
fileChooser.setInitialDirectory(new File(System.getProperty("user.home")));
fileChooser.getExtensionFilters().add(new FileChooser.ExtensionFilter("PNG", "*.png"));
File file = fileChooser.showOpenDialog(controller.getWindow());
if (file != null) {
String uri = file.toURI().toString();
iconImage.setImage(new Image(uri));
iconTextField.setText(uri);
}
});
saveButton.setOnAction(event -> {
String iconPath = iconTextField.getText();
selectedNodeType.setIcon(iconPath);
for (CoreNode node : controller.getNetworkGraph().getGraph().getVertices()) {
if (!selectedNodeType.getKey().equals(node.getNodeTypeKey())) {
continue;
}
node.setNodeType(selectedNodeType);
}
controller.getNetworkGraph().getGraphViewer().repaint();
controller.getGraphToolbar().updateNodeType(selectedNodeType.getDisplay(), iconPath);
Toast.info(String.format("Node %s Updated", selectedNodeType.getDisplay()));
});
}
public void showDialog() {
listView.getItems().clear();
nodeTypeMap.clear();
for (NodeType nodeType : NodeType.getNodeTypes()) {
if (nodeType.getValue() != NodeType.DEFAULT) {
continue;
}
nodeTypeMap.put(nodeType.getDisplay(), nodeType);
listView.getItems().add(nodeType.getDisplay());
}
listView.getSelectionModel().selectFirst();
show();
}
}

View file

@ -9,24 +9,39 @@ import org.apache.logging.log4j.Logger;
import javax.swing.*;
import java.awt.*;
import java.net.URI;
import java.net.URISyntaxException;
import java.nio.file.Paths;
import java.util.HashMap;
import java.util.Map;
public final class IconUtils {
private static final Logger logger = LogManager.getLogger();
public static final int ICON_SIZE = 75;
private static final Map<String, LayeredIcon> ICON_MAP = new HashMap<>();
private static final Map<String, ImageIcon> ICON_MAP = new HashMap<>();
private IconUtils() {
}
public static LayeredIcon getIcon(String iconPath) {
return ICON_MAP.computeIfAbsent(iconPath, key -> {
ImageIcon imageIcon = new ImageIcon(IconUtils.class.getResource(iconPath));
Image image = imageIcon.getImage().getScaledInstance(ICON_SIZE, ICON_SIZE, Image.SCALE_DEFAULT);
return new LayeredIcon(image);
public static LayeredIcon getExternalLayeredIcon(String iconPath) {
ImageIcon imageIcon = ICON_MAP.computeIfAbsent(iconPath, key -> {
try {
return new ImageIcon(Paths.get(new URI(iconPath)).toString());
} catch (URISyntaxException ex) {
logger.error("error loading icon: {}", iconPath);
throw new IllegalArgumentException("invalid icon uri: " + iconPath);
}
});
Image image = imageIcon.getImage().getScaledInstance(ICON_SIZE, ICON_SIZE, Image.SCALE_DEFAULT);
return new LayeredIcon(image);
}
public static LayeredIcon getLayeredIcon(String iconPath) {
ImageIcon imageIcon = ICON_MAP.computeIfAbsent(iconPath, key ->
new ImageIcon(IconUtils.class.getResource(iconPath)));
Image image = imageIcon.getImage().getScaledInstance(ICON_SIZE, ICON_SIZE, Image.SCALE_DEFAULT);
return new LayeredIcon(image);
}
public static SVGGlyph get(String name) {

View file

@ -29,6 +29,11 @@
<MenuItem mnemonicParsing="false" onAction="#onSessionHooksMenu" text="Hooks" />
<MenuItem mnemonicParsing="false" onAction="#onSessionOptionsMenu" text="Options" />
</items>
</Menu>
<Menu mnemonicParsing="false" text="Options">
<items>
<MenuItem mnemonicParsing="false" onAction="#onOptionsMenuNodeTypes" text="Node Configuration" />
</items>
</Menu>
<Menu mnemonicParsing="false" text="Help">
<items>

View file

@ -0,0 +1,78 @@
<?xml version="1.0" encoding="UTF-8"?>
<?import com.jfoenix.controls.JFXButton?>
<?import com.jfoenix.controls.JFXListView?>
<?import com.jfoenix.controls.JFXTextField?>
<?import javafx.geometry.Insets?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.image.ImageView?>
<?import javafx.scene.layout.ColumnConstraints?>
<?import javafx.scene.layout.GridPane?>
<?import javafx.scene.layout.RowConstraints?>
<?import javafx.scene.layout.VBox?>
<GridPane hgap="10.0" maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" minHeight="-Infinity" minWidth="-Infinity" prefHeight="400.0" prefWidth="600.0" vgap="10.0" xmlns:fx="http://javafx.com/fxml/1" xmlns="http://javafx.com/javafx/8.0.171">
<columnConstraints>
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" percentWidth="33.0" prefWidth="100.0" />
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0" />
</columnConstraints>
<rowConstraints>
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
</rowConstraints>
<children>
<VBox prefHeight="200.0" prefWidth="100.0" spacing="10.0">
<children>
<JFXListView fx:id="listView" VBox.vgrow="ALWAYS" />
<GridPane hgap="10.0" vgap="10.0">
<columnConstraints>
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0" />
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0" />
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0" />
</columnConstraints>
<rowConstraints>
<RowConstraints />
<RowConstraints minHeight="10.0" prefHeight="30.0" />
</rowConstraints>
<children>
<JFXButton fx:id="addButton" maxWidth="1.7976931348623157E308" styleClass="core-button" text="Add" GridPane.rowIndex="1" />
<JFXButton fx:id="deleteButton" maxWidth="1.7976931348623157E308" styleClass="core-button" text="Delete" GridPane.columnIndex="1" GridPane.rowIndex="1" />
<JFXButton fx:id="saveButton" maxWidth="1.7976931348623157E308" styleClass="core-button" text="Save" GridPane.columnIndex="2" GridPane.rowIndex="1" />
</children>
</GridPane>
</children>
<padding>
<Insets bottom="10.0" left="10.0" right="10.0" top="10.0" />
</padding>
</VBox>
<VBox prefHeight="200.0" prefWidth="100.0" spacing="10.0" GridPane.columnIndex="1">
<children>
<Label maxWidth="1.7976931348623157E308" text="Model" />
<JFXTextField fx:id="modelTextField" disable="true" />
<Label maxWidth="1.7976931348623157E308" text="Display" />
<JFXTextField fx:id="displayTextField" disable="true" />
<Label maxWidth="1.7976931348623157E308" text="Icon" />
<GridPane hgap="10.0" vgap="10.0">
<columnConstraints>
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0" />
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" percentWidth="20.0" prefWidth="100.0" />
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" percentWidth="20.0" prefWidth="100.0" />
</columnConstraints>
<rowConstraints>
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
</rowConstraints>
<children>
<JFXTextField fx:id="iconTextField" disable="true" />
<ImageView fx:id="iconImage" fitHeight="50.0" fitWidth="50.0" pickOnBounds="true" preserveRatio="true" GridPane.columnIndex="2" GridPane.halignment="CENTER" />
<JFXButton fx:id="iconButton" maxWidth="1.7976931348623157E308" styleClass="core-button" text="Find" GridPane.columnIndex="1" />
</children>
</GridPane>
</children>
<GridPane.margin>
<Insets />
</GridPane.margin>
<padding>
<Insets bottom="10.0" left="10.0" right="10.0" top="10.0" />
</padding>
</VBox>
</children>
</GridPane>