package graphicalrefactor.editor; import java.io.BufferedReader; import java.io.File; import java.io.FileNotFoundException; import java.io.FileReader; import java.io.FileWriter; import java.io.IOException; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import com.mxgraph.layout.mxCircleLayout; import com.mxgraph.layout.mxCompactTreeLayout; import com.mxgraph.model.mxCell; import com.mxgraph.model.mxGeometry; import com.mxgraph.model.mxGraphModel; import com.mxgraph.model.mxIGraphModel; import com.mxgraph.util.mxConstants; import com.mxgraph.util.mxPoint; import com.mxgraph.view.mxCellState; import com.mxgraph.util.mxRectangle; import com.mxgraph.view.mxGraph; import com.mxgraph.view.mxGraphView; import algorithms.NecessityOfStoringResourceStates; import algorithms.SelectableDataTransfers; import algorithms.UpdateConflictCheck; import code.ast.CompilationUnit; import graphicalrefactor.layouts.*; import models.Edge; import models.EdgeAttribute; import models.Node; import models.dataConstraintModel.ChannelGenerator; import models.dataConstraintModel.ChannelMember; import models.dataConstraintModel.IdentifierTemplate; import models.dataFlowModel.DataFlowModel; import models.dataFlowModel.DataflowChannelGenerator; import models.dataFlowModel.PushPullAttribute; import models.dataFlowModel.ResourceDependency; import models.dataFlowModel.ResourceDependencyGraph; import models.dataFlowModel.ResourceNode; import models.visualModel.FormulaChannelGenerator; import parser.Parser; import parser.Parser.TokenStream; import parser.exceptions.ExpectedAssignment; import parser.exceptions.ExpectedChannel; import parser.exceptions.ExpectedChannelName; import parser.exceptions.ExpectedEquals; import parser.exceptions.ExpectedFormulaChannel; import parser.exceptions.ExpectedGeometry; import parser.exceptions.ExpectedInOrOutOrRefKeyword; import parser.exceptions.ExpectedIoChannel; import parser.exceptions.ExpectedLeftCurlyBracket; import parser.exceptions.ExpectedModel; import parser.exceptions.ExpectedNode; import parser.exceptions.ExpectedRHSExpression; import parser.exceptions.ExpectedResource; import parser.exceptions.ExpectedRightBracket; import parser.exceptions.ExpectedStateTransition; import parser.exceptions.WrongLHSExpression; import parser.exceptions.WrongRHSExpression; import parser.ParserDTRAM; public class Editor { final int PORT_DIAMETER = 8; final int PORT_RADIUS = PORT_DIAMETER / 2; private String curFileName = null; private String curFilePath = null; private ArrayList<CompilationUnit> codes = null; protected DataFlowModel model = null; protected mxGraph graph = null; protected ResourceDependencyGraph resourceDependencyGraph = null; public Editor(mxGraph graph) { this.graph = graph; } public mxGraph getGraph() { return graph; } public void setGraph(mxGraph graph) { this.graph = graph; } public DataFlowModel getModel() { if (model == null) { model = new DataFlowModel(); } return model; } public ResourceDependencyGraph getResourceDependencyGraph() { if (resourceDependencyGraph == null) { updateResourceDependencyGraph(getModel()); } return resourceDependencyGraph; } public ResourceDependencyGraph updateResourceDependencyGraph(DataFlowModel model) { ResourceDependencyGraph resourceGraph = NecessityOfStoringResourceStates.doDecide(model); resourceDependencyGraph = SelectableDataTransfers.init(resourceGraph); updateEdgeAttiributes(resourceDependencyGraph); return resourceDependencyGraph; } public void resetResourceDependencyGraph() { resourceDependencyGraph = null; } public void setResourceDependencyGraph(ResourceDependencyGraph resourceDependencyGraph) { this.resourceDependencyGraph = resourceDependencyGraph; } public ArrayList<CompilationUnit> getCodes() { return codes; } public void setCodes(ArrayList<CompilationUnit> codes) { this.codes = codes; } public String getCurFileName() { return curFileName; } public String getCurFilePath() { return curFilePath; } public void setCurFilePath(String curFilePath) { this.curFilePath = curFilePath; this.curFileName = new File(curFilePath).getName(); } public void clear() { model = null; ((mxGraphModel) graph.getModel()).clear(); resourceDependencyGraph = null; curFilePath = null; curFileName = null; codes = null; } /** * Open a given file, parse the file, construct a DataFlowModel and a mxGraph * @param file given file * @return a constructed DataFlowModel */ public DataFlowModel open(File file) { try { String extension =""; if(file != null && file.exists()) { //�t�@�C�������擾 String name = file.getName(); //�g���q���擾 extension = name.substring(name.lastIndexOf(".")); } if(extension.contains(".model")) { openModel(file); } else { ParserDTRAM parserDTRAM = new ParserDTRAM(new BufferedReader(new FileReader(file))); try { model = parserDTRAM.doParseModel(); graph = constructGraph(model); parserDTRAM.doParseGeometry(graph); curFilePath = file.getAbsolutePath(); curFileName = file.getName(); if (!UpdateConflictCheck.run(model)) return null; updateResourceDependencyGraph(model); return model; } catch (ExpectedChannel | ExpectedChannelName | ExpectedLeftCurlyBracket | ExpectedInOrOutOrRefKeyword | ExpectedStateTransition | ExpectedEquals | ExpectedRHSExpression | WrongLHSExpression | WrongRHSExpression | ExpectedRightBracket | ExpectedAssignment | ExpectedModel | ExpectedGeometry | ExpectedNode | ExpectedResource | ExpectedFormulaChannel | ExpectedIoChannel e) { e.printStackTrace(); } } } catch (FileNotFoundException e) { e.printStackTrace(); } return null; } public DataFlowModel openModel(File file) { try { Parser parser = new Parser(new BufferedReader(new FileReader(file))); try { model = parser.doParse(); curFilePath = file.getAbsolutePath(); curFileName = file.getName(); if (!UpdateConflictCheck.run(model)) return null; graph = constructGraph(model); updateResourceDependencyGraph(model); return model; } catch (ExpectedChannel | ExpectedChannelName | ExpectedLeftCurlyBracket | ExpectedInOrOutOrRefKeyword | ExpectedStateTransition | ExpectedEquals | ExpectedRHSExpression | WrongLHSExpression | WrongRHSExpression | ExpectedRightBracket | ExpectedAssignment e) { e.printStackTrace(); } } catch (FileNotFoundException e) { e.printStackTrace(); } return null; } public void save() { if (curFilePath != null) { try { File file = new File(curFilePath); String extension = ""; if(file != null && file.exists()) { //�t�@�C�������擾 String name = file.getName(); //�g���q���擾 extension = name.substring(name.lastIndexOf(".")); } if(extension.contains(".model")) { saveModel(file); } else { FileWriter filewriter = new FileWriter(file); filewriter.write("model {\n"); filewriter.write(model.getSourceText()); filewriter.write("}\n"); filewriter.write("geometry {\n"); Object root = graph.getDefaultParent(); for (int i = 0; i < graph.getModel().getChildCount(root); i++) { Object cell = graph.getModel().getChildAt(root, i); if (graph.getModel().isVertex(cell)) { mxGraphView view = graph.getView(); mxCellState state = view.getState(cell); int x = (int) state.getX(); int y = (int) state.getY(); int w = (int) state.getWidth(); int h = (int) state.getHeight(); for(ChannelGenerator ch: model.getChannelGenerators()) { if(ch instanceof FormulaChannelGenerator && state.getLabel().equals(ch.getChannelName())) { filewriter.write("node fc " + state.getLabel() + ":" + x + "," + y + "," + w + "," + h+"\n"); } else if(ch instanceof ChannelGenerator && state.getLabel().equals(ch.getChannelName())) { filewriter.write("node c " + state.getLabel() + ":" + x + "," + y + "," + w + "," + h+"\n"); } } for (IdentifierTemplate res: model.getIdentifierTemplates()){ if(res instanceof IdentifierTemplate && state.getLabel().equals(res.getResourceName())) filewriter.write("node r " + state.getLabel() + ":" + x + "," + y + "," + w + "," + h + "\n"); } for (ChannelGenerator ioC: model.getIOChannelGenerators()) { if(ioC instanceof ChannelGenerator && state.getLabel().equals(ioC.getChannelName())) { filewriter.write("node ioc " + state.getLabel() + ":" + x + "," + y + "," + w + "," + h + "\n"); } } } } filewriter.write("}\n"); filewriter.close(); } } catch (IOException e) { e.printStackTrace(); } } } public void saveModel(File file) { if (curFilePath != null) { try { FileWriter filewriter = new FileWriter(file); filewriter.write(model.getSourceText()); filewriter.close(); } catch (IOException e) { e.printStackTrace(); } } } /** * Construct a mxGraph from DataFlowModel and DataFlowModel * @param model * @param resourceDependencyGraph * @return constructed mxGraph */ public mxGraph constructGraph(DataFlowModel model) { ((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<DataflowChannelGenerator, Object> channelsIn = new HashMap<>(); Map<DataflowChannelGenerator, Object> channelsOut = new HashMap<>(); Map<IdentifierTemplate, Object> resources = new HashMap<>(); // create channel vertices for (ChannelGenerator c: model.getChannelGenerators()) { DataflowChannelGenerator channelGen = (DataflowChannelGenerator) c; if (channelsIn.get(channelGen) == null || channelsOut.get(channelGen) == null) { Object channel = graph.insertVertex(parent, null, channelGen.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, channel); // 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, channel); // insert the output port of a channel channelsIn.put(channelGen, port_in); channelsOut.put(channelGen, port_out); } } // create resource vertices for (IdentifierTemplate res: model.getIdentifierTemplates()) { Object resource = graph.insertVertex(parent, null, res.getResourceName(), 20, 20, 80, 30, "shape=ellipse;perimeter=ellipsePerimeter"); // insert a resource as a vertex resources.put(res, resource); } // add input, output and reference edges for (ChannelGenerator ch: model.getChannelGenerators()) { DataflowChannelGenerator channelGen = (DataflowChannelGenerator) ch; // input edge for (IdentifierTemplate srcRes: channelGen.getInputIdentifierTemplates()) { graph.insertEdge(parent, null, new SrcDstAttribute(srcRes, channelGen), resources.get(srcRes), channelsIn.get(channelGen), "movable=false"); } // output edge for (IdentifierTemplate dstRes: channelGen.getOutputIdentifierTemplates()) { graph.insertEdge(parent, null, new SrcDstAttribute(channelGen, dstRes), channelsOut.get(channelGen), resources.get(dstRes), "movable=false"); } // reference edges for (IdentifierTemplate refRes: channelGen.getReferenceIdentifierTemplates()) { graph.insertEdge(parent, null, null, resources.get(refRes), channelsIn.get(channelGen), "dashed=true;movable=false"); } } for (ChannelGenerator ioChannelGen: model.getIOChannelGenerators()) { if (channelsOut.get(ioChannelGen) == null) { Object channel = graph.insertVertex(parent, null, ioChannelGen.getChannelName(), 150, 20, 30, 30); // insert an I/O channel as a vertex mxCell port_out = new mxCell(null, geo2, "shape=ellipse;perimter=ellipsePerimeter"); port_out.setVertex(true); graph.addCell(port_out, channel); // insert the output port of a channel channelsOut.put((DataflowChannelGenerator) ioChannelGen, port_out); for (IdentifierTemplate outRes: ((DataflowChannelGenerator) ioChannelGen).getOutputIdentifierTemplates()) { graph.insertEdge(parent, null, null, port_out, resources.get(outRes), "movable=false"); } } } } finally { graph.getModel().endUpdate(); } setTreeLayout(); return graph; } public void setDAGLayout() { Object parent = graph.getDefaultParent(); graph.getModel().beginUpdate(); try { DAGLayout ctl = new DAGLayout(graph); ctl.execute(parent); } finally { graph.getModel().endUpdate(); } } public void updateEdgeAttiributes(ResourceDependencyGraph resourceDependencyGraph) { Object parent = graph.getDefaultParent(); graph.getModel().beginUpdate(); try { // add input, output and reference edges for (Edge e : resourceDependencyGraph.getEdges()) { if (e instanceof ResourceDependency) { ResourceDependency dependency = (ResourceDependency) e; DataflowChannelGenerator channelGen = dependency.getChannelGenerator(); ResourceNode srcRes = (ResourceNode) dependency.getSource(); // input edge for (Object edge: graph.getChildEdges(parent)) { mxCell edgeCell = (mxCell) edge; if (edgeCell.getValue() instanceof SrcDstAttribute) { SrcDstAttribute edgeAttr = (SrcDstAttribute) edgeCell.getValue(); if (edgeAttr.getSrouce() == srcRes.getIdentifierTemplate() && edgeAttr.getDestination() == channelGen) { edgeCell.setValue(dependency.getAttribute()); break; } } } } } } finally { graph.getModel().endUpdate(); } graph.refresh(); } public void setTreeLayout() { Object parent = graph.getDefaultParent(); graph.getModel().beginUpdate(); try { mxCompactTreeLayout ctl = new mxCompactTreeLayout(graph); ctl.setLevelDistance(100); // ctl.setHorizontal(false); ctl.setEdgeRouting(false); ctl.execute(parent); } finally { graph.getModel().endUpdate(); } } public void setCircleLayout() { Object parent = graph.getDefaultParent(); graph.getModel().beginUpdate(); try { mxCircleLayout ctl = new mxCircleLayout(graph); ctl.execute(parent); } finally { graph.getModel().endUpdate(); } } public void addIdentifierTemplate(IdentifierTemplate res) { getModel().addIdentifierTemplate(res); resetResourceDependencyGraph(); graph.getModel().beginUpdate(); Object parent = graph.getDefaultParent(); try { graph.insertVertex(parent, null, res.getResourceName(), 20, 20, 80, 30, "shape=ellipse;perimeter=ellipsePerimeter"); // insert a resource as a vertex } finally { graph.getModel().endUpdate(); } } public void addChannelGenerator(DataflowChannelGenerator channelGen) { getModel().addChannelGenerator(channelGen); resetResourceDependencyGraph(); graph.getModel().beginUpdate(); Object parent = graph.getDefaultParent(); 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); Object channel = graph.insertVertex(parent, null, channelGen.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, channel); // 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, channel); // insert the output port of a channel } finally { graph.getModel().endUpdate(); } } public void addIOChannelGenerator(DataflowChannelGenerator ioChannelGen) { getModel().addIOChannelGenerator(ioChannelGen); resetResourceDependencyGraph(); graph.getModel().beginUpdate(); Object parent = graph.getDefaultParent(); try { mxGeometry geo2 = new mxGeometry(1.0, 0.5, PORT_DIAMETER, PORT_DIAMETER); geo2.setOffset(new mxPoint(-PORT_RADIUS, -PORT_RADIUS)); geo2.setRelative(true); Object channel = graph.insertVertex(parent, null, ioChannelGen.getChannelName(), 150, 20, 30, 30); // insert an I/O channel as a vertex mxCell port_out = new mxCell(null, geo2, "shape=ellipse;perimter=ellipsePerimeter"); port_out.setVertex(true); graph.addCell(port_out, channel); // insert the output port of a channel } finally { graph.getModel().endUpdate(); } } public void addFormulaChannelGenerator(FormulaChannelGenerator formulaChannelGen) { getModel().addChannelGenerator(formulaChannelGen); resetResourceDependencyGraph(); graph.getModel().beginUpdate(); Object parent = graph.getDefaultParent(); 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); Object channel = graph.insertVertex(parent, null, formulaChannelGen.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, channel); // 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, channel); // insert the output port of a channel } finally { graph.getModel().endUpdate(); } } public boolean connectEdge(mxCell edge, mxCell src, mxCell dst) { DataFlowModel model = getModel(); ChannelGenerator srcCh = model.getChannelGenerator((String) src.getValue()); if (srcCh == null) { srcCh = model.getIOChannelGenerator((String) src.getValue()); if (srcCh == null) { IdentifierTemplate srcRes = model.getIdentifierTemplate((String) src.getValue()); ChannelGenerator dstCh = model.getChannelGenerator((String) dst.getValue()); if (srcRes == null || dstCh == null) return false; // resource to channel edge ChannelMember srcCm = new ChannelMember(srcRes); ((DataflowChannelGenerator ) dstCh).addChannelMemberAsInput(srcCm); edge.setValue(new SrcDstAttribute(srcRes, dstCh)); resetResourceDependencyGraph(); return true; } } IdentifierTemplate dstRes = model.getIdentifierTemplate((String) dst.getValue()); if (dstRes == null) return false; // channel to resource edge ChannelMember dstCm = new ChannelMember(dstRes); ((DataflowChannelGenerator) srcCh).addChannelMemberAsOutput(dstCm); edge.setValue(new SrcDstAttribute(srcCh, dstRes)); resetResourceDependencyGraph(); return true; } public void delete() { for (Object obj: graph.getSelectionCells()) { mxCell cell = (mxCell) obj; if (cell.isEdge()) { String srcName = (String) cell.getSource().getValue(); String dstName = (String) cell.getTarget().getValue(); if (model.getIdentifierTemplate(srcName) != null) { // resource to channel edge ChannelGenerator ch = model.getChannelGenerator(dstName); ch.removeChannelMember(model.getIdentifierTemplate(srcName)); } else if (model.getIdentifierTemplate(dstName) != null) { // channel to resource edge ChannelGenerator ch = model.getChannelGenerator(srcName); if (ch == null) { ch = model.getIOChannelGenerator(srcName); } ch.removeChannelMember(model.getIdentifierTemplate(dstName)); } } else if (cell.isVertex()) { String name = (String) cell.getValue(); if (model.getChannelGenerator(name) != null) { model.removeChannelGenerator(name); } else if (model.getIOChannelGenerator(name) != null) { model.removeIOChannelGenerator(name); } else if (model.getIdentifierTemplate(name) != null) { model.removeIdentifierTemplate(name); } } } graph.removeCells(graph.getSelectionCells()); resetResourceDependencyGraph(); } public void setChannelCode(DataflowChannelGenerator ch, String code) { ch.setSourceText(code); TokenStream stream = new TokenStream(); for (String line: code.split("\n")) { stream.addLine(line); } try { DataflowChannelGenerator ch2 = Parser.parseChannel(stream, getModel()); for (ChannelMember chm2: ch2.getInputChannelMembers()) { for (ChannelMember chm: ch.getInputChannelMembers()) { if (chm2.getIdentifierTemplate() == chm.getIdentifierTemplate()) { chm.setStateTransition(chm2.getStateTransition()); break; } } } for (ChannelMember chm2: ch2.getOutputChannelMembers()) { for (ChannelMember chm: ch.getOutputChannelMembers()) { if (chm2.getIdentifierTemplate() == chm.getIdentifierTemplate()) { chm.setStateTransition(chm2.getStateTransition()); break; } } } for (ChannelMember chm2: ch2.getReferenceChannelMembers()) { for (ChannelMember chm: ch.getReferenceChannelMembers()) { if (chm2.getIdentifierTemplate() == chm.getIdentifierTemplate()) { chm.setStateTransition(chm2.getStateTransition()); break; } } } resetResourceDependencyGraph(); } catch (ExpectedRightBracket | ExpectedChannel | ExpectedChannelName | ExpectedLeftCurlyBracket | ExpectedInOrOutOrRefKeyword | ExpectedStateTransition | ExpectedEquals | ExpectedRHSExpression | WrongLHSExpression | WrongRHSExpression | ExpectedAssignment e) { e.printStackTrace(); } } private class SrcDstAttribute extends EdgeAttribute { private Object src; private Object dst; public SrcDstAttribute(Object src, Object dst) { this.src = src; this.dst = dst; } public Object getSrouce() { return src; } public Object getDestination() { return dst; } public String toString() { return ""; } } }