package application.editor;
import application.editor.stages.ControlFlowModelingStage;
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.algebra.Symbol;
import models.algebra.Variable;
import models.controlFlowModel.ControlFlowGraph;
import models.dataConstraintModel.Channel;
import models.dataConstraintModel.ResourcePath;
import models.dataFlowModel.DataFlowGraph;
import models.dataFlowModel.DataTransferChannel;
import models.dataFlowModel.DataTransferModel;
import models.dataFlowModel.ResourceNode;
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 static ControlFlowModelingStage STAGE_CONTROL_FLOW_DELEGATION = 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);
STAGE_CONTROL_FLOW_DELEGATION = new ControlFlowModelingStage(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();
} else if (curStage instanceof ControlFlowModelingStage) {
return ((ControlFlowModelingStage) curStage).getControlFlowGraph().getDataFlowGraph();
}
return null;
}
public ControlFlowGraph getControlFlowGraph() {
if (curStage instanceof ControlFlowModelingStage) {
return ((ControlFlowModelingStage) curStage).getControlFlowGraph();
}
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);
// 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 | ExpectedDoubleQuotation 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);
// 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 | ExpectedDoubleQuotation e) {
e.printStackTrace();
}
} catch (FileNotFoundException e) {
e.printStackTrace();
}
}
public void save() {
if (curFilePath == null) {
return;
}
File file = new File(curFilePath);
// get a file's extension
String extension = file.getName().substring(file.getName().lastIndexOf("."));
if (extension.contains(".model")) {
saveModel(file);
} else 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();
mxCell dataFlowLayer = (mxCell) ((mxCell) root).getChildAt(Stage.DATA_FLOW_LAYER);
for (int i = 0; i < graph.getModel().getChildCount(dataFlowLayer); i++) {
Object cell = graph.getModel().getChildAt(dataFlowLayer, 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 (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");
}
}
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");
}
}
}
}
fileString.append("}\n");
return fileString.toString();
}
public void setDAGLayout() {
mxCell root = (mxCell) graph.getDefaultParent();
mxCell dataFlowLayer = (mxCell) root.getChildAt(Stage.DATA_FLOW_LAYER);
graph.getModel().beginUpdate();
try {
DAGLayout ctl = new DAGLayout(graph);
ctl.execute(dataFlowLayer);
// for(int i = 0; i < dataFlowLayer.getChildCount(); i++){
// ctl.execute(dataFlowLayer.getChildAt(i));
// }
} 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 List<ResourceNode> getSelectedResourceNodes() {
Object[] sels = graph.getSelectionCells();
List<ResourceNode> resNodes = new ArrayList<>();
if (curStage instanceof DataFlowModelingStage) {
for (Object sel : sels) {
if (sel instanceof mxCell && ((mxCell) sel).isVertex()) {
mxCell cell = ((mxCell) sel);
ResourceNode resNode = ((DataFlowModelingStage) curStage).getResourceNode(cell);
if (resNode != null) {
resNodes.add(resNode);
}
}
}
}
return resNodes;
}
public List<Channel> getSelectedChannels() {
Object[] sels = graph.getSelectionCells();
List<Channel> channels = new ArrayList<>();
for (Object sel : sels) {
if (sel instanceof mxCell && ((mxCell) sel).isVertex()) {
mxCell cell = ((mxCell) sel);
Channel channel = model.getChannel((String) cell.getValue());
if (channel != null) {
channels.add(channel);
} else {
channel = model.getInputChannel((String) cell.getValue());
if (channel != null) {
channels.add(channel);
}
}
}
}
return channels;
}
public void delete() {
boolean stageChanged = changeStage(STAGE_DATA_FLOW_MODELING);
if (!stageChanged) {
return;
}
((DataFlowModelingStage) curStage).delete();
}
public void addResourceNode(ResourceNode parentNode, String resName) {
// Force to change to data-flow modeling stage
boolean stageChanged = changeStage(STAGE_DATA_FLOW_MODELING);
if (!stageChanged) {
return;
}
((DataFlowModelingStage) curStage).addResourceNode(parentNode, resName);
model = curStage.getModel();
}
public void addChannel(String channelName) {
// Force to change to data-flow modeling stage
boolean stageChanged = changeStage(STAGE_DATA_FLOW_MODELING);
if (!stageChanged) {
return;
}
DataTransferChannel channel = null;
if (channelName.contains(Parser.LEFT_BRACKET) && channelName.contains(Parser.RIGHT_BRACKET)) {
channel = new DataTransferChannel(channelName.substring(0, channelName.indexOf(Parser.LEFT_BRACKET)));
Parser.TokenStream stream = new Parser.TokenStream();
Parser parser = new Parser(stream);
stream.addLine(channelName.substring(channelName.indexOf(Parser.LEFT_BRACKET), channelName.length()));
try {
String leftBracket = stream.next();
if (leftBracket.equals(Parser.LEFT_BRACKET)) {
// has selectors
String rightBracket = null;
do {
String selector = stream.next();
Variable var = parser.parseVariable(stream, model, selector);
channel.addSelector(var);
rightBracket = stream.next();
} while (rightBracket.equals(Parser.COMMA));
if (!rightBracket.equals(Parser.RIGHT_BRACKET)) throw new ExpectedRightBracket(stream.getLine());
leftBracket = stream.next();
}
} catch (ExpectedRightBracket e) {
e.printStackTrace();
}
} else {
channel = new DataTransferChannel(channelName);
}
((DataFlowModelingStage) curStage).addChannel(channel);
model = curStage.getModel();
}
public void addEventChannel(String channelName) {
// Force to change to data-flow modeling stage
boolean stageChanged = changeStage(STAGE_DATA_FLOW_MODELING);
if (!stageChanged) {
return;
}
DataTransferChannel eventChannel = null;
if (channelName.contains(Parser.LEFT_BRACKET) && channelName.contains(Parser.RIGHT_BRACKET)) {
eventChannel = new DataTransferChannel(channelName.substring(0, channelName.indexOf(Parser.LEFT_BRACKET)));
Parser.TokenStream stream = new Parser.TokenStream();
Parser parser = new Parser(stream);
stream.addLine(channelName.substring(channelName.indexOf(Parser.LEFT_BRACKET), channelName.length()));
try {
String leftBracket = stream.next();
if (leftBracket.equals(Parser.LEFT_BRACKET)) {
// has selectors
String rightBracket = null;
do {
String selector = stream.next();
Variable var = parser.parseVariable(stream, model, selector);
eventChannel.addSelector(var);
rightBracket = stream.next();
} while (rightBracket.equals(Parser.COMMA));
if (!rightBracket.equals(Parser.RIGHT_BRACKET)) throw new ExpectedRightBracket(stream.getLine());
leftBracket = stream.next();
}
} catch (ExpectedRightBracket e) {
e.printStackTrace();
}
} else {
eventChannel = new DataTransferChannel(channelName);
}
((DataFlowModelingStage) curStage).addEventChannel(eventChannel);
model = curStage.getModel();
}
public void addFormulaChannel(String channelName, Symbol op) {
// Force to change to data-flow modeling stage
boolean stageChanged = changeStage(STAGE_DATA_FLOW_MODELING);
if (!stageChanged) {
return;
}
FormulaChannel formulaChannel = new FormulaChannel(channelName, op);
((DataFlowModelingStage) curStage).addFormulaChannel(formulaChannel);
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 "";
}
}
}