diff --git a/AlgebraicDataflowArchitectureModel/models/SimpleUI.model b/AlgebraicDataflowArchitectureModel/models/SimpleUI.model index f393c9d..584d8e3 100644 --- a/AlgebraicDataflowArchitectureModel/models/SimpleUI.model +++ b/AlgebraicDataflowArchitectureModel/models/SimpleUI.model @@ -17,3 +17,15 @@ native channel TextEvent(wid: Str) { out screen.widgets.{wid}.text(curText: Str, textEvent(nextText)) = nextText } + +channel AddButton { + out screen.widgets(widgets: Map, addButton(wid: Str, text: Str)) = insert(widgets, wid, {"type": "button", "text": text, "state": 0}) +} + +channel AddLabel { + out screen.widgets(widgets: Map, addLabel(wid: Str, text: Str)) = insert(widgets, wid, {"type": "label", "text": text, "state": 0}) +} + +channel AddInputText { + out screen.widgets(widgets: Map, addInputText(wid: Str)) = insert(widgets, wid, {"type": "inputText", "state": 0}) +} diff --git a/AlgebraicDataflowArchitectureModel/src/application/SimulatorWindow.java b/AlgebraicDataflowArchitectureModel/src/application/SimulatorWindow.java index 6a0684b..a8b4281 100644 --- a/AlgebraicDataflowArchitectureModel/src/application/SimulatorWindow.java +++ b/AlgebraicDataflowArchitectureModel/src/application/SimulatorWindow.java @@ -12,6 +12,7 @@ import javax.swing.JFrame; +import application.editor.SimulationLayout; import com.mxgraph.model.mxCell; import com.mxgraph.model.mxGeometry; import com.mxgraph.model.mxGraphModel; @@ -61,9 +62,6 @@ public class SimulatorWindow extends JFrame{ - /** - * - */ private static final long serialVersionUID = -2425820512017088254L; public static final String title = "Simulation Tool"; @@ -73,7 +71,10 @@ private Editor editor = null; private mxGraph graph = null; private mxGraphComponent graphComponent = null; + private UIWindow uiWindow; + private Simulator simulator = null; + private boolean bReflectingArchitectureModel = false; private double x = 20; private double y = 20; @@ -129,20 +130,22 @@ DataTransferModel model = this.editor.getModel(); TypeInference.infer(model); simulator = new Simulator(model); - constructSimulateGraph(simulator.getCurState().getRootResources(), this.editor.getModel(),this.editor.getDataFlowGraph()); + SimulationLayout layout = new SimulationLayout(simulator.getCurState()); + layout.constructSimulateGraph(graph, simulator); graphComponent.setCellEditor(new InputEventCellEditor(graphComponent, simulator, this.editor, graph)); + + uiWindow = new UIWindow(simulator); } - - + public mxGraph constructSimulateGraph(Set simulateRes, DataTransferModel model, DataFlowGraph dataFlowGraph) { bReflectingArchitectureModel = true; ((mxGraphModel) graph.getModel()).clear(); Object parent = graph.getDefaultParent(); graph.getModel().beginUpdate(); - + try { Map resources = new HashMap<>(); - + // create resource vertices for (Resource resNode: simulateRes) { int w = 80; @@ -155,11 +158,11 @@ createChildSimulateResourceVerticies(resource, resNode, resources, w, h); x+=80; } - + } finally { graph.getModel().endUpdate(); } - + bReflectingArchitectureModel = false; return graph; } diff --git a/AlgebraicDataflowArchitectureModel/src/application/UIWindow.java b/AlgebraicDataflowArchitectureModel/src/application/UIWindow.java new file mode 100644 index 0000000..97ca1e3 --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/src/application/UIWindow.java @@ -0,0 +1,26 @@ +package application; + +import javax.swing.JFrame; +import javax.swing.JPanel; + +import simulator.Simulator; +import simulator.interfaces.swing.SwingPresenter; + +public class UIWindow extends JFrame { + + private static final long serialVersionUID = 1770206525826167136L; + private SwingPresenter presenter; + private Simulator simulator; + private JPanel mainPanel; + + public UIWindow(Simulator simulator) { + setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + this.simulator = simulator; + mainPanel = new JPanel(); + presenter = new SwingPresenter(mainPanel, simulator); + this.add(mainPanel); + + setSize(870,640); + setVisible(true); + } +} diff --git a/AlgebraicDataflowArchitectureModel/src/application/editor/InputEventCellEditor.java b/AlgebraicDataflowArchitectureModel/src/application/editor/InputEventCellEditor.java index e945773..ea39086 100644 --- a/AlgebraicDataflowArchitectureModel/src/application/editor/InputEventCellEditor.java +++ b/AlgebraicDataflowArchitectureModel/src/application/editor/InputEventCellEditor.java @@ -169,8 +169,10 @@ Event newEvent = new Event(eventChs.get(eventNum), eventMessage, eventResPath, simulator.getCurState().getResource(resId)); simulator.transition(newEvent); - - constructNextSimulateGraph(simulator.getCurState().getRootResources(), simulator.getModel(),simulator.getModel().getDataFlowGraph(), graph); + + SimulationLayout layout = new SimulationLayout(simulator.getCurState()); + layout.constructSimulateGraph(graph, simulator); + graphComponent.setCellEditor(new InputEventCellEditor(graphComponent, simulator, this.editor, graph)); } catch (ParameterizedIdentifierIsFutureWork | ResolvingMultipleDefinitionIsFutureWork @@ -208,10 +210,10 @@ ((mxGraphModel) nextGraph.getModel()).clear(); Object parent = nextGraph.getDefaultParent(); nextGraph.getModel().beginUpdate(); - + try { Map resources = new HashMap<>(); - + // create resource vertices for (Resource resNode: simulateRes) { int w = 400; @@ -221,15 +223,15 @@ res.toString(), x, y, w, h, "shape=ellipse;perimeter=ellipsePerimeter;verticalAlign=top;"); // insert a resource as a vertex resources.put(resNode, resource); - + createNextChildSimulateResourceVerticies(resource, resNode, resources, w, h); x+=400; } - + } finally { nextGraph.getModel().endUpdate(); } - + bReflectingArchitectureModel = false; return nextGraph; } @@ -241,7 +243,7 @@ int i = 1; ResourcePath childRes = childNode.getResourceIdentifier(); Object childResource = graph.insertVertex(resource, null, - childRes.toString(), x/i, y, w/(i+1), h/(i+2), + childRes.toString(), x/i, 0, w/(i+1), h/(i+2), "shape=ellipse;perimeter=ellipsePerimeter;verticalAlign=top;"); // insert a resource as a vertex resources.put(childNode, childResource); i++; diff --git a/AlgebraicDataflowArchitectureModel/src/application/editor/SimulationLayout.java b/AlgebraicDataflowArchitectureModel/src/application/editor/SimulationLayout.java new file mode 100644 index 0000000..4534ab4 --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/src/application/editor/SimulationLayout.java @@ -0,0 +1,142 @@ +package application.editor; + +import com.mxgraph.model.mxGraphModel; +import com.mxgraph.view.mxGraph; +import models.dataConstraintModel.ResourcePath; +import simulator.Resource; +import simulator.ResourceIdentifier; +import simulator.Simulator; +import simulator.SystemState; + +import java.util.Collection; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; + +public class SimulationLayout { + HashMap divisionLevelMap = new HashMap<>(); + HashMap resourceScaleMap = new HashMap<>(); + int maxDivisionLevel = 1; + public final double BASE_WIDTH = 400; + public final double BASE_HEIGHT = BASE_WIDTH/2; + public final double MARGIN_SCALE = 0.92; + SystemState systemState; + public SimulationLayout(SystemState systemState){ + this.systemState = systemState; + for (Resource res:systemState.getRootResources()) { + setDivisionLevel(divisionLevelMap, res.getResourceIdentifier(), 1); + } + for (ResourceIdentifier res:divisionLevelMap.keySet()) { + double scale = (double) maxDivisionLevel / divisionLevelMap.get(res); + resourceScaleMap.put(res, scale); + } + } + public double getScale(ResourceIdentifier resource){ + return resourceScaleMap.get(resource); + } + public double getDivision(ResourceIdentifier resource){ + return divisionLevelMap.get(resource); + } + + public int getMaxDivisionLevel() { + return maxDivisionLevel; + } + + public boolean isExistResource(ResourceIdentifier resourceIdentifier){ + return divisionLevelMap.containsKey(resourceIdentifier); + } + private void setDivisionLevel(HashMap resourceSet, ResourceIdentifier resource, int childCount){ + int divisionLevel; + if(resourceSet.get(resource.getParent()) == null){ + divisionLevel = 1; + }else{ + divisionLevel = resourceSet.get(resource.getParent()) * childCount; + } + if (divisionLevel > maxDivisionLevel)maxDivisionLevel = divisionLevel; + resourceSet.put(resource,divisionLevel); + + Collection identifiers = systemState.getResource(resource).getChildren(); + if (identifiers != null) { + for (Resource child:identifiers) { + setDivisionLevel(resourceSet, child.getResourceIdentifier(), identifiers.size()); + } + } + } + + private Object setLayout(mxGraph graph,Object parent, ResourceIdentifier resourceIdentifier,double index, double length){ + double width, height, x, y; + double parentWidth = graph.getCellGeometry(parent).getWidth(); + double parentHeight = graph.getCellGeometry(parent).getHeight(); + + width = parentWidth / length * MARGIN_SCALE; + height = width/2; + x = parentWidth * (index - 1)/length + (parentWidth/length)*(1-MARGIN_SCALE)/2; + + if ((int)length == 1) { + y = 20; + height -=20; + } else { + y = parentHeight/2 - height/2; + } + + Object result = graph.insertVertex(parent, null, + resourceIdentifier.toString(), x, y, width, height, + "shape=ellipse;perimeter=ellipsePerimeter;verticalAlign=top;"); + System.out.println(result); + return result; + } + + public mxGraph constructSimulateGraph(mxGraph graph, Simulator simulator){ + ((mxGraphModel) graph.getModel()).clear(); + Object parent = graph.getDefaultParent(); + graph.getModel().beginUpdate(); + + try { + Map resources = new HashMap<>(); + int i = 0; + // create resource vertices + for (Resource resNode: simulator.getCurState().getRootResources()) { + double scale = this.getScale(resNode.getResourceIdentifier()); + double maxDiv = this.getMaxDivisionLevel(); + double w = this.BASE_WIDTH * scale /maxDiv; + double h = this.BASE_HEIGHT * scale /maxDiv; + int childCount = simulator.getCurState().getRootResources().size(); + double x = w * (1 + i - childCount / 2.0); + double y = 20 ; + ResourcePath res = resNode.getResourceIdentifier(); + Object resource = graph.insertVertex(parent, null, + res.toString(), x, y, w, h, + "shape=ellipse;perimeter=ellipsePerimeter;verticalAlign=top;"); // insert a resource as a vertex + resources.put(resNode, resource); + i++; + createNextChildSimulateResourceVerticies(graph, resource, resNode, resources); + + } + + } finally { + graph.getModel().endUpdate(); + } + + return graph; + } + private void createNextChildSimulateResourceVerticies(mxGraph graph, Object parent, Resource resNode, Map resources) { //sample + Collection children = resNode.getChildren(); + if (children != null) { + //List children = resNode.getChildren(); + double i = 1; + double childCount = children.size(); + for (Resource childNode: children) { + Object childResource = setLayout(graph, parent, childNode.getResourceIdentifier(), i, childCount); + resources.put(childNode, childResource); + i++; + createNextChildSimulateResourceVerticies(graph, childResource, childNode, resources); + + } + } + if (children == null || children.size() == 0) { + Object state = graph.insertVertex(parent, null, + resNode.getState().getValue().toString(), 0.5, 0.5, 0.25, 0.25, "opacity=0;verticalAlign=down;", true); // insert a state label as a vertex + } + } +} diff --git a/AlgebraicDataflowArchitectureModel/src/models/algebra/Term.java b/AlgebraicDataflowArchitectureModel/src/models/algebra/Term.java index 1b5a6ac..3398f18 100644 --- a/AlgebraicDataflowArchitectureModel/src/models/algebra/Term.java +++ b/AlgebraicDataflowArchitectureModel/src/models/algebra/Term.java @@ -172,8 +172,11 @@ boolean bReduced = false; for (Expression child: children) { if (child instanceof Term && !(child instanceof Constant)) { - child = ((Term) (child)).reduce(); - bReduced = true; + Expression newChild = ((Term) (child)).reduce(); + if (newChild != child) { + bReduced = true; + child = newChild; + } } newChildren.add(child); } diff --git a/AlgebraicDataflowArchitectureModel/src/simulator/interfaces/swing/SwingPresenter.java b/AlgebraicDataflowArchitectureModel/src/simulator/interfaces/swing/SwingPresenter.java index f8b3b2e..68df398 100644 --- a/AlgebraicDataflowArchitectureModel/src/simulator/interfaces/swing/SwingPresenter.java +++ b/AlgebraicDataflowArchitectureModel/src/simulator/interfaces/swing/SwingPresenter.java @@ -1,6 +1,7 @@ package simulator.interfaces.swing; import java.awt.Component; +import java.awt.Toolkit; import java.util.HashMap; import java.util.HashSet; import java.util.Map; @@ -10,8 +11,10 @@ import javax.swing.JLabel; import javax.swing.JPanel; import javax.swing.JTextField; +import javax.swing.SwingUtilities; import models.algebra.Expression; +import models.algebra.Term; import models.dataConstraintModel.JsonTerm; import models.dataConstraintModel.MapTerm; import models.dataConstraintModel.ResourcePath; @@ -39,87 +42,95 @@ public SwingPresenter(JPanel mainPanel, Simulator simulator) { this.mainPanel = mainPanel; this.simulator = simulator; + components = new HashMap<>(); screenUpdateChannel = (DataTransferChannel) simulator.getModel().getChannel(screenUpdateChannelName); setVisibleChannel = (DataTransferChannel) simulator.getModel().getChannel(setVisibleChannelName); - mouseEventChannel = (DataTransferChannel) simulator.getModel().getChannel(mouseEventChannelName); - textEventChannel = (DataTransferChannel) simulator.getModel().getChannel(textEventChannelName); + mouseEventChannel = (DataTransferChannel) simulator.getModel().getInputChannel(mouseEventChannelName); + textEventChannel = (DataTransferChannel) simulator.getModel().getInputChannel(textEventChannelName); simulator.addNativeReceiver(this, screenUpdateChannel); } @Override public void onReceiveFromModel(Event event) { Expression message = event.getMessage(); - if (message instanceof JsonTerm) { - // Remove old native receivers. - for (DataTransferChannel channel: channelAndResourcesForReceiving.keySet()) { - for (Resource resource: channelAndResourcesForReceiving.get(channel)) { - simulator.removeNativeReceiver(channel, resource); + if (message instanceof Term && ((Term) message).getChildren().size() == 1) { + message = ((Term) message).getChild(0); + if (message instanceof JsonTerm) { + // Remove old native receivers. + for (DataTransferChannel channel: channelAndResourcesForReceiving.keySet()) { + for (Resource resource: channelAndResourcesForReceiving.get(channel)) { + simulator.removeNativeReceiver(channel, resource); + } } - } - channelAndResourcesForReceiving.clear(); - - // Reconstruct swing components. - JsonTerm screenContent = (JsonTerm) message; - Resource screenResource = simulator.getCurState().getResource(event.getInputResource().getResourceIdentifier()); - Expression widgets = screenContent.get("\"widgets\""); - Resource widgetsResource = screenResource.getChildrenMap().get("\"widgets\""); - if (widgets instanceof MapTerm) { - for (String key: ((MapTerm) widgets).keySet()) { - Expression value = ((MapTerm) widgets).get(key); - if (value instanceof JsonTerm) { - JsonTerm widget = (JsonTerm) value; - Resource widgetResource = widgetsResource.getChildrenMap().get(key); - Expression type = widget.get("\"type\""); - if (type.toString().equals("button")) { - // Add a button component. - Expression text = widget.get("\"text\""); - JButton button = new JButton(text.toString().toString()); - mainPanel.add(button); - components.put(key, button); - // Connect swing component and model. - ResourcePath resPath = mouseEventChannel.getOutputResources().iterator().next(); - button.addMouseListener(new ComponentMouseSender(simulator, mouseEventChannel, resPath, widgetResource)); // button => widgetResource - ComponentVisibilityReceiver nativeReceiver = new ComponentVisibilityReceiver(button); // widgetResource => button - simulator.addNativeReceiver(nativeReceiver, setVisibleChannel, widgetResource); - Set resources = channelAndResourcesForReceiving.get(setVisibleChannel); - if (resources == null) { - resources = new HashSet<>(); - channelAndResourcesForReceiving.put(setVisibleChannel, resources); + channelAndResourcesForReceiving.clear(); + + // Reconstruct swing components. + JsonTerm screenContent = (JsonTerm) message; + Resource screenResource = simulator.getCurState().getResource(event.getInputResource().getResourceIdentifier()); + Expression widgets = screenContent.get("widgets"); + Resource widgetsResource = screenResource.getChildrenMap().get("widgets"); + if (widgets instanceof MapTerm) { + mainPanel.removeAll(); + for (String key: ((MapTerm) widgets).keySet()) { + Expression value = ((MapTerm) widgets).get(key); + if (value instanceof JsonTerm) { + JsonTerm widget = (JsonTerm) value; + Resource widgetResource = widgetsResource.getChildrenMap().get(key); + Expression type = widget.get("\"type\""); + if (type.toString().equals("\"button\"")) { + // Add a button component. + Expression text = widget.get("\"text\""); + JButton button = new JButton(text.toString().replace("\"", "")); + mainPanel.add(button); + components.put(key, button); + // Connect swing component and model. + ResourcePath resPath = mouseEventChannel.getOutputResources().iterator().next(); + button.addMouseListener(new ComponentMouseSender(simulator, mouseEventChannel, resPath, widgetResource)); // button => widgetResource + ComponentVisibilityReceiver nativeReceiver = new ComponentVisibilityReceiver(button); // widgetResource => button + simulator.addNativeReceiver(nativeReceiver, setVisibleChannel, widgetResource); + Set resources = channelAndResourcesForReceiving.get(setVisibleChannel); + if (resources == null) { + resources = new HashSet<>(); + channelAndResourcesForReceiving.put(setVisibleChannel, resources); + } + resources.add(widgetsResource); + } else if (type.toString().equals("\"label\"")) { + // Add a label component. + Expression text = widget.get("\"text\""); + JLabel label = new JLabel(text.toString().replace("\"", "")); + mainPanel.add(label); + components.put(key, label); + // Connect swing component and model. + ComponentVisibilityReceiver nativeReceiver = new ComponentVisibilityReceiver(label); + simulator.addNativeReceiver(nativeReceiver, setVisibleChannel, widgetResource); + Set resources = channelAndResourcesForReceiving.get(setVisibleChannel); + if (resources == null) { + resources = new HashSet<>(); + channelAndResourcesForReceiving.put(setVisibleChannel, resources); + } + resources.add(widgetsResource); + } else if (type.toString().equals("\"inputText\"")) { + // Add a text input component. + JTextField textField = new JTextField(10); + mainPanel.add(textField); + components.put(key, textField); + // Connect swing component and model. + ResourcePath resPath = textEventChannel.getOutputResources().iterator().next(); + textField.addInputMethodListener(new ComponentTextSender(simulator, textEventChannel, resPath, widgetResource)); // textField => widgetResource + ComponentVisibilityReceiver nativeReceiver = new ComponentVisibilityReceiver(textField); // widgetResource => textField + simulator.addNativeReceiver(nativeReceiver, setVisibleChannel, widgetResource); + Set resources = channelAndResourcesForReceiving.get(setVisibleChannel); + if (resources == null) { + resources = new HashSet<>(); + channelAndResourcesForReceiving.put(setVisibleChannel, resources); + } + resources.add(widgetsResource); } - resources.add(widgetsResource); - } else if (type.toString().equals("label")) { - // Add a label component. - Expression text = widget.get("\"text\""); - JLabel label = new JLabel(text.toString().toString()); - mainPanel.add(label); - components.put(key, label); - // Connect swing component and model. - ComponentVisibilityReceiver nativeReceiver = new ComponentVisibilityReceiver(label); - simulator.addNativeReceiver(nativeReceiver, setVisibleChannel, widgetResource); - Set resources = channelAndResourcesForReceiving.get(setVisibleChannel); - if (resources == null) { - resources = new HashSet<>(); - channelAndResourcesForReceiving.put(setVisibleChannel, resources); - } - resources.add(widgetsResource); - } else if (type.toString().equals("inputText")) { - // Add a text input component. - JTextField textField = new JTextField(); - mainPanel.add(textField); - components.put(key, textField); - // Connect swing component and model. - ResourcePath resPath = textEventChannel.getOutputResources().iterator().next(); - textField.addInputMethodListener(new ComponentTextSender(simulator, textEventChannel, resPath, widgetResource)); // textField => widgetResource - ComponentVisibilityReceiver nativeReceiver = new ComponentVisibilityReceiver(textField); // widgetResource => textField - simulator.addNativeReceiver(nativeReceiver, setVisibleChannel, widgetResource); - Set resources = channelAndResourcesForReceiving.get(setVisibleChannel); - if (resources == null) { - resources = new HashSet<>(); - channelAndResourcesForReceiving.put(setVisibleChannel, resources); - } - resources.add(widgetsResource); } } + mainPanel.invalidate(); + mainPanel.validate(); + mainPanel.repaint(); } } } diff --git a/AlgebraicDataflowArchitectureModel/src/simulator/states/ListResourceState.java b/AlgebraicDataflowArchitectureModel/src/simulator/states/ListResourceState.java index 022a32f..0e45334 100644 --- a/AlgebraicDataflowArchitectureModel/src/simulator/states/ListResourceState.java +++ b/AlgebraicDataflowArchitectureModel/src/simulator/states/ListResourceState.java @@ -9,19 +9,16 @@ import models.algebra.Expression; import models.algebra.Term; import models.dataConstraintModel.DataConstraintModel; +import models.dataConstraintModel.ListTerm; public class ListResourceState extends CompositeResourceState { private List children = new ArrayList<>(); @Override public Expression getValue() { - Term value = new Constant(DataConstraintModel.nil); - value.setType(DataConstraintModel.typeList); + ListTerm value = new ListTerm(); for (ResourceState child: children) { - Term newTerm = new Term(DataConstraintModel.append); - newTerm.addChild(value); - newTerm.addChild(child.getValue()); - value = newTerm; + value.append(child.getValue()); } return value; } diff --git a/AlgebraicDataflowArchitectureModel/src/simulator/states/MapResourceState.java b/AlgebraicDataflowArchitectureModel/src/simulator/states/MapResourceState.java index 5bd2fc7..e03d70e 100644 --- a/AlgebraicDataflowArchitectureModel/src/simulator/states/MapResourceState.java +++ b/AlgebraicDataflowArchitectureModel/src/simulator/states/MapResourceState.java @@ -7,20 +7,17 @@ import models.algebra.Expression; import models.algebra.Term; import models.dataConstraintModel.DataConstraintModel; +import models.dataConstraintModel.MapTerm; public class MapResourceState extends CompositeResourceState { private Map children = new HashMap<>(); @Override public Expression getValue() { - Term value = new Constant(DataConstraintModel.nil); + MapTerm value = new MapTerm(); value.setType(DataConstraintModel.typeMap); for (Map.Entry childEnt: children.entrySet()) { - Term newTerm = new Term(DataConstraintModel.insert); - newTerm.addChild(value); - newTerm.addChild(new Constant(childEnt.getKey(), DataConstraintModel.typeString)); - newTerm.addChild(childEnt.getValue().getValue()); - value = newTerm; + value.insert(childEnt.getKey(), childEnt.getValue().getValue()); } return value; }