diff --git a/AlgebraicDataflowArchitectureModel/models/SimpleUI.model b/AlgebraicDataflowArchitectureModel/models/SimpleUI.model index 584d8e3..3b0d023 100644 --- a/AlgebraicDataflowArchitectureModel/models/SimpleUI.model +++ b/AlgebraicDataflowArchitectureModel/models/SimpleUI.model @@ -1,5 +1,5 @@ native channel ScreenUpdate { - in screen(curSc: Json, update(nextSc)) = nextSc + in screen(curSc: Json, update(curSc, nextSc)) = nextSc } native channel SetVisible(wid: Str) { @@ -26,6 +26,6 @@ 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}) -} +channel AddTextInput { + out screen.widgets(widgets: Map, addTextInput(wid: Str)) = insert(widgets, wid, {"type": "textInput", "text": "", "state": 0}) +} \ No newline at end of file diff --git a/AlgebraicDataflowArchitectureModel/src/application/simulator/InputEventCellEditor.java b/AlgebraicDataflowArchitectureModel/src/application/simulator/InputEventCellEditor.java index 10e5565..8d219c5 100644 --- a/AlgebraicDataflowArchitectureModel/src/application/simulator/InputEventCellEditor.java +++ b/AlgebraicDataflowArchitectureModel/src/application/simulator/InputEventCellEditor.java @@ -82,13 +82,11 @@ private JComboBox pulldownMenu; private Editor editor; private boolean bReflectingArchitectureModel = false; - private mxGraph graph; - public InputEventCellEditor(mxGraphComponent graphComponent, Simulator simulator, Editor editor, mxGraph graph) { + public InputEventCellEditor(mxGraphComponent graphComponent, Simulator simulator, Editor editor) { this.graphComponent = graphComponent; this.simulator = simulator; this.editor = editor; - this.graph = graph; } @Override @@ -170,10 +168,10 @@ Event newEvent = new Event(eventChs.get(eventNum), eventMessage, eventResPath, simulator.getCurState().getResource(resId)); simulator.transition(newEvent); - SimulationLayout layout = new SimulationLayout(simulator.getCurState()); - layout.constructSimulateGraph(graph, simulator); +// SimulationLayout layout = new SimulationLayout(simulator.getCurState()); +// layout.constructSimulateGraph(graph, simulator); - graphComponent.setCellEditor(new InputEventCellEditor(graphComponent, simulator, this.editor, graph)); + graphComponent.setCellEditor(new InputEventCellEditor(graphComponent, simulator, this.editor)); } catch (ParameterizedIdentifierIsFutureWork | ResolvingMultipleDefinitionIsFutureWork | InvalidMessage | UnificationFailed | ValueUndefined | ExpectedRightBracket | WrongJsonExpression | ExpectedColon e) { @@ -205,56 +203,56 @@ } } - private mxGraph constructNextSimulateGraph(Set simulateRes, DataTransferModel model,DataFlowGraph dataFlowGraph, mxGraph nextGraph) { - bReflectingArchitectureModel = true; - ((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; - int h = 150; - ResourcePath res = resNode.getResourceIdentifier(); - Object resource = nextGraph.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); - - createNextChildSimulateResourceVerticies(resource, resNode, resources, w, h); - x+=400; - } - - } finally { - nextGraph.getModel().endUpdate(); - } - - bReflectingArchitectureModel = false; - return nextGraph; - } - - private void createNextChildSimulateResourceVerticies(Object resource, Resource resNode, Map resources, int w, int h) { //sample - - if(resNode.getChildren() != null) { - for (Resource childNode: resNode.getChildren()) { - int i = 1; - ResourcePath childRes = childNode.getResourceIdentifier(); - Object childResource = graph.insertVertex(resource, null, - 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++; - createNextChildSimulateResourceVerticies(childResource, childNode, resources, w, h); - } - } - if (resNode.getChildren() == null || resNode.getChildren().size() == 0) { - Object state = graph.insertVertex(resource, 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 - } - } +// private mxGraph constructNextSimulateGraph(Set simulateRes, DataTransferModel model,DataFlowGraph dataFlowGraph, mxGraph nextGraph) { +// bReflectingArchitectureModel = true; +// ((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; +// int h = 150; +// ResourcePath res = resNode.getResourceIdentifier(); +// Object resource = nextGraph.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); +// +// createNextChildSimulateResourceVerticies(resource, resNode, resources, w, h); +// x+=400; +// } +// +// } finally { +// nextGraph.getModel().endUpdate(); +// } +// +// bReflectingArchitectureModel = false; +// return nextGraph; +// } +// +// private void createNextChildSimulateResourceVerticies(Object resource, Resource resNode, Map resources, int w, int h) { //sample +// +// if(resNode.getChildren() != null) { +// for (Resource childNode: resNode.getChildren()) { +// int i = 1; +// ResourcePath childRes = childNode.getResourceIdentifier(); +// Object childResource = graph.insertVertex(resource, null, +// 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++; +// createNextChildSimulateResourceVerticies(childResource, childNode, resources, w, h); +// } +// } +// if (resNode.getChildren() == null || resNode.getChildren().size() == 0) { +// Object state = graph.insertVertex(resource, 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 +// } +// } @Override public void stopEditing(boolean cancel) { diff --git a/AlgebraicDataflowArchitectureModel/src/application/simulator/SimulatorWindow.java b/AlgebraicDataflowArchitectureModel/src/application/simulator/SimulatorWindow.java index 07268f3..6dfb078 100644 --- a/AlgebraicDataflowArchitectureModel/src/application/simulator/SimulatorWindow.java +++ b/AlgebraicDataflowArchitectureModel/src/application/simulator/SimulatorWindow.java @@ -56,8 +56,10 @@ import simulator.Resource; import simulator.ResourceIdentifier; import simulator.Simulator; +import simulator.SystemState; +import simulator.interfaces.INativeReceiver; -public class SimulatorWindow extends JFrame{ +public class SimulatorWindow extends JFrame implements INativeReceiver { private static final long serialVersionUID = -2425820512017088254L; public static final String title = "Simulation Tool"; @@ -129,60 +131,68 @@ simulator = new Simulator(model); SimulationLayout layout = new SimulationLayout(simulator.getCurState()); layout.constructSimulateGraph(graph, simulator); - graphComponent.setCellEditor(new InputEventCellEditor(graphComponent, simulator, this.editor, graph)); + graphComponent.setCellEditor(new InputEventCellEditor(graphComponent, simulator, this.editor)); + simulator.addSystemReceiver(this); menuBar = new SimulatorMenuBar(this); setJMenuBar(menuBar); } - - 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; - int h = 30; - 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); - createChildSimulateResourceVerticies(resource, resNode, resources, w, h); - x+=80; - } - - } finally { - graph.getModel().endUpdate(); - } - - bReflectingArchitectureModel = false; - return graph; - } - - public void createChildSimulateResourceVerticies(Object resource, Resource resNode, Map resources, int w, int h) { //sample - - if(resNode.getChildren() != null) { - for (Resource childNode: resNode.getChildren()) { - ResourcePath childRes = childNode.getResourceIdentifier(); - Object childResource = graph.insertVertex(resource, null, - childRes.toString(), 0, 0, w/2, h/2, - "shape=ellipse;perimeter=ellipsePerimeter;verticalAlign=top;"); // insert a resource as a vertex - resources.put(childNode, childResource); - createChildSimulateResourceVerticies(childResource, childNode, resources, w, h); - } - } - if (resNode.getChildren() == null || resNode.getChildren().size() == 0) { - Object state = graph.insertVertex(resource, 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 - } + + @Override + public void onReceiveFromModel(Event event, SystemState nextSystemState) { + SimulationLayout layout = new SimulationLayout(nextSystemState); + layout.constructSimulateGraph(graph, 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; +// int h = 30; +// 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); +// createChildSimulateResourceVerticies(resource, resNode, resources, w, h); +// x+=80; +// } +// +// } finally { +// graph.getModel().endUpdate(); +// } +// +// bReflectingArchitectureModel = false; +// return graph; +// } +// +// +// public void createChildSimulateResourceVerticies(Object resource, Resource resNode, Map resources, int w, int h) { //sample +// +// if(resNode.getChildren() != null) { +// for (Resource childNode: resNode.getChildren()) { +// ResourcePath childRes = childNode.getResourceIdentifier(); +// Object childResource = graph.insertVertex(resource, null, +// childRes.toString(), 0, 0, w/2, h/2, +// "shape=ellipse;perimeter=ellipsePerimeter;verticalAlign=top;"); // insert a resource as a vertex +// resources.put(childNode, childResource); +// createChildSimulateResourceVerticies(childResource, childNode, resources, w, h); +// } +// } +// if (resNode.getChildren() == null || resNode.getChildren().size() == 0) { +// Object state = graph.insertVertex(resource, 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 +// } +// } public mxGraphComponent getGraphComponent() { return graphComponent; diff --git a/AlgebraicDataflowArchitectureModel/src/models/dataConstraintModel/DataConstraintModel.java b/AlgebraicDataflowArchitectureModel/src/models/dataConstraintModel/DataConstraintModel.java index eb5e29e..2776604 100644 --- a/AlgebraicDataflowArchitectureModel/src/models/dataConstraintModel/DataConstraintModel.java +++ b/AlgebraicDataflowArchitectureModel/src/models/dataConstraintModel/DataConstraintModel.java @@ -200,6 +200,8 @@ result = (Long.parseLong(sArg0) == Long.parseLong(sArg1)); } else if (arg0.getType().equals(typeInt) || arg1.getType().equals(typeInt)) { result = (Integer.parseInt(sArg0) == Integer.parseInt(sArg1)); + } else if (arg0.getType().equals(typeString) || arg1.getType().equals(typeString)) { + result = (sArg0.toString().equals(sArg1.toString())); } if (result) { return new Constant(true_); diff --git a/AlgebraicDataflowArchitectureModel/src/models/dataConstraintModel/JsonTerm.java b/AlgebraicDataflowArchitectureModel/src/models/dataConstraintModel/JsonTerm.java index 6c5d1eb..a5c1973 100644 --- a/AlgebraicDataflowArchitectureModel/src/models/dataConstraintModel/JsonTerm.java +++ b/AlgebraicDataflowArchitectureModel/src/models/dataConstraintModel/JsonTerm.java @@ -38,6 +38,16 @@ return getChild(keyToIndex.get(key.toString())); } + @Override + public Object clone() { + JsonTerm newTerm = new JsonTerm(); + for (Expression e: children) { + newTerm.addChild((Expression) e.clone()); + } + newTerm.keyToIndex = new HashMap(keyToIndex); + return newTerm; + } + public String toString() { String jsonStr = "{"; String delim = ""; diff --git a/AlgebraicDataflowArchitectureModel/src/models/dataConstraintModel/ListTerm.java b/AlgebraicDataflowArchitectureModel/src/models/dataConstraintModel/ListTerm.java index d70d476..de5b736 100644 --- a/AlgebraicDataflowArchitectureModel/src/models/dataConstraintModel/ListTerm.java +++ b/AlgebraicDataflowArchitectureModel/src/models/dataConstraintModel/ListTerm.java @@ -1,5 +1,7 @@ package models.dataConstraintModel; +import java.util.HashMap; + import models.algebra.Expression; import models.algebra.Symbol; import models.algebra.Term; @@ -19,6 +21,15 @@ return getChild(index); } + @Override + public Object clone() { + ListTerm newTerm = new ListTerm(); + for (Expression e: children) { + newTerm.addChild((Expression) e.clone()); + } + return newTerm; + } + public String toString() { String listStr = "["; String delim = ""; diff --git a/AlgebraicDataflowArchitectureModel/src/models/dataConstraintModel/MapTerm.java b/AlgebraicDataflowArchitectureModel/src/models/dataConstraintModel/MapTerm.java index 34792f6..3646146 100644 --- a/AlgebraicDataflowArchitectureModel/src/models/dataConstraintModel/MapTerm.java +++ b/AlgebraicDataflowArchitectureModel/src/models/dataConstraintModel/MapTerm.java @@ -38,6 +38,16 @@ return getChild(keyToIndex.get(key.toString())); } + @Override + public Object clone() { + MapTerm newTerm = new MapTerm(); + for (Expression e: children) { + newTerm.addChild((Expression) e.clone()); + } + newTerm.keyToIndex = new HashMap(keyToIndex); + return newTerm; + } + public String toString() { String mapStr = "{"; String delim = ""; diff --git a/AlgebraicDataflowArchitectureModel/src/simulator/ChannelState.java b/AlgebraicDataflowArchitectureModel/src/simulator/ChannelState.java index 9fd4993..ce4424e 100644 --- a/AlgebraicDataflowArchitectureModel/src/simulator/ChannelState.java +++ b/AlgebraicDataflowArchitectureModel/src/simulator/ChannelState.java @@ -10,7 +10,7 @@ import models.dataConstraintModel.Selector; import models.dataFlowModel.DataTransferChannel; -public class ChannelState { +public class ChannelState implements Cloneable { private DataTransferChannel channel; private ReferenceStructure referenceStructure; @@ -52,7 +52,13 @@ referenceStructure.addDependingParamAndValue(channelValues, dependingVariable, itsValue); } - private static class ReferenceStructure { + public Object clone() { + ChannelState newChannelState = new ChannelState(channel); + newChannelState.referenceStructure = (ReferenceStructure) referenceStructure.clone(); + return newChannelState; + } + + private static class ReferenceStructure implements Cloneable { private Map dependingParamAndValues = null; private Map referenceStructure; @@ -130,5 +136,19 @@ public ReferenceStructure getReferenceStructure(Constant channelParam) { return referenceStructure.get(channelParam); } + + public Object clone() { + ReferenceStructure newReferenceStructure = new ReferenceStructure(); + if (dependingParamAndValues != null) { + newReferenceStructure.dependingParamAndValues = new HashMap<>(dependingParamAndValues); + } + if (referenceStructure != null) { + newReferenceStructure.referenceStructure = new HashMap<>(); + for (Map.Entry refEnt: referenceStructure.entrySet()) { + newReferenceStructure.referenceStructure.put(refEnt.getKey(), (ReferenceStructure) refEnt.getValue().clone()); + } + } + return newReferenceStructure; + } } } diff --git a/AlgebraicDataflowArchitectureModel/src/simulator/Event.java b/AlgebraicDataflowArchitectureModel/src/simulator/Event.java index b0bce8c..643be88 100644 --- a/AlgebraicDataflowArchitectureModel/src/simulator/Event.java +++ b/AlgebraicDataflowArchitectureModel/src/simulator/Event.java @@ -55,7 +55,7 @@ } ancestor = ancestor.getParent(); } - channelSelectorAndValues.add(new AbstractMap.SimpleEntry<>(sel, ancestor.getParameter())); + if (ancestor!= null) channelSelectorAndValues.add(new AbstractMap.SimpleEntry<>(sel, ancestor.getParameter())); } } diff --git a/AlgebraicDataflowArchitectureModel/src/simulator/Resource.java b/AlgebraicDataflowArchitectureModel/src/simulator/Resource.java index 48dad8f..23254b8 100644 --- a/AlgebraicDataflowArchitectureModel/src/simulator/Resource.java +++ b/AlgebraicDataflowArchitectureModel/src/simulator/Resource.java @@ -1,16 +1,13 @@ package simulator; -import java.util.ArrayList; import java.util.Collection; import java.util.LinkedHashMap; -import java.util.List; import java.util.Map; import models.algebra.Constant; import models.algebra.Type; import models.dataConstraintModel.DataConstraintModel; import models.dataConstraintModel.ResourceHierarchy; -import models.dataConstraintModel.ResourcePath; import simulator.states.*; public class Resource { @@ -20,6 +17,13 @@ private ResourceState state = null; private Constant parameter = null; + public Resource(Resource resource) { + this.resourceHierarchy = resource.resourceHierarchy; + this.parent = resource.parent; + this.state = (ResourceState) resource.state.clone(); + this.parameter = resource.parameter; + } + public Resource(ResourceHierarchy resourceHierarchy) { this.resourceHierarchy = resourceHierarchy; Type resType = resourceHierarchy.getResourceStateType(); diff --git a/AlgebraicDataflowArchitectureModel/src/simulator/Simulator.java b/AlgebraicDataflowArchitectureModel/src/simulator/Simulator.java index 2338858..b819fe9 100644 --- a/AlgebraicDataflowArchitectureModel/src/simulator/Simulator.java +++ b/AlgebraicDataflowArchitectureModel/src/simulator/Simulator.java @@ -31,6 +31,7 @@ public class Simulator { private DataTransferModel model; private SystemState curState; + private List systemReceivers = new ArrayList<>(); private Map> nativeReceivers = new HashMap<>(); private Map nativeChannelReceivers = new HashMap<>(); @@ -80,9 +81,16 @@ fireEvent(inputEvent, curState, nextSystemState); curState = nextSystemState; + for (INativeReceiver receiver: systemReceivers) { + receiver.onReceiveFromModel(inputEvent, nextSystemState); + } return nextSystemState; } + public void addSystemReceiver(INativeReceiver receiver) { + systemReceivers.add(receiver); + } + public void addNativeReceiver(INativeReceiver receiver, DataTransferChannel channel) { nativeChannelReceivers.put(channel, receiver); } @@ -96,6 +104,10 @@ receivers.put(resource, receiver); } + public void removeSystemReceiver(INativeReceiver receiver) { + systemReceivers.remove(receiver); + } + public void removeNativeReceiver(DataTransferChannel channel) { nativeChannelReceivers.remove(channel); } @@ -175,10 +187,10 @@ } else if (channel.isNative()) { // A native output event channel INativeReceiver receiver = nativeChannelReceivers.get(channel); // receiver for the channel - if (receiver != null) receiver.onReceiveFromModel(event); + if (receiver != null) receiver.onReceiveFromModel(event, nextSystemState); if (nativeReceivers.get(channel) != null) { receiver = nativeReceivers.get(channel).get(event.getInputResource()); // receiver for the channel and resource - if (receiver != null) receiver.onReceiveFromModel(event); + if (receiver != null) receiver.onReceiveFromModel(event, nextSystemState); } } } @@ -189,11 +201,13 @@ IResourceStateValueProvider resourceStateValueProvider = new IResourceStateValueProvider() { @Override public Expression getCurrentStateValueOf(ResourceIdentifier resId) { + if (curSystemState.getResource(resId) == null) return null; return curSystemState.getResource(resId).getState().getValue(); } @Override public Expression getNextStateValueOf(ResourceIdentifier resId) { + if (nextSystemState.getResource(resId).getState() == null) return null; return nextSystemState.getResource(resId).getState().getValue(); } }; diff --git a/AlgebraicDataflowArchitectureModel/src/simulator/SystemState.java b/AlgebraicDataflowArchitectureModel/src/simulator/SystemState.java index 8f5037e..4ae4020 100644 --- a/AlgebraicDataflowArchitectureModel/src/simulator/SystemState.java +++ b/AlgebraicDataflowArchitectureModel/src/simulator/SystemState.java @@ -31,8 +31,16 @@ } public SystemState(SystemState prevState) { - rootResources = new HashSet<>(prevState.getRootResources()); - channelStates = new HashMap<>(prevState.getChannelStates()); + for (Resource resource: prevState.getRootResources()) { + rootResources.add(new Resource(resource)); + } + for (Map.Entry channelEnt: prevState.getChannelStates().entrySet()) { + if (channelEnt.getValue() != null) { + channelStates.put(channelEnt.getKey(), (ChannelState) channelEnt.getValue().clone()); + } else { + channelStates.put(channelEnt.getKey(), null); + } + } } public Set getRootResources() { diff --git a/AlgebraicDataflowArchitectureModel/src/simulator/interfaces/INativeReceiver.java b/AlgebraicDataflowArchitectureModel/src/simulator/interfaces/INativeReceiver.java index 50e651e..296506a 100644 --- a/AlgebraicDataflowArchitectureModel/src/simulator/interfaces/INativeReceiver.java +++ b/AlgebraicDataflowArchitectureModel/src/simulator/interfaces/INativeReceiver.java @@ -1,7 +1,8 @@ package simulator.interfaces; import simulator.Event; +import simulator.SystemState; public interface INativeReceiver { - public void onReceiveFromModel(Event event); + public void onReceiveFromModel(Event event, SystemState nextSystemState); } diff --git a/AlgebraicDataflowArchitectureModel/src/simulator/interfaces/html/HtmlElement.java b/AlgebraicDataflowArchitectureModel/src/simulator/interfaces/html/HtmlElement.java index 1f2480d..0373165 100644 --- a/AlgebraicDataflowArchitectureModel/src/simulator/interfaces/html/HtmlElement.java +++ b/AlgebraicDataflowArchitectureModel/src/simulator/interfaces/html/HtmlElement.java @@ -4,6 +4,7 @@ import java.util.Map; import models.algebra.Constant; +import models.dataConstraintModel.JsonTerm; import models.dataConstraintModel.MapTerm; public class HtmlElement { @@ -12,6 +13,7 @@ private final String id; private String text; private Map styles; + private IRestEventListener restEventListener; HtmlElement(String type, String id, String text){ this.type = type; @@ -30,18 +32,23 @@ public MapTerm toMap() { MapTerm res = new MapTerm(); - res.insert("type", new Constant(type)); - res.insert("id", new Constant(id)); - res.insert("text", new Constant(text)); + res.insert("\"type\"", new Constant("\"" + type + "\"")); + res.insert("\"id\"", new Constant(id)); + res.insert("\"text\"", new Constant(text)); MapTerm stylesMap = new MapTerm(); for(String prop : styles.keySet()) { stylesMap.insert(prop, new Constant(styles.get(prop))); } - res.insert("styles", stylesMap); + res.insert("\"styles\"", stylesMap); return res; } + public void onRestEvent(String method, JsonTerm message) { + restEventListener.onEvent(method, message); + } + + public String getType() { return type; } @@ -57,5 +64,9 @@ public void setText(String text) { this.text = text; } + + public void setRestEventListener(IRestEventListener event) { + this.restEventListener = event; + } } diff --git a/AlgebraicDataflowArchitectureModel/src/simulator/interfaces/html/HtmlElementMouseSender.java b/AlgebraicDataflowArchitectureModel/src/simulator/interfaces/html/HtmlElementMouseSender.java new file mode 100644 index 0000000..ab2d513 --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/src/simulator/interfaces/html/HtmlElementMouseSender.java @@ -0,0 +1,38 @@ +package simulator.interfaces.html; + +import models.algebra.Constant; +import models.algebra.Expression; +import models.algebra.Term; +import models.dataConstraintModel.DataConstraintModel; +import models.dataConstraintModel.JsonTerm; +import models.dataConstraintModel.ResourcePath; +import models.dataFlowModel.DataTransferChannel; +import simulator.Resource; +import simulator.Simulator; +import simulator.interfaces.NativeSender; + +public class HtmlElementMouseSender extends NativeSender implements IRestEventListener{ + + public HtmlElementMouseSender(Simulator simulator, DataTransferChannel channel, ResourcePath resourcePath, + Resource resource) { + super(simulator, channel, resourcePath, resource); + } + + @Override + public void onEvent(String method, JsonTerm message) { + if(method.equals("onMousePressed")) { + Constant one = new Constant("1", DataConstraintModel.typeInt); + Expression eventMessage = channel.getOutputChannelMembers().iterator().next().getStateTransition().getMessageExpression(); + Term termMessage = (Term)eventMessage.clone(); + termMessage.setChild(0, one); + sendToModel(termMessage); + } else if(method.equals("onMouseReleased")) { + Constant zero = new Constant("0", DataConstraintModel.typeInt); + Expression eventMessage = channel.getOutputChannelMembers().iterator().next().getStateTransition().getMessageExpression(); + Term termMessage = (Term) eventMessage.clone(); + termMessage.setChild(0, zero); + sendToModel(termMessage); + } + } + +} diff --git a/AlgebraicDataflowArchitectureModel/src/simulator/interfaces/html/HtmlElementTextReceiver.java b/AlgebraicDataflowArchitectureModel/src/simulator/interfaces/html/HtmlElementTextReceiver.java new file mode 100644 index 0000000..5998a45 --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/src/simulator/interfaces/html/HtmlElementTextReceiver.java @@ -0,0 +1,42 @@ +package simulator.interfaces.html; + +import models.algebra.Constant; +import models.algebra.Expression; +import models.algebra.Term; +import models.dataConstraintModel.JsonTerm; +import models.dataConstraintModel.MapTerm; +import simulator.Event; +import simulator.SystemState; +import simulator.interfaces.INativeReceiver; + +public class HtmlElementTextReceiver implements INativeReceiver{ + + protected HtmlElement element; + private final IWebSocketMessageSender ws; + + public HtmlElementTextReceiver(HtmlElement elem, IWebSocketMessageSender ws) { + this.ws = ws; + element = elem; + } + + @Override + public void onReceiveFromModel(Event event, SystemState nextSystemState) { + Expression message = event.getMessage(); + if (message instanceof Term) { + Expression text = ((Term) message).getChild(0); + if(text instanceof Constant) { + element.setText(text.toString()); + + JsonTerm json = new JsonTerm(); + json.addMember("\"method\"", new Constant("\"changeText\"")); + json.addMember("\"id\"", new Constant(element.getId())); + MapTerm datas = new MapTerm(); + datas.insert("\"newText\"", new Constant(text.toString())); + json.addMember("\"datas\"", datas); + + ws.send(json.toString()); + } + } + } + +} diff --git a/AlgebraicDataflowArchitectureModel/src/simulator/interfaces/html/HtmlElementTextSender.java b/AlgebraicDataflowArchitectureModel/src/simulator/interfaces/html/HtmlElementTextSender.java new file mode 100644 index 0000000..7fdf1be --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/src/simulator/interfaces/html/HtmlElementTextSender.java @@ -0,0 +1,34 @@ +package simulator.interfaces.html; + +import models.algebra.Constant; +import models.algebra.Expression; +import models.algebra.Term; +import models.dataConstraintModel.DataConstraintModel; +import models.dataConstraintModel.JsonTerm; +import models.dataConstraintModel.ResourcePath; +import models.dataFlowModel.DataTransferChannel; +import simulator.Resource; +import simulator.Simulator; +import simulator.interfaces.NativeSender; + +public class HtmlElementTextSender extends NativeSender implements IRestEventListener{ + + public HtmlElementTextSender(Simulator simulator, DataTransferChannel channel, ResourcePath resourcePath, + Resource resource) { + super(simulator, channel, resourcePath, resource); + } + + @Override + public void onEvent(String method, JsonTerm message) { + if(method.equals("onTextChanged")) { + String newText = message.get("newText").toString(); + System.out.println(newText); + Constant text = new Constant(newText, DataConstraintModel.typeString); + Expression sendMessage = channel.getOutputChannelMembers().iterator().next().getStateTransition().getMessageExpression(); + Term termMessage = (Term)sendMessage.clone(); + termMessage.setChild(0, text); + sendToModel(termMessage); + } + } + +} diff --git a/AlgebraicDataflowArchitectureModel/src/simulator/interfaces/html/HtmlElementVisibilityReceiver.java b/AlgebraicDataflowArchitectureModel/src/simulator/interfaces/html/HtmlElementVisibilityReceiver.java index e264a89..3d981e4 100644 --- a/AlgebraicDataflowArchitectureModel/src/simulator/interfaces/html/HtmlElementVisibilityReceiver.java +++ b/AlgebraicDataflowArchitectureModel/src/simulator/interfaces/html/HtmlElementVisibilityReceiver.java @@ -7,13 +7,11 @@ import models.dataConstraintModel.JsonTerm; import models.dataConstraintModel.MapTerm; import simulator.Event; +import simulator.SystemState; import simulator.interfaces.INativeReceiver; public class HtmlElementVisibilityReceiver implements INativeReceiver{ - //HtmlElementにwebsocketのインスタンスを渡さない場合こちらに必要 - //見えるかどうかの変更があった場合、html(クライアント側)へwebsocket messageを送る必要がある - // protected HtmlElement element; private final IWebSocketMessageSender ws; @@ -24,7 +22,7 @@ } @Override - public void onReceiveFromModel(Event event) { + public void onReceiveFromModel(Event event, SystemState nextSystemState) { Expression message = event.getMessage(); if (message instanceof Term) { Expression visible = ((Term) message).getChild(0); diff --git a/AlgebraicDataflowArchitectureModel/src/simulator/interfaces/html/HtmlPresenter.java b/AlgebraicDataflowArchitectureModel/src/simulator/interfaces/html/HtmlPresenter.java index bd32c17..b6c4736 100644 --- a/AlgebraicDataflowArchitectureModel/src/simulator/interfaces/html/HtmlPresenter.java +++ b/AlgebraicDataflowArchitectureModel/src/simulator/interfaces/html/HtmlPresenter.java @@ -7,124 +7,238 @@ import models.algebra.Constant; import models.algebra.Expression; +import models.algebra.Term; import models.dataConstraintModel.JsonTerm; import models.dataConstraintModel.ListTerm; import models.dataConstraintModel.MapTerm; +import models.dataConstraintModel.ResourcePath; import models.dataFlowModel.DataTransferChannel; import simulator.Event; import simulator.Resource; import simulator.Simulator; +import simulator.SystemState; import simulator.interfaces.INativeReceiver; public class HtmlPresenter implements INativeReceiver{ - + public final String screenUpdateChannelName = "ScreenUpdate"; public final String setVisibleChannelName = "SetVisible"; + public final String setTextChannelName = "SetText"; public final String mouseEventChannelName = "MouseEvent"; public final String textEventChannelName = "TextEvent"; - + protected Simulator simulator; protected DataTransferChannel screenUpdateChannel; protected DataTransferChannel setVisibleChannel; protected DataTransferChannel mouseEventChannel; protected DataTransferChannel textEventChannel; - - protected Map> channelAndResourcesForReceiving = new HashMap<>();// ??? - + protected DataTransferChannel setTextChannel; + + protected Map> channelAndResourcesForReceiving = new HashMap<>(); + protected Map elements; - + protected IWebSocketMessageSender ws; - public HtmlPresenter(Simulator simulator, IWebSocketMessageSender ws) { + + public HtmlPresenter(Simulator simulator, IWebSocketMessageSender ws, Map elems) { this.simulator = simulator; this.ws = ws; screenUpdateChannel = (DataTransferChannel) simulator.getModel().getChannel(screenUpdateChannelName); setVisibleChannel = (DataTransferChannel) simulator.getModel().getChannel(setVisibleChannelName); mouseEventChannel = (DataTransferChannel) simulator.getModel().getInputChannel(mouseEventChannelName); + setTextChannel = (DataTransferChannel) simulator.getModel().getChannel(setTextChannelName); textEventChannel = (DataTransferChannel) simulator.getModel().getInputChannel(textEventChannelName); simulator.addNativeReceiver(this, screenUpdateChannel); + + elements = elems; + } + + + @Override + public void onReceiveFromModel(Event event, SystemState nextSystemState) { + //画面遷移するときに呼ばれそう + + Expression message = event.getMessage(); + + if (message instanceof Term && ((Term) message).getChildren().size() >= 2) { + Expression curScExp = ((Term) message).getChild(0); + Expression nextScExp = ((Term) message).getChild(1); + + if (curScExp instanceof JsonTerm && nextScExp instanceof JsonTerm) { + + JsonTerm sendData = new JsonTerm(); + sendData.addMember("\"method\"", new Constant("\"updateHtml\"")); + JsonTerm sendElements = new JsonTerm(); + ListTerm addElements = new ListTerm(); + ListTerm delElements = new ListTerm(); + + JsonTerm curSc = (JsonTerm) curScExp; + JsonTerm nextSc = (JsonTerm) nextScExp; + Expression oldWidgets = curSc.get("widgets"); + Expression newWidgets = nextSc.get("widgets"); + + if (oldWidgets instanceof MapTerm && newWidgets instanceof MapTerm) { + + Set oldWidSet = new HashSet<>(((MapTerm) oldWidgets).keySet()); + Set newWidSet = new HashSet<>(((MapTerm) newWidgets).keySet()); + oldWidSet.removeAll(((MapTerm) newWidgets).keySet()); + newWidSet.removeAll(((MapTerm)oldWidgets).keySet()); + + if(!oldWidSet.isEmpty()) { + deleteOldWidgets(oldWidSet, delElements); + } + + if (!newWidSet.isEmpty()) { + addNewWidgets(newWidSet, nextSystemState, event, newWidgets, addElements); + } + } + + sendElements.addMember("\"add\"", addElements); + sendElements.addMember("\"delete\"", delElements); + sendData.addMember("\"data\"", sendElements); + ws.send(sendData.toString()); + } + } + } + + + private void addNewWidgets(Set newWidSet, SystemState nextSystemState, Event event, Expression newWidgets, ListTerm addElements) { + + Resource screenResource = nextSystemState.getResource(event.getInputResource().getResourceIdentifier()); + Resource widgetsResource = screenResource.getChildrenMap().get("widgets"); + for(String newWid: newWidSet) { + Expression value = ((MapTerm) newWidgets).get(newWid); + if(value instanceof JsonTerm) { + JsonTerm widget = (JsonTerm) value; + Resource widgetResource = widgetsResource.getChildrenMap().get(newWid); + Expression type = widget.get("\"type\""); + + switch(type.toString()) { + case "\"button\"": + addButton(widget, newWid, addElements, widgetResource); + break; + case "\"label\"": + addLabel(widget, newWid, addElements, widgetResource); + break; + case "\"textInput\"": + addTextInput(widget, newWid, addElements, widgetResource); + break; + } + } + } + + } + + private void addButton(JsonTerm widget, String wid, ListTerm addElements, Resource widgetResource) { + String text = widget.get("\"text\"").toString(); + HtmlElement button = new HtmlElement("button", wid, text); - elements = new HashMap<>(); + //ボタンが押されたり離されたりした時を検知 + ResourcePath resPath = mouseEventChannel.getOutputResources().iterator().next(); + button.setRestEventListener(new HtmlElementMouseSender(simulator, mouseEventChannel, resPath, widgetResource)); + + //ボタンが透明になったことを通知 + HtmlElementVisibilityReceiver nativeVisibilityReceiver = new HtmlElementVisibilityReceiver(button, ws); + simulator.addNativeReceiver(nativeVisibilityReceiver, setVisibleChannel, widgetResource); + Map resources = channelAndResourcesForReceiving.get(setVisibleChannel); + if (resources == null) { + resources = new HashMap<>(); + channelAndResourcesForReceiving.put(setVisibleChannel, resources); + } + resources.put(wid, widgetResource); + + //ボタンの文字が変わったことを通知 + HtmlElementTextReceiver nativeTextReceiver = new HtmlElementTextReceiver(button, ws); + simulator.addNativeReceiver(nativeTextReceiver, setTextChannel, widgetResource); + resources = channelAndResourcesForReceiving.get(setTextChannel); + if (resources == null) { + resources = new HashMap<>(); + channelAndResourcesForReceiving.put(setTextChannel, resources); + } + resources.put(wid, widgetResource); + + elements.put(wid, button); + addElements.append(button.toMap()); } - @Override - public void onReceiveFromModel(Event event) { - //画面遷移するときに呼ばれそう + private void addLabel(JsonTerm widget, String wid, ListTerm addElements, Resource widgetResource) { + String text = widget.get("\"text\"").toString(); + HtmlElement label = new HtmlElement("label", wid, text); + //ボタンが透明になったことを通知 + HtmlElementVisibilityReceiver nativeVisibilityReceiver = new HtmlElementVisibilityReceiver(label, ws); + simulator.addNativeReceiver(nativeVisibilityReceiver, setVisibleChannel, widgetResource); + Map resources = channelAndResourcesForReceiving.get(setVisibleChannel); + if (resources == null) { + resources = new HashMap<>(); + channelAndResourcesForReceiving.put(setVisibleChannel, resources); + } + resources.put(wid, widgetResource); - Expression message = event.getMessage(); + //ボタンの文字が変わったことを通知 + HtmlElementTextReceiver nativeTextReceiver = new HtmlElementTextReceiver(label, ws); + simulator.addNativeReceiver(nativeTextReceiver, setTextChannel, widgetResource); + resources = channelAndResourcesForReceiving.get(setTextChannel); + if (resources == null) { + resources = new HashMap<>(); + channelAndResourcesForReceiving.put(setTextChannel, resources); + } + resources.put(wid, widgetResource); - // Remove old native receivers. - if (message instanceof JsonTerm) { - - for (DataTransferChannel channel : channelAndResourcesForReceiving.keySet()) { - for (Resource resource : channelAndResourcesForReceiving.get(channel)) { + elements.put(wid, label); + addElements.append(label.toMap()); + } + + private void addTextInput(JsonTerm widget, String wid, ListTerm addElements, Resource widgetResource) { + String text = widget.get("\"text\"").toString(); + HtmlElement textInput = new HtmlElement("textInput", wid, text); + + //文字の変更を検知 + ResourcePath resPath = textEventChannel.getOutputResources().iterator().next(); + textInput.setRestEventListener(new HtmlElementTextSender(simulator, textEventChannel, resPath, widgetResource)); + + //ボタンが透明になったことを通知 + HtmlElementVisibilityReceiver nativeVisibilityReceiver = new HtmlElementVisibilityReceiver(textInput, ws); + simulator.addNativeReceiver(nativeVisibilityReceiver, setVisibleChannel, widgetResource); + Map resources = channelAndResourcesForReceiving.get(setVisibleChannel); + if (resources == null) { + resources = new HashMap<>(); + channelAndResourcesForReceiving.put(setVisibleChannel, resources); + } + resources.put(wid, widgetResource); + + //ボタンの文字が変わったことを通知 + HtmlElementTextReceiver nativeTextReceiver = new HtmlElementTextReceiver(textInput, ws); + simulator.addNativeReceiver(nativeTextReceiver, setTextChannel, widgetResource); + resources = channelAndResourcesForReceiving.get(setTextChannel); + if (resources == null) { + resources = new HashMap<>(); + channelAndResourcesForReceiving.put(setTextChannel, resources); + } + resources.put(wid, widgetResource); + + elements.put(wid, textInput); + addElements.append(textInput.toMap()); + } + + + private void deleteOldWidgets(Set oldWidSet, ListTerm delElements) { + for (String oldWid : oldWidSet) { + elements.remove(oldWid); + //TODO + // del widgets + delElements.append(new Constant(oldWid)); + } + + for (DataTransferChannel channel : channelAndResourcesForReceiving.keySet()) { + Map widToResource = channelAndResourcesForReceiving.get(channel); + for (String oldWid: oldWidSet) { + Resource resource = widToResource.remove(oldWid); + if (resource != null) { simulator.removeNativeReceiver(channel, resource); } } - - channelAndResourcesForReceiving.clear(); - - JsonTerm screenContent = (JsonTerm) message; //受け取ったmessageをjsonとして扱う - Resource screenResource = simulator.getCurState().getResource(event.getInputResource().getResourceIdentifier()); //出力チャンネルに接続されたresourceを取得? - Expression widgets = screenContent.get("widgets"); //json化したmessageから"widgets"を取得 - Resource widgetsResource = screenResource.getChildrenMap().get("widgets");//??? - - elements.clear(); - - if(widgets instanceof MapTerm) { - for(String key : ((MapTerm) widgets).keySet()) { // keyはなに? どうやって決められる? - Expression value = ((MapTerm) widgets).get(key); //widgetの構成要素(text, typeなど)を持つjson, 一つのwidgetを表す? - if(value instanceof JsonTerm) { - JsonTerm widget = (JsonTerm) value; //jsonとして扱えるように - Resource widgetResouce = widgetsResource.getChildrenMap().get(key); //??? - Expression type = widget.get("\"type\""); //widgetのtypeを取得 - if(type.toString().equals("\"button\"")) { - - //こんな感じになりそう - Expression text = widget.get("\"text\""); - HtmlElement button = new HtmlElement(type.toString(), key, text.toString().replace("\"", "")); - elements.put(key, button); - - //ボタンが押された時の処理 - //ボタンが押されたかどうかをどうやって確認するか - //そもそもボタンが押されたらREST API が叩かれるのでは? - - //可視化、不可視化のやつ - HtmlElementVisibilityReceiver nativeReceiver = new HtmlElementVisibilityReceiver(button, ws); - simulator.addNativeReceiver(nativeReceiver, setVisibleChannel, widgetResouce); - Set resources = channelAndResourcesForReceiving.get(setVisibleChannel);//この辺謎 - if (resources == null) { - resources = new HashSet<>(); - channelAndResourcesForReceiving.put(setVisibleChannel, resources); - } - resources.add(widgetsResource); - - } else if(type.toString().equals("label")) { - - Expression text = widget.get("\"text\""); - HtmlElement elem = new HtmlElement(type.toString(), key, text.toString().replace("\"", "")); - elements.put(key, elem); - - } else if(type.toString().equals("inputText")) { - - HtmlElement elem = new HtmlElement(type.toString(), key, ""); - elements.put(key, elem); - - } - } - } - - JsonTerm json = new JsonTerm(); - json.addMember("method", new Constant("updateHtml")); - ListTerm elements = new ListTerm(); - for(String id : this.elements.keySet()) { - elements.append(this.elements.get(id).toMap()); - } - ws.send(json.toString()); - } - - } } diff --git a/AlgebraicDataflowArchitectureModel/src/simulator/interfaces/html/IRestEventListener.java b/AlgebraicDataflowArchitectureModel/src/simulator/interfaces/html/IRestEventListener.java new file mode 100644 index 0000000..58fc999 --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/src/simulator/interfaces/html/IRestEventListener.java @@ -0,0 +1,9 @@ +package simulator.interfaces.html; + +import models.dataConstraintModel.JsonTerm; + +public interface IRestEventListener { + + public void onEvent(String method, JsonTerm message); + +} diff --git a/AlgebraicDataflowArchitectureModel/src/simulator/interfaces/swing/ComponentTextReceiver.java b/AlgebraicDataflowArchitectureModel/src/simulator/interfaces/swing/ComponentTextReceiver.java index e110a67..69badc8 100644 --- a/AlgebraicDataflowArchitectureModel/src/simulator/interfaces/swing/ComponentTextReceiver.java +++ b/AlgebraicDataflowArchitectureModel/src/simulator/interfaces/swing/ComponentTextReceiver.java @@ -10,6 +10,7 @@ import models.algebra.Expression; import models.algebra.Term; import simulator.Event; +import simulator.SystemState; import simulator.interfaces.INativeReceiver; public class ComponentTextReceiver implements INativeReceiver { @@ -20,7 +21,7 @@ } @Override - public void onReceiveFromModel(Event event) { + public void onReceiveFromModel(Event event, SystemState nextSystemState) { Expression message = event.getMessage(); if (message instanceof Term) { Expression text = ((Term) message).getChild(0); diff --git a/AlgebraicDataflowArchitectureModel/src/simulator/interfaces/swing/ComponentTextSender.java b/AlgebraicDataflowArchitectureModel/src/simulator/interfaces/swing/ComponentTextSender.java index 4e13f41..c6580fd 100644 --- a/AlgebraicDataflowArchitectureModel/src/simulator/interfaces/swing/ComponentTextSender.java +++ b/AlgebraicDataflowArchitectureModel/src/simulator/interfaces/swing/ComponentTextSender.java @@ -1,8 +1,9 @@ package simulator.interfaces.swing; -import java.awt.TextField; -import java.awt.event.InputMethodEvent; -import java.awt.event.InputMethodListener; +import javax.swing.event.DocumentEvent; +import javax.swing.event.DocumentListener; +import javax.swing.text.BadLocationException; +import javax.swing.text.Document; import models.algebra.Constant; import models.algebra.Expression; @@ -14,23 +15,52 @@ import simulator.Simulator; import simulator.interfaces.NativeSender; -public class ComponentTextSender extends NativeSender implements InputMethodListener { +public class ComponentTextSender extends NativeSender implements DocumentListener { public ComponentTextSender(Simulator simulator, DataTransferChannel channel, ResourcePath resourcePath, Resource resource) { super(simulator, channel, resourcePath, resource); } @Override - public void inputMethodTextChanged(InputMethodEvent event) { - Constant text = new Constant(((TextField) event.getSource()).getText(), DataConstraintModel.typeString); - Expression message = channel.getOutputChannelMembers().iterator().next().getStateTransition().getMessageExpression(); - message = (Term) message.clone(); - ((Term) message).setChild(0, text); - sendToModel(message); + public void insertUpdate(DocumentEvent e) { + Document d = e.getDocument(); + try { + Constant text = new Constant(d.getText(0, d.getLength()), DataConstraintModel.typeString); + Expression message = channel.getOutputChannelMembers().iterator().next().getStateTransition().getMessageExpression(); + message = (Term) message.clone(); + ((Term) message).setChild(0, text); + sendToModel(message); + } catch (BadLocationException e1) { + e1.printStackTrace(); + } } @Override - public void caretPositionChanged(InputMethodEvent event) { + public void removeUpdate(DocumentEvent e) { + Document d = e.getDocument(); + try { + Constant text = new Constant(d.getText(0, d.getLength()), DataConstraintModel.typeString); + Expression message = channel.getOutputChannelMembers().iterator().next().getStateTransition().getMessageExpression(); + message = (Term) message.clone(); + ((Term) message).setChild(0, text); + sendToModel(message); + } catch (BadLocationException e1) { + e1.printStackTrace(); + } + } + + @Override + public void changedUpdate(DocumentEvent e) { + Document d = e.getDocument(); + try { + Constant text = new Constant(d.getText(0, d.getLength()), DataConstraintModel.typeString); + Expression message = channel.getOutputChannelMembers().iterator().next().getStateTransition().getMessageExpression(); + message = (Term) message.clone(); + ((Term) message).setChild(0, text); + sendToModel(message); + } catch (BadLocationException e1) { + e1.printStackTrace(); + } } } diff --git a/AlgebraicDataflowArchitectureModel/src/simulator/interfaces/swing/ComponentVisibilityReceiver.java b/AlgebraicDataflowArchitectureModel/src/simulator/interfaces/swing/ComponentVisibilityReceiver.java index 2527a52..447dae1 100644 --- a/AlgebraicDataflowArchitectureModel/src/simulator/interfaces/swing/ComponentVisibilityReceiver.java +++ b/AlgebraicDataflowArchitectureModel/src/simulator/interfaces/swing/ComponentVisibilityReceiver.java @@ -7,6 +7,7 @@ import models.algebra.Term; import models.dataConstraintModel.DataConstraintModel; import simulator.Event; +import simulator.SystemState; import simulator.interfaces.INativeReceiver; public class ComponentVisibilityReceiver implements INativeReceiver { @@ -17,7 +18,7 @@ } @Override - public void onReceiveFromModel(Event event) { + public void onReceiveFromModel(Event event, SystemState nextSystemState) { Expression message = event.getMessage(); if (message instanceof Term) { Expression visible = ((Term) message).getChild(0); diff --git a/AlgebraicDataflowArchitectureModel/src/simulator/interfaces/swing/SwingPresenter.java b/AlgebraicDataflowArchitectureModel/src/simulator/interfaces/swing/SwingPresenter.java index 68df398..e82372e 100644 --- a/AlgebraicDataflowArchitectureModel/src/simulator/interfaces/swing/SwingPresenter.java +++ b/AlgebraicDataflowArchitectureModel/src/simulator/interfaces/swing/SwingPresenter.java @@ -22,11 +22,13 @@ import simulator.Event; import simulator.Resource; import simulator.Simulator; +import simulator.SystemState; import simulator.interfaces.INativeReceiver; public class SwingPresenter implements INativeReceiver { public final String screenUpdateChannelName = "ScreenUpdate"; public final String setVisibleChannelName = "SetVisible"; + public final String setTextChannelName = "SetText"; public final String mouseEventChannelName = "MouseEvent"; public final String textEventChannelName = "TextEvent"; @@ -35,9 +37,10 @@ protected Map components; protected DataTransferChannel screenUpdateChannel; protected DataTransferChannel setVisibleChannel; + protected DataTransferChannel setTextChannel; protected DataTransferChannel mouseEventChannel; protected DataTransferChannel textEventChannel; - protected Map> channelAndResourcesForReceiving = new HashMap<>(); + protected Map> channelAndResourcesForReceiving = new HashMap<>(); public SwingPresenter(JPanel mainPanel, Simulator simulator) { this.mainPanel = mainPanel; @@ -45,92 +48,131 @@ components = new HashMap<>(); screenUpdateChannel = (DataTransferChannel) simulator.getModel().getChannel(screenUpdateChannelName); setVisibleChannel = (DataTransferChannel) simulator.getModel().getChannel(setVisibleChannelName); + setTextChannel = (DataTransferChannel) simulator.getModel().getChannel(setTextChannelName); mouseEventChannel = (DataTransferChannel) simulator.getModel().getInputChannel(mouseEventChannelName); textEventChannel = (DataTransferChannel) simulator.getModel().getInputChannel(textEventChannelName); simulator.addNativeReceiver(this, screenUpdateChannel); } @Override - public void onReceiveFromModel(Event event) { + public void onReceiveFromModel(Event event, SystemState nextSystemState) { Expression message = event.getMessage(); - 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) { - 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); + if (message instanceof Term && ((Term) message).getChildren().size() >= 2) { + Expression curScExp = ((Term) message).getChild(0); + Expression nextScExp = ((Term) message).getChild(1); + if (curScExp instanceof JsonTerm && nextScExp instanceof JsonTerm) { + JsonTerm curSc = (JsonTerm) curScExp; + JsonTerm nextSc = (JsonTerm) nextScExp; + Expression oldWidgets = curSc.get("widgets"); + Expression newWidgets = nextSc.get("widgets"); + if (oldWidgets instanceof MapTerm && newWidgets instanceof MapTerm) { + Set oldWidSet = new HashSet<>(((MapTerm) oldWidgets).keySet()); + Set newWidSet = new HashSet<>(((MapTerm) newWidgets).keySet()); + oldWidSet.removeAll(((MapTerm) newWidgets).keySet()); + newWidSet.removeAll(((MapTerm) oldWidgets).keySet()); + if (!oldWidSet.isEmpty() || !newWidSet.isEmpty()) { + // If the set of screen components is changed. + + // Remove old components and their native receivers. + for (String oldWid: oldWidSet) { + mainPanel.remove(components.get(oldWid)); + } + + for (DataTransferChannel channel: channelAndResourcesForReceiving.keySet()) { + Map widToResource = channelAndResourcesForReceiving.get(channel); + for (String oldWid: oldWidSet) { + Resource resource = widToResource.remove(oldWid); + if (resource != null) { + simulator.removeNativeReceiver(channel, resource); } - 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); } } + + // Add new swing components. + Resource screenResource = nextSystemState.getResource(event.getInputResource().getResourceIdentifier()); + Resource widgetsResource = screenResource.getChildrenMap().get("widgets"); + for (String newWid: newWidSet) { + Expression value = ((MapTerm) newWidgets).get(newWid); + if (value instanceof JsonTerm) { + JsonTerm widget = (JsonTerm) value; + Resource widgetResource = widgetsResource.getChildrenMap().get(newWid); + 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(newWid, button); + // Connect swing component and model. + ResourcePath resPath = mouseEventChannel.getOutputResources().iterator().next(); + button.addMouseListener(new ComponentMouseSender(simulator, mouseEventChannel, resPath, widgetResource)); // button => widgetResource + + ComponentVisibilityReceiver nativeVisibilityReceiver = new ComponentVisibilityReceiver(button); // widgetResource => button + simulator.addNativeReceiver(nativeVisibilityReceiver, setVisibleChannel, widgetResource); + Map resources = channelAndResourcesForReceiving.get(setVisibleChannel); + if (resources == null) { + resources = new HashMap<>(); + channelAndResourcesForReceiving.put(setVisibleChannel, resources); + } + resources.put(newWid, widgetsResource); + + ComponentTextReceiver nativeTextReceiver = new ComponentTextReceiver(button); // widgetResource => button + simulator.addNativeReceiver(nativeTextReceiver, setTextChannel, widgetResource); + resources = channelAndResourcesForReceiving.get(setTextChannel); + if (resources == null) { + resources = new HashMap<>(); + channelAndResourcesForReceiving.put(setTextChannel, resources); + } + resources.put(newWid, 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(newWid, label); + + // Connect swing component and model. + ComponentVisibilityReceiver nativeVisibilityReceiver = new ComponentVisibilityReceiver(label); // widgetResource => label + simulator.addNativeReceiver(nativeVisibilityReceiver, setVisibleChannel, widgetResource); + Map resources = channelAndResourcesForReceiving.get(setVisibleChannel); + if (resources == null) { + resources = new HashMap<>(); + channelAndResourcesForReceiving.put(setVisibleChannel, resources); + } + resources.put(newWid, widgetsResource); + + ComponentTextReceiver nativeTextReceiver = new ComponentTextReceiver(label); // widgetResource => label + simulator.addNativeReceiver(nativeTextReceiver, setTextChannel, widgetResource); + resources = channelAndResourcesForReceiving.get(setTextChannel); + if (resources == null) { + resources = new HashMap<>(); + channelAndResourcesForReceiving.put(setTextChannel, resources); + } + resources.put(newWid, widgetsResource); + } else if (type.toString().equals("\"textInput\"")) { + // Add a text input component. + JTextField textField = new JTextField(10); + mainPanel.add(textField); + components.put(newWid, textField); + // Connect swing component and model. + ResourcePath resPath = textEventChannel.getOutputResources().iterator().next(); + textField.getDocument().addDocumentListener(new ComponentTextSender(simulator, textEventChannel, resPath, widgetResource)); // textField => widgetResource + + ComponentVisibilityReceiver nativeReceiver = new ComponentVisibilityReceiver(textField); // widgetResource => textField + simulator.addNativeReceiver(nativeReceiver, setVisibleChannel, widgetResource); + Map resources = channelAndResourcesForReceiving.get(setVisibleChannel); + if (resources == null) { + resources = new HashMap<>(); + channelAndResourcesForReceiving.put(setVisibleChannel, resources); + } + resources.put(newWid, widgetsResource); + } + } + } + mainPanel.invalidate(); + mainPanel.validate(); + mainPanel.repaint(); } - mainPanel.invalidate(); - mainPanel.validate(); - mainPanel.repaint(); } } } diff --git a/AlgebraicDataflowArchitectureModel/src/simulator/states/JsonResourceState.java b/AlgebraicDataflowArchitectureModel/src/simulator/states/JsonResourceState.java index cf4ce2b..20909c6 100644 --- a/AlgebraicDataflowArchitectureModel/src/simulator/states/JsonResourceState.java +++ b/AlgebraicDataflowArchitectureModel/src/simulator/states/JsonResourceState.java @@ -39,4 +39,12 @@ } } } + + public Object clone() { + JsonResourceState newJsonResourceState = new JsonResourceState(); + for (String key: children.keySet()) { + newJsonResourceState.children.put(key, (ResourceState) children.get(key).clone()); + } + return newJsonResourceState; + } } diff --git a/AlgebraicDataflowArchitectureModel/src/simulator/states/ListResourceState.java b/AlgebraicDataflowArchitectureModel/src/simulator/states/ListResourceState.java index 0e45334..34eff54 100644 --- a/AlgebraicDataflowArchitectureModel/src/simulator/states/ListResourceState.java +++ b/AlgebraicDataflowArchitectureModel/src/simulator/states/ListResourceState.java @@ -45,4 +45,12 @@ } } } + + public Object clone() { + ListResourceState newListResourceState = new ListResourceState(); + for (ResourceState state: children) { + newListResourceState.children.add((ResourceState) state.clone()); + } + return newListResourceState; + } } diff --git a/AlgebraicDataflowArchitectureModel/src/simulator/states/MapResourceState.java b/AlgebraicDataflowArchitectureModel/src/simulator/states/MapResourceState.java index e03d70e..6071c51 100644 --- a/AlgebraicDataflowArchitectureModel/src/simulator/states/MapResourceState.java +++ b/AlgebraicDataflowArchitectureModel/src/simulator/states/MapResourceState.java @@ -39,4 +39,12 @@ } } } + + public Object clone() { + MapResourceState newMapResourceState = new MapResourceState(); + for (String key: children.keySet()) { + newMapResourceState.children.put(key, (ResourceState) children.get(key).clone()); + } + return newMapResourceState; + } } diff --git a/AlgebraicDataflowArchitectureModel/src/simulator/states/PrimitiveResourceState.java b/AlgebraicDataflowArchitectureModel/src/simulator/states/PrimitiveResourceState.java index d5aba63..adfb7f3 100644 --- a/AlgebraicDataflowArchitectureModel/src/simulator/states/PrimitiveResourceState.java +++ b/AlgebraicDataflowArchitectureModel/src/simulator/states/PrimitiveResourceState.java @@ -24,4 +24,8 @@ boolean hasChildren() { return false; } + + public Object clone() { + return this; + } } diff --git a/AlgebraicDataflowArchitectureModel/src/simulator/states/State.java b/AlgebraicDataflowArchitectureModel/src/simulator/states/State.java index f9286dd..2dfa5c0 100644 --- a/AlgebraicDataflowArchitectureModel/src/simulator/states/State.java +++ b/AlgebraicDataflowArchitectureModel/src/simulator/states/State.java @@ -2,6 +2,7 @@ import models.algebra.Expression; -abstract public class State { +abstract public class State implements Cloneable { abstract public Expression getValue(); + abstract public Object clone(); } diff --git a/AlgebraicDataflowArchitectureModel/src/tests/NativeAccessTest.java b/AlgebraicDataflowArchitectureModel/src/tests/NativeAccessTest.java index d9598b8..e014bab 100644 --- a/AlgebraicDataflowArchitectureModel/src/tests/NativeAccessTest.java +++ b/AlgebraicDataflowArchitectureModel/src/tests/NativeAccessTest.java @@ -81,7 +81,7 @@ }; INativeReceiver textReceiver = new INativeReceiver() { // Model to native code @Override - public void onReceiveFromModel(Event event) { // Receive a message from the model + public void onReceiveFromModel(Event event, SystemState nextSystemState) { // Receive a message from the model Expression message = event.getMessage(); System.out.println(message); }