package application.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.mxGraphModel; import com.mxgraph.model.mxIGraphModel; import com.mxgraph.swing.mxGraphComponent; import com.mxgraph.swing.view.mxICellEditor; import com.mxgraph.util.mxConstants; import com.mxgraph.view.mxCellState; import com.mxgraph.util.mxRectangle; import com.mxgraph.view.mxGraph; import com.mxgraph.view.mxGraphView; import algorithms.DataTransferModelAnalyzer; import algorithms.Validation; import application.editor.stages.ControlFlowDelegationStage; import application.editor.stages.DataFlowCellEditor; import application.editor.stages.DataFlowModelingStage; import application.editor.stages.PushPullSelectionStage; import application.layouts.*; import code.ast.CompilationUnit; import models.Edge; import models.EdgeAttribute; import models.Node; import models.dataConstraintModel.ChannelGenerator; import models.dataConstraintModel.IdentifierTemplate; import models.dataFlowModel.DataTransferModel; import models.dataFlowModel.DataTransferChannelGenerator; import models.dataFlowModel.PushPullAttribute; import models.dataFlowModel.DataFlowEdge; import models.dataFlowModel.DataFlowGraph; import models.dataFlowModel.ResourceNode; import models.visualModel.FormulaChannelGenerator; import parser.Parser; 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 { public DataTransferModel model = null; public mxGraph graph = null; private mxGraphComponent graphComponent = null; protected Stage curStage = null; protected List<Stage> stageQueue = null; private List<IStageChangeListener> stageChangeListeners = null; protected String curFileName = null; protected String curFilePath = null; protected ArrayList<CompilationUnit> codes = null; public static DataFlowModelingStage STAGE_DATA_FLOW_MODELING = null; public static PushPullSelectionStage STAGE_PUSH_PULL_SELECTION = null; public static ControlFlowDelegationStage STAGE_CONTROL_FLOW_DELEGATION = null; public Editor(mxGraphComponent graphComponent) { this.graphComponent = graphComponent; this.graph = graphComponent.getGraph(); STAGE_DATA_FLOW_MODELING = new DataFlowModelingStage(graph); STAGE_PUSH_PULL_SELECTION = new PushPullSelectionStage(graph); STAGE_CONTROL_FLOW_DELEGATION = new ControlFlowDelegationStage(graph); graphComponent.setCellEditor(STAGE_DATA_FLOW_MODELING.createCellEditor(graphComponent)); stageQueue = new ArrayList<>(); stageQueue.add(STAGE_DATA_FLOW_MODELING); stageQueue.add(STAGE_PUSH_PULL_SELECTION); stageQueue.add(STAGE_CONTROL_FLOW_DELEGATION); curStage = STAGE_DATA_FLOW_MODELING; stageChangeListeners = new ArrayList<>(); } public mxGraph getGraph() { return graph; } public mxGraphComponent getGraphComponent() { return this.graphComponent; } public DataTransferModel getModel() { model = curStage.getModel(); return model; } public Stage getCurStage() { return curStage; } public boolean canChange(Stage nextStage) { return nextStage.canChangeFrom(curStage); } public boolean nextStage() { int curStageNo = stageQueue.indexOf(curStage); if (curStageNo + 1 >= stageQueue.size()) return false; return changeStage(stageQueue.get(curStageNo + 1)); } public boolean changeStage(Stage nextStage) { if (!nextStage.canChangeFrom(curStage)) return false; nextStage.init(curStage); graphComponent.setCellEditor(nextStage.createCellEditor(graphComponent)); curStage = nextStage; return true; } public void addStageChangeListener(IStageChangeListener stageChangeListener) { stageChangeListeners.add(stageChangeListener); } private void notifyStageChangeListeners() { for (IStageChangeListener l: stageChangeListeners) { l.stageChanged(curStage); } } public DataFlowGraph getDataFlowGraph() { if (curStage instanceof PushPullSelectionStage) { return ((PushPullSelectionStage) curStage).getDataFlowGraph(); } return null; } 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() { // Force to change to the data-flow modeling stage. boolean stageChanged = changeStage(STAGE_DATA_FLOW_MODELING); if (!stageChanged) return; model = null; ((DataFlowModelingStage) curStage).clear(); notifyStageChangeListeners(); 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 DataTransferModel open(File file) { // Force to change to the data-flow modeling stage. boolean stageChanged = changeStage(STAGE_DATA_FLOW_MODELING); if (!stageChanged) return null; try { String extension =""; if(file != null && file.exists()) { // get file's name String name = file.getName(); // get file's extension extension = name.substring(name.lastIndexOf(".")); } if(extension.contains(".model")) { openModel(file); } else { // Parse the .dtram file. ParserDTRAM parserDTRAM = new ParserDTRAM(new BufferedReader(new FileReader(file))); try { model = parserDTRAM.doParseModel(); if (curStage instanceof DataFlowModelingStage) { // Update the mxGraph. ((DataFlowModelingStage) curStage).setModel(model); } // Restore the geometry. parserDTRAM.doParseGeometry(graph); // Change to the push/pull selection stage, analyze the data transfer model and construct a data-flow graph. changeStage(STAGE_PUSH_PULL_SELECTION); notifyStageChangeListeners(); curFilePath = file.getAbsolutePath(); curFileName = file.getName(); 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 DataTransferModel openModel(File file) { // Force to change to data-flow modeling stage. boolean stageChanged = changeStage(STAGE_DATA_FLOW_MODELING); if (!stageChanged) return null; try { // Parse the .model file. Parser parser = new Parser(new BufferedReader(new FileReader(file))); try { model = parser.doParse(); if (curStage instanceof DataFlowModelingStage) { // Update the mxGraph. ((DataFlowModelingStage) curStage).setModel(model); } // Set DAG layout. setDAGLayout(); // Change to the push/pull selection stage, analyze the data transfer model and construct a data-flow graph. changeStage(STAGE_PUSH_PULL_SELECTION); notifyStageChangeListeners(); curFilePath = file.getAbsolutePath(); curFileName = file.getName(); return model; } catch (ExpectedChannel | ExpectedChannelName | ExpectedLeftCurlyBracket | ExpectedInOrOutOrRefKeyword | ExpectedStateTransition | ExpectedEquals | ExpectedRHSExpression | WrongLHSExpression | WrongRHSExpression | ExpectedRightBracket | ExpectedAssignment e) { e.printStackTrace(); } } catch (FileNotFoundException e) { e.printStackTrace(); } return null; } /**-------------------------------------------------------------------------------- * save /**-------------------------------------------------------------------------------- * */ public void save() { if (curFilePath != null) { try { File file = new File(curFilePath); String extension = ""; if(file != null && file.exists()) { // get a file's name String name = file.getName(); // get a file's extension extension = name.substring(name.lastIndexOf(".")); } if(extension.contains(".model")) { saveModel(file); } else { FileWriter filewriter = new FileWriter(file); filewriter.write(toOutputString()); 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(); } } } /**-------------------------------------------------------------------------------- * get writing texts "dtram" file information is written. * * @return formatted "dtram" info texts. */ protected String toOutputString() { String fileString = ""; fileString += "model {\n"; fileString += this.model.getSourceText(); fileString += "}\n"; fileString += "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())) { fileString += "\tnode fc " + state.getLabel() + ":" + x + "," + y + "," + w + "," + h+"\n"; } else if(ch instanceof ChannelGenerator && state.getLabel().equals(ch.getChannelName())) { fileString +="\tnode c " + state.getLabel() + ":" + x + "," + y + "," + w + "," + h+"\n"; } } for (IdentifierTemplate res: model.getIdentifierTemplates()){ if(res instanceof IdentifierTemplate && state.getLabel().equals(res.getResourceName())) fileString += "\tnode r " + state.getLabel() + ":" + x + "," + y + "," + w + "," + h + "\n"; } for (ChannelGenerator ioC: model.getIOChannelGenerators()) { if(ioC instanceof ChannelGenerator && state.getLabel().equals(ioC.getChannelName())) { fileString += "\tnode ioc " + state.getLabel() + ":" + x + "," + y + "," + w + "," + h + "\n"; } } } } fileString += "}\n"; return fileString; } 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 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) { // Force to change to the data-flow modeling stage. boolean stageChanged = changeStage(STAGE_DATA_FLOW_MODELING); if (!stageChanged) return; ((DataFlowModelingStage) curStage).addIdentifierTemplate(res); model = ((DataFlowModelingStage) curStage).getModel(); notifyStageChangeListeners(); } public void addChannelGenerator(DataTransferChannelGenerator channelGen) { // Force to change to the data-flow modeling stage. boolean stageChanged = changeStage(STAGE_DATA_FLOW_MODELING); if (!stageChanged) return; ((DataFlowModelingStage) curStage).addChannelGenerator(channelGen); model = ((DataFlowModelingStage) curStage).getModel(); notifyStageChangeListeners(); } public void addIOChannelGenerator(DataTransferChannelGenerator ioChannelGen) { // Force to change to the data-flow modeling stage. boolean stageChanged = changeStage(STAGE_DATA_FLOW_MODELING); if (!stageChanged) return; ((DataFlowModelingStage) curStage).addIOChannelGenerator(ioChannelGen); model = ((DataFlowModelingStage) curStage).getModel(); notifyStageChangeListeners(); } public void addFormulaChannelGenerator(FormulaChannelGenerator formulaChannelGen) { // Force to change to the data-flow modeling stage. boolean stageChanged = changeStage(STAGE_DATA_FLOW_MODELING); if (!stageChanged) return; ((DataFlowModelingStage) curStage).addFormulaChannelGenerator(formulaChannelGen); model = ((DataFlowModelingStage) curStage).getModel(); notifyStageChangeListeners(); } public boolean connectEdge(mxCell edge, mxCell src, mxCell dst) { // Force to change to the data-flow modeling stage. boolean stageChanged = changeStage(STAGE_DATA_FLOW_MODELING); if (!stageChanged) return false; boolean isConnected = ((DataFlowModelingStage) curStage).connectEdge(edge, src, dst); notifyStageChangeListeners(); return isConnected; } public void delete() { // Force to change to the data-flow modeling stage. boolean stageChanged = changeStage(STAGE_DATA_FLOW_MODELING); if (!stageChanged) return; ((DataFlowModelingStage) curStage).delete(); notifyStageChangeListeners(); } public static 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 ""; } } }