diff --git a/AlgebraicDataflowArchitectureModel/src/application/editor/Editor.java b/AlgebraicDataflowArchitectureModel/src/application/editor/Editor.java index 346f738..b1b8bb6 100644 --- a/AlgebraicDataflowArchitectureModel/src/application/editor/Editor.java +++ b/AlgebraicDataflowArchitectureModel/src/application/editor/Editor.java @@ -187,6 +187,7 @@ if (extension.contains(".dtram")) { openDTRAM(file); } + setDAGLayout(); } private void openModel(File file) { diff --git a/AlgebraicDataflowArchitectureModel/src/application/editor/stages/PushPullSelectionStage.java b/AlgebraicDataflowArchitectureModel/src/application/editor/stages/PushPullSelectionStage.java index 70309d8..6e3020d 100644 --- a/AlgebraicDataflowArchitectureModel/src/application/editor/stages/PushPullSelectionStage.java +++ b/AlgebraicDataflowArchitectureModel/src/application/editor/stages/PushPullSelectionStage.java @@ -5,15 +5,22 @@ import application.editor.FlowCellEditor; import application.editor.Stage; import com.mxgraph.model.mxCell; +import com.mxgraph.model.mxGeometry; import com.mxgraph.model.mxGraphModel; import com.mxgraph.swing.mxGraphComponent; import com.mxgraph.util.mxEventSource.mxIEventListener; +import com.mxgraph.util.mxPoint; +import generators.JavaCodeGenerator; import models.Edge; +import models.algebra.*; +import models.dataConstraintModel.Channel; +import models.dataConstraintModel.ChannelMember; +import models.dataConstraintModel.ResourcePath; +import models.dataConstraintModel.Selector; import models.dataFlowModel.*; import java.awt.event.MouseListener; -import java.util.ArrayList; -import java.util.List; +import java.util.*; public class PushPullSelectionStage extends Stage { @@ -28,6 +35,7 @@ if (prevStage instanceof DataFlowModelingStage) { model = prevStage.getModel(); dataFlowGraph = analyzeDataTransferModel(model); + constructGraph(); } } @@ -109,6 +117,171 @@ graph.refresh(); } + /** + * Construct a mxGraph from DataFlowGraph + */ + public void constructGraph() { + ((mxGraphModel) graph.getModel()).clear(); + Object parent = graph.getDefaultParent(); + graph.getModel().beginUpdate(); + try { + mxGeometry geo1 = new mxGeometry(0, 0.5, PORT_DIAMETER, PORT_DIAMETER); + geo1.setOffset(new mxPoint(-PORT_RADIUS, -PORT_RADIUS)); + geo1.setRelative(true); + + mxGeometry geo2 = new mxGeometry(1.0, 0.5, PORT_DIAMETER, PORT_DIAMETER); + geo2.setOffset(new mxPoint(-PORT_RADIUS, -PORT_RADIUS)); + geo2.setRelative(true); + + Map channelsIn = new HashMap<>(); + Map channelsOut = new HashMap<>(); + Map resources = new HashMap<>(); + + // create resource vertices + for (ResourceNode resNode : dataFlowGraph.getRootResourceNodes()) { + int w = 80; + int h = 30; + ResourcePath res = resNode.getPrimaryResourcePath(); + Object resource = graph.insertVertex(parent, null, res.getLeafResourceName(), 20, 20, w, h, "shape=ellipse;perimeter=ellipsePerimeter"); // insert a resource as a vertex + resources.put(resNode, resource); + createChildResourceVertices(resource, resNode, resources, w, h); + } + + // create channel vertices + for (ChannelNode c : dataFlowGraph.getRootChannelNodes()) { + DataTransferChannel channel = (DataTransferChannel) c.getChannel(); + if (!channel.getInputResources().isEmpty()) { + // Normal channel + if (channelsIn.get(channel) == null || channelsOut.get(channel) == null) { + if (Objects.equals(channel.getSelectors().toString(), "[]")) { + Object chCell = graph.insertVertex(parent, null, channel.getChannelName(), 150, 20, 30, 30); // insert a channel as a vertex + mxCell port_in = new mxCell(null, geo1, "shape=ellipse;perimter=ellipsePerimeter"); + port_in.setVertex(true); + graph.addCell(port_in, chCell); // insert the input port of a channel + mxCell port_out = new mxCell(null, geo2, "shape=ellipse;perimter=ellipsePerimeter"); + port_out.setVertex(true); + graph.addCell(port_out, chCell); // insert the output port of a channel + channelsIn.put(channel, port_in); + channelsOut.put(channel, port_out); + } else { + for (Selector s : channel.getSelectors()) { + Expression exp = s.getExpression(); + String selName = exp.toString(); + String cName = channel.getChannelName(); + String channelName = cName + " (" + selName + ")"; + Object chCell = graph.insertVertex(parent, null, channelName, 150, 20, 60, 30); // insert a channel as a vertex + mxCell port_in = new mxCell(null, geo1, "shape=ellipse;perimter=ellipsePerimeter"); + port_in.setVertex(true); + graph.addCell(port_in, chCell); // insert the input port of a channel + mxCell port_out = new mxCell(null, geo2, "shape=ellipse;perimter=ellipsePerimeter"); + port_out.setVertex(true); + graph.addCell(port_out, chCell); // insert the output port of a channel + channelsIn.put(channel, port_in); + channelsOut.put(channel, port_out); + } + } + } + } else { + // I/O channel + if (channelsOut.get(channel) == null) { + if (Objects.equals(channel.getSelectors().toString(), "[]")) { + Object chCell = graph.insertVertex(parent, null, channel.getChannelName(), 150, 20, 30, 30); // insert a channel as a vertex + mxCell port_in = new mxCell(null, geo1, "shape=ellipse;perimter=ellipsePerimeter"); + port_in.setVertex(true); + graph.addCell(port_in, chCell); // insert the input port of a channel + mxCell port_out = new mxCell(null, geo2, "shape=ellipse;perimter=ellipsePerimeter"); + port_out.setVertex(true); + graph.addCell(port_out, chCell); // insert the output port of a channel + channelsIn.put(channel, port_in); + channelsOut.put(channel, port_out); + } else { + for (Selector s : channel.getSelectors()) { + Expression exp = s.getExpression(); + String selName = exp.toString(); + String cName = channel.getChannelName(); + String channelName = cName + " (" + selName + ")"; + Object chCell = graph.insertVertex(parent, null, channelName, 150, 20, 60, 30); // insert a channel as a vertex + mxCell port_in = new mxCell(null, geo1, "shape=ellipse;perimter=ellipsePerimeter"); + port_in.setVertex(true); + graph.addCell(port_in, chCell); // insert the input port of a channel + mxCell port_out = new mxCell(null, geo2, "shape=ellipse;perimter=ellipsePerimeter"); + port_out.setVertex(true); + graph.addCell(port_out, chCell); // insert the output port of a channel + channelsIn.put(channel, port_in); + channelsOut.put(channel, port_out); + } + } + } + } + } + + // add input, output and reference edges + for (Edge edge : dataFlowGraph.getEdges()) { + DataFlowEdge dfEdge = (DataFlowEdge) edge; + if (dfEdge.isChannelToResource()) { + // output edge + DataTransferChannel channel = ((ChannelNode) dfEdge.getSource()).getChannel(); + ResourcePath dstRes = ((ResourceNode) dfEdge.getDestination()).getInSideResource(channel); + graph.insertEdge(parent, null, new Editor.SrcDstAttribute(channel, dstRes), channelsOut.get(channel), resources.get((ResourceNode) dfEdge.getDestination()), "movable=false"); + } else { + // input edge + DataTransferChannel channel = ((ChannelNode) dfEdge.getDestination()).getChannel(); + ResourcePath srcRes = ((ResourceNode) dfEdge.getSource()).getOutSideResource(channel); + Set> toRes = getResourceDependencyForChannel(channel, model, dataFlowGraph); + for (Map.Entry RtoR : toRes) { + graph.insertEdge(parent, null, null, resources.get(RtoR.getValue()), resources.get(RtoR.getKey()), "dashed=true;movable=false"); + } + + graph.insertEdge(parent, null, new Editor.SrcDstAttribute(srcRes, channel), resources.get((ResourceNode) dfEdge.getSource()), channelsIn.get(channel), "movable=false"); + } + } + + for (Channel ch : model.getChannels()) { + // reference edges + DataTransferChannel channel = (DataTransferChannel) ch; + for (ResourcePath refRes : channel.getReferenceResources()) { + graph.insertEdge(parent, null, null, resources.get(dataFlowGraph.getResourceNode(refRes)), channelsIn.get(channel), "dashed=true;movable=false"); + } + } + } finally { + graph.getModel().endUpdate(); + } + } + + private void createChildResourceVertices(Object resource, ResourceNode resNode, Map resources, int w, int h) { + for (ResourceNode childNode : resNode.getChildren()) { + ResourcePath childRes = childNode.getPrimaryResourcePath(); + Object childResource = graph.insertVertex(resource, null, childRes.getName(), 0, 0, w, h, "shape=ellipse;perimeter=ellipsePerimeter"); // insert a resource as a vertex + resources.put(childNode, childResource); + createChildResourceVertices(childResource, childNode, resources, w, h); + } + } + + private Set> getResourceDependencyForChannel(DataTransferChannel ch, DataTransferModel model, DataFlowGraph dataFlowGraph) { + Set> resourceDependency = new HashSet<>(); + if (!ch.getOutputChannelMembers().isEmpty()) { + try { + Map>> dependency = ch.fillOutsideResourcePaths(ch.getOutputChannelMembers().iterator().next(), JavaCodeGenerator.pullAccessor); + for (ChannelMember srcMem : dependency.keySet()) { + ResourceNode srcNode = dataFlowGraph.getResourceNode(srcMem.getResource()); + if (srcNode != null) { + for (ChannelMember dstMem : dependency.get(srcMem).getValue()) { + ResourceNode dstNode = dataFlowGraph.getResourceNode(dstMem.getResource()); + while (srcNode.getResourceHierarchy().getNumParameters() == 0 && srcNode.getParent() != null) { + srcNode = srcNode.getParent(); + } + resourceDependency.add(new AbstractMap.SimpleEntry<>(srcNode, dstNode)); + } + } + } + } catch (ParameterizedIdentifierIsFutureWork | ResolvingMultipleDefinitionIsFutureWork | InvalidMessage | + UnificationFailed | ValueUndefined e) { + e.printStackTrace(); + } + } + return resourceDependency; + } + public DataFlowGraph getDataFlowGraph() { return dataFlowGraph; }