package application.simulator; import application.editor.Editor; import com.mxgraph.model.mxCell; import com.mxgraph.model.mxIGraphModel; import com.mxgraph.swing.mxGraphComponent; import com.mxgraph.swing.view.mxICellEditor; import com.mxgraph.util.mxConstants; import com.mxgraph.util.mxUtils; import com.mxgraph.view.mxCellState; import models.algebra.*; import models.dataConstraintModel.Channel; import models.dataConstraintModel.ChannelMember; import models.dataConstraintModel.ResourcePath; import models.dataFlowModel.DataTransferChannel; import models.dataFlowModel.PushPullAttribute; import models.dataFlowModel.PushPullValue; import models.dataFlowModel.ResolvingMultipleDefinitionIsFutureWork; import parser.Parser; import parser.Parser.TokenStream; import parser.exceptions.ExpectedColon; import parser.exceptions.ExpectedDoubleQuotation; import parser.exceptions.ExpectedRightBracket; import parser.exceptions.WrongJsonExpression; import simulator.Event; import simulator.Resource; import simulator.ResourceIdentifier; import simulator.Simulator; import javax.swing.*; import java.awt.*; import java.util.ArrayList; import java.util.EventObject; import java.util.List; public class InputEventCellEditor implements mxICellEditor { public int DEFAULT_MIN_WIDTH = 70; public int DEFAULT_MIN_HEIGHT = 30; public double DEFAULT_MINIMUM_EDITOR_SCALE = 1; protected double minimumEditorScale = DEFAULT_MINIMUM_EDITOR_SCALE; protected int minimumWidth = DEFAULT_MIN_WIDTH; protected int minimumHeight = DEFAULT_MIN_HEIGHT; private final mxGraphComponent graphComponent; private final SimulatorWindow simulatorWindow; private final Simulator simulator; private final Editor editor; private Object editingCell; private EventObject trigger; private JComboBox<String> comboBox; public InputEventCellEditor(mxGraphComponent graphComponent, SimulatorWindow simulatorWindow) { this.graphComponent = graphComponent; this.simulatorWindow = simulatorWindow; simulator = simulatorWindow.getSimulator(); editor = simulatorWindow.getEditor(); } @Override public Object getEditingCell() { return editingCell; } @Override public void startEditing(Object cell, EventObject evt) { if (editingCell != null) { stopEditing(true); } if (!graphComponent.getGraph().getModel().isEdge(cell)) { Resource res = simulator.getCurState().getResource((String) ((mxCell) cell).getValue()); ResourceIdentifier resId = res.getResourceIdentifier(); // Resource ArrayList<DataTransferChannel> eventChs = new ArrayList<>(); // IOChannel List ArrayList<String> messages = new ArrayList<>(); // ADL message ArrayList<Expression> eventMessages = new ArrayList<>(); // Message list ResourcePath eventResPath = null; for (Channel ch : simulator.getModel().getInputChannels()) { // All channel if (((DataTransferChannel) ch).getInputResources().isEmpty()) { // Input channel or Normal channel for (ChannelMember out : ((DataTransferChannel) ch).getOutputChannelMembers()) { ResourcePath resPath = out.getResource(); if (resId.isInstanceOf(resPath)) { // account.uid == accounts.123 eventResPath = resPath; eventChs.add(((DataTransferChannel) ch)); String message = null; Expression mesExp = out.getStateTransition().getMessageExpression(); // sync(a,b) eventMessages.add(mesExp); if (mesExp instanceof Term) { message = ((Term) mesExp).getSymbol().toString(); // sync } else if (mesExp instanceof Variable) { message = ((Variable) mesExp).getName(); // x,y,z.. } messages.add(message); // Pull-down } } } } if (messages.isEmpty()) { return; } String[] eventList = messages.toArray(new String[messages.size()]); JComboBox<String> event = new JComboBox<>(eventList); JPanel eventChoice = new JPanel(); eventChoice.add(event); // FirstEventChoice int ret = JOptionPane.showConfirmDialog(simulatorWindow, eventChoice, "Event Choice", JOptionPane.OK_CANCEL_OPTION); if (ret == JOptionPane.OK_OPTION) { JPanel inputEvent = new JPanel(); int i, eventNum; i = eventNum = 0; for (String eventString : eventList) { if (eventString.equals(event.getSelectedItem().toString())) { eventNum = i; } i++; } JTextArea textArea = new JTextArea(eventMessages.get(eventNum).toString(), 10, 30); // EventInput inputEvent.add(textArea); int approve = JOptionPane.showConfirmDialog(simulatorWindow, inputEvent, "Event Code", JOptionPane.OK_CANCEL_OPTION); if (approve == JOptionPane.OK_OPTION) { try { TokenStream stream = new Parser.TokenStream(); Parser parser = new Parser(stream); stream.addLine(textArea.getText()); Expression eventMessage = parser.parseTerm(stream, simulator.getModel()); Event newEvent = new Event(eventChs.get(eventNum), eventMessage, eventResPath, simulator.getCurState().getResource(resId)); simulator.transition(newEvent); // SimulationLayout layout = new SimulationLayout(simulator.getCurState()); // layout.constructSimulateGraph(graph, simulator); graphComponent.setCellEditor(new InputEventCellEditor(graphComponent, simulatorWindow)); } catch (ParameterizedIdentifierIsFutureWork | ResolvingMultipleDefinitionIsFutureWork | InvalidMessage | UnificationFailed | ValueUndefined | ExpectedRightBracket | WrongJsonExpression | ExpectedColon | ExpectedDoubleQuotation e) { e.printStackTrace(); } } } return; } mxCellState state = graphComponent.getGraph().getView().getState(cell); if (state != null && state.getLabel() != null && !state.getLabel().isEmpty()) { editingCell = cell; trigger = evt; double scale = Math.max(minimumEditorScale, graphComponent.getGraph().getView().getScale()); Object value = graphComponent.getGraph().getModel().getValue(cell); if (value instanceof PushPullAttribute) { PushPullAttribute attr = (PushPullAttribute) value; comboBox = new JComboBox<>(attr.getOptionStrings()); comboBox.setBorder(BorderFactory.createEmptyBorder()); comboBox.setOpaque(false); comboBox.setBounds(getEditorBounds(state, scale)); comboBox.setVisible(true); graphComponent.getGraphControl().add(comboBox, 0); comboBox.updateUI(); } } } // private mxGraph constructNextSimulateGraph(Set<Resource> simulateRes, DataTransferModel model,DataFlowGraph dataFlowGraph, mxGraph nextGraph) { // bReflectingArchitectureModel = true; // ((mxGraphModel) nextGraph.getModel()).clear(); // Object parent = nextGraph.getDefaultParent(); // nextGraph.getModel().beginUpdate(); // // try { // Map<Resource, Object> resources = new HashMap<>(); // // // create resource vertices // for (Resource resNode: simulateRes) { // int w = 400; // int h = 150; // ResourcePath res = resNode.getResourceIdentifier(); // Object resource = nextGraph.insertVertex(parent, null, // res.toString(), x, y, w, h, // "shape=ellipse;perimeter=ellipsePerimeter;verticalAlign=top;"); // insert a resource as a vertex // resources.put(resNode, resource); // // createNextChildSimulateResourceVerticies(resource, resNode, resources, w, h); // x+=400; // } // // } finally { // nextGraph.getModel().endUpdate(); // } // // bReflectingArchitectureModel = false; // return nextGraph; // } // // private void createNextChildSimulateResourceVerticies(Object resource, Resource resNode, Map<Resource, Object> resources, int w, int h) { //sample // // if(resNode.getChildren() != null) { // for (Resource childNode: resNode.getChildren()) { // int i = 1; // ResourcePath childRes = childNode.getResourceIdentifier(); // Object childResource = graph.insertVertex(resource, null, // childRes.toString(), x/i, 0, w/(i+1), h/(i+2), // "shape=ellipse;perimeter=ellipsePerimeter;verticalAlign=top;"); // insert a resource as a vertex // resources.put(childNode, childResource); // i++; // createNextChildSimulateResourceVerticies(childResource, childNode, resources, w, h); // } // } // if (resNode.getChildren() == null || resNode.getChildren().size() == 0) { // Object state = graph.insertVertex(resource, null, // resNode.getState().getValue().toString(), 0.5, 0.5, 0.25, 0.25, "opacity=0;verticalAlign=down;", true); // insert a state label as a vertex // } // } @Override public void stopEditing(boolean cancel) { if (editingCell != null) { comboBox.transferFocusUpCycle(); Object cell = editingCell; editingCell = null; if (!cancel) { EventObject trig = trigger; trigger = null; Object value = graphComponent.getGraph().getModel().getValue(cell); if (value instanceof PushPullAttribute) { PushPullAttribute attr = (PushPullAttribute) value; List<PushPullValue> options = attr.getOptions(); PushPullValue selected = null; for (PushPullValue option : options) { if (option.toString().equals(getCurrentValue())) { selected = option; break; } } if (selected != null) { options.remove(selected); options.add(0, selected); } graphComponent.labelChanged(cell, attr, trig); } } else { mxCellState state = graphComponent.getGraph().getView().getState(cell); graphComponent.redraw(state); } if (comboBox.getParent() != null) { comboBox.setVisible(false); comboBox.getParent().remove(comboBox); } graphComponent.requestFocusInWindow(); } } public String getCurrentValue() { return (String) comboBox.getSelectedItem(); } /** * Returns the bounds to be used for the editor. */ public Rectangle getEditorBounds(mxCellState state, double scale) { mxIGraphModel model = state.getView().getGraph().getModel(); Rectangle bounds; bounds = state.getLabelBounds().getRectangle(); bounds.height += 10; // Applies the horizontal and vertical label positions if (model.isVertex(state.getCell())) { String horizontal = mxUtils.getString(state.getStyle(), mxConstants.STYLE_LABEL_POSITION, mxConstants.ALIGN_CENTER); if (horizontal.equals(mxConstants.ALIGN_LEFT)) { bounds.x -= (int) state.getWidth(); } else if (horizontal.equals(mxConstants.ALIGN_RIGHT)) { bounds.x += (int) state.getWidth(); } String vertical = mxUtils.getString(state.getStyle(), mxConstants.STYLE_VERTICAL_LABEL_POSITION, mxConstants.ALIGN_MIDDLE); if (vertical.equals(mxConstants.ALIGN_TOP)) { bounds.y -= (int) state.getHeight(); } else if (vertical.equals(mxConstants.ALIGN_BOTTOM)) { bounds.y += (int) state.getHeight(); } } bounds.setSize((int) Math.max(bounds.getWidth(), Math.round(minimumWidth * scale)), (int) Math.max(bounds.getHeight(), Math.round(minimumHeight * scale))); return bounds; } }