package application.editor; import application.editor.stages.DataFlowModelingStage; import application.editor.stages.PushPullSelectionStage; import application.layouts.DAGLayout; import code.ast.CompilationUnit; import com.mxgraph.layout.mxCircleLayout; import com.mxgraph.layout.mxCompactTreeLayout; import com.mxgraph.model.mxCell; import com.mxgraph.swing.mxGraphComponent; import com.mxgraph.util.mxEvent; import com.mxgraph.util.mxEventSource.mxIEventListener; import com.mxgraph.view.mxCellState; import com.mxgraph.view.mxGraph; import com.mxgraph.view.mxGraphView; import models.EdgeAttribute; import models.dataConstraintModel.Channel; import models.dataConstraintModel.ResourcePath; import models.dataFlowModel.DataFlowGraph; import models.dataFlowModel.DataTransferChannel; import models.dataFlowModel.DataTransferModel; import models.visualModel.FormulaChannel; import parser.Parser; import parser.ParserDTRAM; import parser.exceptions.*; import java.awt.event.MouseListener; import java.io.*; import java.util.ArrayList; import java.util.List; public class Editor { protected DataTransferModel model = null; protected mxGraph graph; private final mxGraphComponent graphComponent; protected Stage curStage; private final List<IStageChangeListener> stageChangeListeners; private mxIEventListener curChangeEventListener = null; private MouseListener curMouseEventListener = 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 Editor(mxGraphComponent graphComponent) { this.graphComponent = graphComponent; this.graph = graphComponent.getGraph(); STAGE_DATA_FLOW_MODELING = new DataFlowModelingStage(graphComponent); STAGE_PUSH_PULL_SELECTION = new PushPullSelectionStage(graphComponent); graphComponent.setCellEditor(STAGE_DATA_FLOW_MODELING.createCellEditor(graphComponent)); curStage = STAGE_DATA_FLOW_MODELING; stageChangeListeners = new ArrayList<>(); } public boolean canChange(Stage nextStage) { return nextStage.canChangeFrom(curStage); } public boolean changeStage(Stage nextStage) { if (!nextStage.canChangeFrom(curStage)) { return false; } nextStage.init(curStage); graphComponent.setCellEditor(nextStage.createCellEditor(graphComponent)); // add listeners // "curChangeEventListener" will be called when updating the mxGraph. if (curChangeEventListener != null) { graph.getModel().removeListener(curChangeEventListener); } curChangeEventListener = nextStage.createChangeEventListener(this); if (curChangeEventListener != null) { graph.getModel().addListener(mxEvent.CHANGE, curChangeEventListener); } // A handler of a mouse event. if (curMouseEventListener != null) { graphComponent.getGraphControl().removeMouseListener(curMouseEventListener); } curMouseEventListener = nextStage.createMouseEventListener(this); if (curMouseEventListener != null) { graphComponent.getGraphControl().addMouseListener(curMouseEventListener); } curStage = nextStage; notifyStageChangeListeners(); 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 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; } ((DataFlowModelingStage) curStage).clear(); model = null; curFilePath = null; curFileName = null; codes = null; } /** * Open a given file, parse the file, construct a DataFlowModel and a mxGraph * * @param file given file */ public void open(File file) { // Force to change to data-modeling stage boolean stageChanged = changeStage(STAGE_DATA_FLOW_MODELING); if (!stageChanged) { return; } if (file == null || !file.exists()) { return; } // get a file's extension String extension = file.getName().substring(file.getName().lastIndexOf(".")); if (extension.contains(".model")) { openModel(file); } if (extension.contains(".dtram")) { openDTRAM(file); } } private void openModel(File file) { try { Parser parser = new Parser(new BufferedReader(new FileReader(file))); try { // Parse the .model file. model = parser.doParse(); // Update stage's model to new parsed one if (curStage instanceof DataFlowModelingStage) { ((DataFlowModelingStage) curStage).setModel(model); } // Force to change PushPullSelectionStage to construct mxGraph boolean stageChanged = changeStage(STAGE_PUSH_PULL_SELECTION); if (stageChanged && curStage instanceof PushPullSelectionStage) { ((PushPullSelectionStage) curStage).constructGraph(); } // Set layout setDAGLayout(); // Update current file info curFilePath = file.getAbsolutePath(); curFileName = file.getName(); } catch (ExpectedChannel | ExpectedChannelName | ExpectedLeftCurlyBracket | ExpectedInOrOutOrRefOrSubKeyword | ExpectedStateTransition | ExpectedEquals | ExpectedRHSExpression | WrongLHSExpression | WrongRHSExpression | ExpectedRightBracket | ExpectedAssignment | ExpectedRightCurlyBracket | WrongPathExpression | WrongJsonExpression | ExpectedColon e) { e.printStackTrace(); } } catch (FileNotFoundException e) { e.printStackTrace(); } } private void openDTRAM(File file) { try { ParserDTRAM parser = new ParserDTRAM(new BufferedReader(new FileReader(file))); try { // Parse the .dtram file. model = parser.doParseModel(); // Update stage's model to new parsed one if (curStage instanceof DataFlowModelingStage) { ((DataFlowModelingStage) curStage).setModel(model); } // Force to change PushPullSelectionStage to construct mxGraph boolean stageChanged = changeStage(STAGE_PUSH_PULL_SELECTION); if (stageChanged && curStage instanceof PushPullSelectionStage) { ((PushPullSelectionStage) curStage).constructGraph(); } // Restore the geometry parser.doParseGeometry(graph); // Update current file info curFilePath = file.getAbsolutePath(); curFileName = file.getName(); } catch (ExpectedChannel | ExpectedChannelName | ExpectedLeftCurlyBracket | ExpectedInOrOutOrRefOrSubKeyword | ExpectedStateTransition | ExpectedEquals | ExpectedRHSExpression | WrongLHSExpression | WrongRHSExpression | ExpectedRightBracket | ExpectedAssignment | ExpectedModel | ExpectedGeometry | ExpectedNode | ExpectedResource | ExpectedFormulaChannel | ExpectedIoChannel | ExpectedRightCurlyBracket | WrongPathExpression | WrongJsonExpression | ExpectedColon e) { e.printStackTrace(); } } catch (FileNotFoundException e) { e.printStackTrace(); } } public void save() { if (curFilePath == null) { return; } File file = new File(curFilePath); String extension = file.getName().substring(file.getName().lastIndexOf(".")); if (extension.contains(".model")) { saveModel(file); } if (extension.contains(".dtram")) { saveDTRAM(file); } } private void saveModel(File file) { try { FileWriter filewriter = new FileWriter(file); filewriter.write(model.getSourceText()); filewriter.close(); } catch (IOException e) { e.printStackTrace(); } } private void saveDTRAM(File file) { try { FileWriter filewriter = new FileWriter(file); filewriter.write(toOutputString()); filewriter.close(); } catch (IOException e) { e.printStackTrace(); } } /** * get writing texts "dtram" file information is written. * * @return formatted "dtram" info texts. */ private String toOutputString() { StringBuilder fileString = new StringBuilder(); fileString.append("model {\n"); fileString.append(model.getSourceText()); fileString.append("}\n"); fileString.append("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 (Channel ch : model.getChannels()) { if (ch instanceof FormulaChannel && state.getLabel().equals(ch.getChannelName())) { fileString.append("\tnode fc ").append(state.getLabel()).append(":").append(x).append(",").append(y).append(",").append(w).append(",").append(h).append("\n"); } else if (ch != null && state.getLabel().equals(ch.getChannelName())) { fileString.append("\tnode c ").append(state.getLabel()).append(":").append(x).append(",").append(y).append(",").append(w).append(",").append(h).append("\n"); } } for (ResourcePath res : model.getResourcePaths()) { if (res != null && state.getLabel().equals(res.getLeafResourceName())) fileString.append("\tnode r ").append(state.getLabel()).append(":").append(x).append(",").append(y).append(",").append(w).append(",").append(h).append("\n"); } for (Channel ioC : model.getInputChannels()) { if (ioC != null && state.getLabel().equals(ioC.getChannelName())) { fileString.append("\tnode ioc ").append(state.getLabel()).append(":").append(x).append(",").append(y).append(",").append(w).append(",").append(h).append("\n"); } } } } fileString.append("}\n"); return fileString.toString(); } public void delete() { boolean stageChanged = changeStage(STAGE_DATA_FLOW_MODELING); if (!stageChanged) { return; } ((DataFlowModelingStage) curStage).delete(); } public void setDAGLayout() { mxCell root = (mxCell) graph.getDefaultParent(); graph.getModel().beginUpdate(); try { DAGLayout ctl = new DAGLayout(graph); ctl.execute(root); } finally { graph.getModel().endUpdate(); } } public void setTreeLayout() { mxCell root = (mxCell) graph.getDefaultParent(); graph.getModel().beginUpdate(); try { mxCompactTreeLayout ctl = new mxCompactTreeLayout(graph); ctl.setLevelDistance(100); // ctl.setHorizontal(false); ctl.setEdgeRouting(false); for (int i = 0; i < root.getChildCount(); i++) { ctl.execute(root.getChildAt(i)); } } finally { graph.getModel().endUpdate(); } } public void setCircleLayout() { mxCell root = (mxCell) graph.getDefaultParent(); graph.getModel().beginUpdate(); try { mxCircleLayout ctl = new mxCircleLayout(graph); for (int i = 0; i < root.getChildCount(); i++) { ctl.execute(root.getChildAt(i)); } } finally { graph.getModel().endUpdate(); } } public void addResourcePath(ResourcePath parentPath, String resName) { // Force to change to data-flow modeling stage boolean stageChanged = changeStage(STAGE_DATA_FLOW_MODELING); if (stageChanged) { return; } ((DataFlowModelingStage) curStage).addResourcePath(parentPath, resName); model = curStage.getModel(); } public void addChannel(DataTransferChannel channelGen) { // Force to change to data-flow modeling stage boolean stageChanged = changeStage(STAGE_DATA_FLOW_MODELING); if (stageChanged) { return; } ((DataFlowModelingStage) curStage).addChannel(channelGen); model = curStage.getModel(); } public void addIOChannel(DataTransferChannel ioChannelGen) { // Force to change to data-flow modeling stage boolean stageChanged = changeStage(STAGE_DATA_FLOW_MODELING); if (stageChanged) { return; } ((DataFlowModelingStage) curStage).addIOChannel(ioChannelGen); model = curStage.getModel(); } public void addFormulaChannel(FormulaChannel formulaChannelGen) { // Force to change to data-flow modeling stage boolean stageChanged = changeStage(STAGE_DATA_FLOW_MODELING); if (stageChanged) { return; } ((DataFlowModelingStage) curStage).addFormulaChannel(formulaChannelGen); model = curStage.getModel(); } public boolean connectEdge(mxCell edge, mxCell src, mxCell dst) { boolean stageChanged = changeStage(STAGE_DATA_FLOW_MODELING); if (!stageChanged) { return false; } return ((DataFlowModelingStage) curStage).connectEdge(edge, src, dst); } public mxGraph getGraph() { return graph; } public mxGraphComponent getGraphComponent() { return graphComponent; } public DataTransferModel getModel() { model = curStage.getModel(); return model; } public Stage getCurStage() { return curStage; } 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 static class SrcDstAttribute extends EdgeAttribute { private final Object src; private final Object dst; public SrcDstAttribute(Object src, Object dst) { this.src = src; this.dst = dst; } public Object getSource() { return src; } public Object getDestination() { return dst; } public String toString() { return ""; } } }