package application.simulator; import java.awt.GridBagConstraints; import java.awt.GridBagLayout; import java.awt.Rectangle; import java.util.EventObject; import java.util.HashMap; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.Map; import java.util.Set; import javax.swing.BorderFactory; import javax.swing.JComboBox; import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.JOptionPane; import javax.swing.JPanel; import javax.swing.JTextArea; import javax.swing.JTextField; 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.util.mxUtils; import com.mxgraph.view.mxCellState; import com.mxgraph.view.mxGraph; import com.mxgraph.view.mxGraphView; import application.editor.Editor; import application.layouts.DAGLayout; import models.algebra.Expression; import models.algebra.InvalidMessage; import models.algebra.ParameterizedIdentifierIsFutureWork; import models.algebra.Term; import models.algebra.UnificationFailed; import models.algebra.ValueUndefined; import models.algebra.Variable; import models.dataConstraintModel.Channel; import models.dataConstraintModel.ChannelMember; import models.dataConstraintModel.ResourceHierarchy; import models.dataConstraintModel.ResourcePath; import models.dataFlowModel.DataTransferModel; import models.dataFlowModel.DataFlowGraph; import models.dataFlowModel.DataTransferChannel; import models.dataFlowModel.PushPullAttribute; import models.dataFlowModel.PushPullValue; import models.dataFlowModel.ResolvingMultipleDefinitionIsFutureWork; import models.visualModel.FormulaChannel; 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.ChannelState; import simulator.Resource; import simulator.ResourceIdentifier; import simulator.Simulator; import simulator.Event; import simulator.SystemState; public class InputEventCellEditor implements mxICellEditor { public int DEFAULT_MIN_WIDTH = 70; public int DEFAULT_MIN_HEIGHT = 30; public double DEFAULT_MINIMUM_EDITOR_SCALE = 1; private double x = 20; private double y = 20; protected double minimumEditorScale = DEFAULT_MINIMUM_EDITOR_SCALE; protected int minimumWidth = DEFAULT_MIN_WIDTH; protected int minimumHeight = DEFAULT_MIN_HEIGHT; private SimulatorWindow window; private Object editingCell; private EventObject trigger; private JComboBox<String> comboBox; private mxGraphComponent graphComponent; private Simulator simulator; private JComboBox<String> pulldownMenu; private Editor editor; private boolean bReflectingArchitectureModel = false; public InputEventCellEditor(SimulatorWindow window, mxGraphComponent graphComponent, Simulator simulator, Editor editor) { this.graphComponent = graphComponent; this.window = window; this.simulator = simulator; this.editor = editor; } @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<>();//iOchannelList ArrayList<String> messages = new ArrayList<>();//ADLmessage ArrayList<Expression> eventMessages = new ArrayList<>();//messageList ResourcePath eventResPath = null; for (Channel ch: simulator.getModel().getInputChannels()) {//all channel eventResPath = getSelectableMessages(ch, resId, eventChs, messages, eventMessages, eventResPath); } if(messages.isEmpty()) { return; } String[] eventList = messages.toArray(new String[messages.size()]); JComboBox<String> event = new JComboBox<String>(eventList); JPanel eventChoice = new JPanel(); eventChoice.add(event);//FirstEventChoice int ret = JOptionPane.showConfirmDialog(window, 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(window, 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(window, graphComponent, simulator, this.editor)); } catch (ParameterizedIdentifierIsFutureWork | ResolvingMultipleDefinitionIsFutureWork | InvalidMessage | UnificationFailed | ValueUndefined | ExpectedRightBracket | WrongJsonExpression | ExpectedColon | ExpectedDoubleQuotation e) { e.printStackTrace(); } } } } mxCellState state = graphComponent.getGraph().getView().getState(cell); if (state != null && state.getLabel() != null && !state.getLabel().equals("")) { editingCell = cell; trigger = evt; double scale = Math.max(minimumEditorScale, graphComponent.getGraph().getView().getScale()); Object value = graphComponent.getGraph().getModel().getValue(cell); if (value != null && 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 ResourcePath getSelectableMessages(Channel ch, ResourceIdentifier resId, ArrayList<DataTransferChannel> eventChs, ArrayList<String> messages, ArrayList<Expression> eventMessages, ResourcePath eventResPath) { if (((DataTransferChannel)ch).getInputResources().size() == 0) {//ioch Or normalch for (ChannelMember out: ((DataTransferChannel)ch).getOutputChannelMembers()) { ResourcePath resPath = out.getResource(); if (!out.isOutside() && resId.isInstanceOf(resPath)) {//account.uid == acounts.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);//pulldown } } for (Channel childCh: ch.getChildren()) { eventResPath = getSelectableMessages(childCh, resId, eventChs, messages, eventMessages, eventResPath); } } return eventResPath; } // 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 != null && 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 = null; 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 -= state.getWidth(); } else if (horizontal.equals(mxConstants.ALIGN_RIGHT)) { bounds.x += state.getWidth(); } String vertical = mxUtils.getString(state.getStyle(), mxConstants.STYLE_VERTICAL_LABEL_POSITION, mxConstants.ALIGN_MIDDLE); if (vertical.equals(mxConstants.ALIGN_TOP)) { bounds.y -= state.getHeight(); } else if (vertical.equals(mxConstants.ALIGN_BOTTOM)) { bounds.y += state.getHeight(); } } bounds.setSize( (int) Math.max(bounds.getWidth(), Math.round(minimumWidth * scale)), (int) Math.max(bounds.getHeight(), Math.round(minimumHeight * scale))); return bounds; } }