diff --git a/AlgebraicDataflowArchitectureModel/.settings/org.eclipse.jdt.core.prefs b/AlgebraicDataflowArchitectureModel/.settings/org.eclipse.jdt.core.prefs index 3fd6c25..5caa538 100644 --- a/AlgebraicDataflowArchitectureModel/.settings/org.eclipse.jdt.core.prefs +++ b/AlgebraicDataflowArchitectureModel/.settings/org.eclipse.jdt.core.prefs @@ -1,5 +1,6 @@ eclipse.preferences.version=1 org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled +org.eclipse.jdt.core.compiler.codegen.methodParameters=do not generate org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8 org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve org.eclipse.jdt.core.compiler.compliance=1.8 @@ -8,5 +9,5 @@ org.eclipse.jdt.core.compiler.debug.sourceFile=generate org.eclipse.jdt.core.compiler.problem.assertIdentifier=error org.eclipse.jdt.core.compiler.problem.enumIdentifier=error -org.eclipse.jdt.core.compiler.release=enabled +org.eclipse.jdt.core.compiler.release=disabled org.eclipse.jdt.core.compiler.source=1.8 diff --git a/AlgebraicDataflowArchitectureModel/lib/jgraphx.jar b/AlgebraicDataflowArchitectureModel/lib/jgraphx.jar new file mode 100644 index 0000000..72b5aae --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/lib/jgraphx.jar Binary files differ diff --git a/AlgebraicDataflowArchitectureModel/src/Main.java b/AlgebraicDataflowArchitectureModel/src/Main.java new file mode 100644 index 0000000..119bdd3 --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/src/Main.java @@ -0,0 +1,12 @@ + + +import graphicalrefactor.views.GraphicalRefactor; + +public class Main { + + public static void main(String[] args) { + GraphicalRefactor frame = new GraphicalRefactor(); + frame.setVisible(true); + } + +} diff --git a/AlgebraicDataflowArchitectureModel/src/graphicalrefactor/actions/AbstractEditorAction.java b/AlgebraicDataflowArchitectureModel/src/graphicalrefactor/actions/AbstractEditorAction.java new file mode 100644 index 0000000..c473f18 --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/src/graphicalrefactor/actions/AbstractEditorAction.java @@ -0,0 +1,23 @@ +package graphicalrefactor.actions; + +import javax.swing.AbstractAction; +import javax.swing.Icon; + +import com.mxgraph.view.mxGraph; + +import graphicalrefactor.editor.Editor; + +public abstract class AbstractEditorAction extends AbstractAction { + + protected Editor editor; + + public AbstractEditorAction(String name, Editor editor) { + super(name); + this.editor = editor; + } + + public void setEditor(Editor editor) { + this.editor = editor; + } + +} \ No newline at end of file diff --git a/AlgebraicDataflowArchitectureModel/src/graphicalrefactor/actions/AbstractViewerAction.java b/AlgebraicDataflowArchitectureModel/src/graphicalrefactor/actions/AbstractViewerAction.java new file mode 100644 index 0000000..97181bf --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/src/graphicalrefactor/actions/AbstractViewerAction.java @@ -0,0 +1,22 @@ +package graphicalrefactor.actions; + +import java.awt.event.ActionEvent; + +import javax.swing.AbstractAction; + +import com.mxgraph.swing.mxGraphComponent; + +public class AbstractViewerAction extends AbstractAction { + + protected mxGraphComponent graphComponent = null; + + public AbstractViewerAction(String name, mxGraphComponent graphComponent) { + super(name); + this.graphComponent = graphComponent; + } + + @Override + public void actionPerformed(ActionEvent e) { + } + +} diff --git a/AlgebraicDataflowArchitectureModel/src/graphicalrefactor/actions/CircleLayoutAction.java b/AlgebraicDataflowArchitectureModel/src/graphicalrefactor/actions/CircleLayoutAction.java new file mode 100644 index 0000000..07f3b7b --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/src/graphicalrefactor/actions/CircleLayoutAction.java @@ -0,0 +1,18 @@ +package graphicalrefactor.actions; + +import java.awt.event.ActionEvent; + +import graphicalrefactor.editor.Editor; + +public class CircleLayoutAction extends AbstractEditorAction { + + public CircleLayoutAction(Editor editor) { + super("Circle Layout", editor); + } + + @Override + public void actionPerformed(ActionEvent e) { + editor.setCircleLayout(); + } + +} diff --git a/AlgebraicDataflowArchitectureModel/src/graphicalrefactor/actions/ExitAction.java b/AlgebraicDataflowArchitectureModel/src/graphicalrefactor/actions/ExitAction.java new file mode 100644 index 0000000..c18a6c5 --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/src/graphicalrefactor/actions/ExitAction.java @@ -0,0 +1,22 @@ +package graphicalrefactor.actions; + +import java.awt.event.ActionEvent; + +import javax.swing.AbstractAction; + +public class ExitAction extends AbstractAction { + /** + * + */ + private static final long serialVersionUID = -8733766417378036850L; + + public ExitAction() { + super("Exit"); + } + + @Override + public void actionPerformed(ActionEvent e) { + System.exit(0); + } + +} diff --git a/AlgebraicDataflowArchitectureModel/src/graphicalrefactor/actions/OpenAction.java b/AlgebraicDataflowArchitectureModel/src/graphicalrefactor/actions/OpenAction.java new file mode 100644 index 0000000..4705a19 --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/src/graphicalrefactor/actions/OpenAction.java @@ -0,0 +1,52 @@ +package graphicalrefactor.actions; + +import java.awt.event.ActionEvent; +import java.io.File; + +import javax.swing.JFileChooser; +import javax.swing.filechooser.FileFilter; + +import graphicalrefactor.editor.Editor; + +public class OpenAction extends AbstractEditorAction { + /** + * + */ + private static final long serialVersionUID = -8290761032629599683L; + + private String lastDir = null; + + public OpenAction(Editor editor) { + super("Open...", editor); + } + + @Override + public void actionPerformed(ActionEvent e) { + if (editor != null) { + String wd = (lastDir != null) ? lastDir : System.getProperty("user.dir"); + + JFileChooser fc = new JFileChooser(wd); + + // Adds file filter for supported file format + FileFilter defaultFilter = new FileFilter() { + + public boolean accept(File file) { + String lcase = file.getName().toLowerCase(); + return lcase.endsWith(".model"); + } + + @Override + public String getDescription() { + return null; + } + }; + fc.addChoosableFileFilter(defaultFilter); + int rc = fc.showDialog(null, "Open File"); + if (rc == JFileChooser.APPROVE_OPTION) { + lastDir = fc.getSelectedFile().getParent(); + editor.open(fc.getSelectedFile()); + } + } + } + +} diff --git a/AlgebraicDataflowArchitectureModel/src/graphicalrefactor/actions/PrototypeGenerateAction.java b/AlgebraicDataflowArchitectureModel/src/graphicalrefactor/actions/PrototypeGenerateAction.java new file mode 100644 index 0000000..fe859cd --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/src/graphicalrefactor/actions/PrototypeGenerateAction.java @@ -0,0 +1,21 @@ +package graphicalrefactor.actions; + +import java.awt.event.ActionEvent; + +import graphicalrefactor.editor.Editor; + +public class PrototypeGenerateAction extends AbstractEditorAction { + /** + * + */ + private static final long serialVersionUID = -3694103632055735068L; + + public PrototypeGenerateAction(Editor editor) { + super("Generate Prototype", editor); + } + + @Override + public void actionPerformed(ActionEvent e) { + } + +} diff --git a/AlgebraicDataflowArchitectureModel/src/graphicalrefactor/actions/SaveAction.java b/AlgebraicDataflowArchitectureModel/src/graphicalrefactor/actions/SaveAction.java new file mode 100644 index 0000000..118f37a --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/src/graphicalrefactor/actions/SaveAction.java @@ -0,0 +1,23 @@ +package graphicalrefactor.actions; + +import java.awt.event.ActionEvent; + +import javax.swing.AbstractAction; + +public class SaveAction extends AbstractAction { + /** + * + */ + private static final long serialVersionUID = 5660460585305281982L; + + public SaveAction() { + super("Save"); + } + + @Override + public void actionPerformed(ActionEvent e) { + // TODO Auto-generated method stub + + } + +} diff --git a/AlgebraicDataflowArchitectureModel/src/graphicalrefactor/actions/TreeLayoutAction.java b/AlgebraicDataflowArchitectureModel/src/graphicalrefactor/actions/TreeLayoutAction.java new file mode 100644 index 0000000..1ce409f --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/src/graphicalrefactor/actions/TreeLayoutAction.java @@ -0,0 +1,18 @@ +package graphicalrefactor.actions; + +import java.awt.event.ActionEvent; + +import graphicalrefactor.editor.Editor; + +public class TreeLayoutAction extends AbstractEditorAction { + + public TreeLayoutAction(Editor editor) { + super("Tree Layout", editor); + } + + @Override + public void actionPerformed(ActionEvent e) { + editor.setTreeLayout(); + } + +} diff --git a/AlgebraicDataflowArchitectureModel/src/graphicalrefactor/actions/ZoomInAction.java b/AlgebraicDataflowArchitectureModel/src/graphicalrefactor/actions/ZoomInAction.java new file mode 100644 index 0000000..e2d1549 --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/src/graphicalrefactor/actions/ZoomInAction.java @@ -0,0 +1,28 @@ +package graphicalrefactor.actions; + +import java.awt.event.ActionEvent; + +import javax.swing.AbstractAction; +import javax.swing.JOptionPane; + +import com.mxgraph.swing.mxGraphComponent; +import com.mxgraph.util.mxResources; + +import graphicalrefactor.editor.Editor; + +public class ZoomInAction extends AbstractViewerAction { + /** + * + */ + private static final long serialVersionUID = 6758532166946195926L; + + public ZoomInAction(mxGraphComponent graphComponent) { + super("Zoom In", graphComponent); + } + + @Override + public void actionPerformed(ActionEvent e) { + graphComponent.zoomIn(); + } + +} diff --git a/AlgebraicDataflowArchitectureModel/src/graphicalrefactor/actions/ZoomOutAction.java b/AlgebraicDataflowArchitectureModel/src/graphicalrefactor/actions/ZoomOutAction.java new file mode 100644 index 0000000..7518f38 --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/src/graphicalrefactor/actions/ZoomOutAction.java @@ -0,0 +1,26 @@ +package graphicalrefactor.actions; + +import java.awt.event.ActionEvent; + +import javax.swing.AbstractAction; + +import com.mxgraph.swing.mxGraphComponent; + +import graphicalrefactor.editor.Editor; + +public class ZoomOutAction extends AbstractViewerAction { + /** + * + */ + private static final long serialVersionUID = 8657530769383486605L; + + public ZoomOutAction(mxGraphComponent graphComponent) { + super("Zoom Out", graphComponent); + } + + @Override + public void actionPerformed(ActionEvent e) { + graphComponent.zoomOut(); + } + +} diff --git a/AlgebraicDataflowArchitectureModel/src/graphicalrefactor/editor/Editor.java b/AlgebraicDataflowArchitectureModel/src/graphicalrefactor/editor/Editor.java new file mode 100644 index 0000000..ec5e155 --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/src/graphicalrefactor/editor/Editor.java @@ -0,0 +1,175 @@ +package graphicalrefactor.editor; + +import java.io.BufferedReader; +import java.io.File; +import java.io.FileNotFoundException; +import java.io.FileReader; +import java.util.HashMap; + +import com.mxgraph.layout.mxCircleLayout; +import com.mxgraph.layout.mxCompactTreeLayout; +import com.mxgraph.layout.mxParallelEdgeLayout; +import com.mxgraph.layout.mxPartitionLayout; +import com.mxgraph.layout.mxStackLayout; +import com.mxgraph.model.mxCell; +import com.mxgraph.model.mxGeometry; +import com.mxgraph.model.mxGraphModel; +import com.mxgraph.util.mxPoint; +import com.mxgraph.view.mxGraph; + +import models.Edge; +import models.Node; +import models.dataFlowModel.DataFlowModel; +import models.dataFlowModel.DataflowChannelGenerator; +import models.dataFlowModel.PushPullAttribute; +import models.dataFlowModel.PushPullValue; +import models.dataFlowModel.ResourceDependency; +import models.dataFlowModel.ResourceDependencyGraph; +import models.dataFlowModel.ResourceNode; +import parser.ExpectedChannel; +import parser.ExpectedChannelName; +import parser.ExpectedEquals; +import parser.ExpectedInOrOutKeyword; +import parser.ExpectedLeftCurlyBracket; +import parser.ExpectedRHSExpression; +import parser.ExpectedRightBracket; +import parser.ExpectedStateTransition; +import parser.Parser; +import parser.WrongLHSExpression; +import parser.WrongRHSExpression; + +public class Editor { + final int PORT_DIAMETER = 8; + final int PORT_RADIUS = PORT_DIAMETER / 2; + + private mxGraph graph = null; + private DataFlowModel model = null; + + public Editor(mxGraph graph) { + this.graph = graph; + } + + public mxGraph getGraph() { + return graph; + } + + public void setGraph(mxGraph graph) { + this.graph = graph; + } + + public DataFlowModel getModel() { + return model; + } + + public void setModel(DataFlowModel model) { + this.model = model; + } + + public DataFlowModel open(File file) { + try { + Parser parser = new Parser(new BufferedReader(new FileReader(file))); + try { + model = parser.doParse(); + + graph = constructGraph(model); + return model; + } catch (ExpectedChannel | ExpectedChannelName | ExpectedLeftCurlyBracket | ExpectedInOrOutKeyword + | ExpectedStateTransition | ExpectedEquals | ExpectedRHSExpression | WrongLHSExpression + | WrongRHSExpression | ExpectedRightBracket e) { + e.printStackTrace(); + } + } catch (FileNotFoundException e) { + e.printStackTrace(); + } + return null; + } + + public mxGraph constructGraph(DataFlowModel model) { + ResourceDependencyGraph resourceDependencyGraph = model.getResourceDependencyGraph(); + + ((mxGraphModel) graph.getModel()).clear(); + Object parent = graph.getDefaultParent(); + graph.getModel().beginUpdate(); + try { + mxGeometry geo1 = new mxGeometry(0, 0.5, PORT_DIAMETER, PORT_DIAMETER); + geo1.setOffset(new mxPoint(-PORT_RADIUS, -PORT_RADIUS)); + geo1.setRelative(true); + + mxGeometry geo2 = new mxGeometry(1.0, 0.5, PORT_DIAMETER, PORT_DIAMETER); + geo2.setOffset(new mxPoint(-PORT_RADIUS, -PORT_RADIUS)); + geo2.setRelative(true); + + HashMap channelsIn = new HashMap<>(); + HashMap channelsOut = new HashMap<>(); + HashMap resources = new HashMap<>(); + + for (Edge e: resourceDependencyGraph.getEdges()) { + if (e instanceof ResourceDependency) { + ResourceDependency dependency = (ResourceDependency) e; + DataflowChannelGenerator channelGen = dependency.getChannelGenerator(); + if (channelsIn.get(channelGen) == null || channelsOut.get(channelGen) == null) { + Object channel = graph.insertVertex(parent, null, channelGen.getChannelName(), 150, 20, 30, 30); // insert a channel as a vertex + mxCell port_in = new mxCell(null, geo1, "shape=ellipse;perimter=ellipsePerimeter"); + port_in.setVertex(true); + graph.addCell(port_in, channel); + mxCell port_out = new mxCell(null, geo2, "shape=ellipse;perimter=ellipsePerimeter"); + port_out.setVertex(true); + graph.addCell(port_out, channel); + channelsIn.put(channelGen, port_in); + channelsOut.put(channelGen, port_out); + } + } + } + + for (Node n: resourceDependencyGraph.getNodes()) { + if (n instanceof ResourceNode) { + ResourceNode resourceNode = (ResourceNode) n; + Object resource = graph.insertVertex(parent, null, resourceNode.getIdentifierTemplate().getResourceName(), + 20, 20, 80, 30, "shape=ellipse;perimeter=ellipsePerimeter"); // insert a resource as a node + resources.put(resourceNode, resource); + } + } + + for (Edge e: resourceDependencyGraph.getEdges()) { + if (e instanceof ResourceDependency) { + ResourceDependency dependency = (ResourceDependency) e; + dependency.setAttribute(new PushPullAttribute(new PushPullValue[] {PushPullValue.PUSHorPULL, PushPullValue.PULL, PushPullValue.PUSH})); + DataflowChannelGenerator channelGen = dependency.getChannelGenerator(); + graph.insertEdge(parent, null, dependency.getAttribute(), resources.get(dependency.getSource()), channelsIn.get(channelGen)); + graph.insertEdge(parent, null, null, channelsOut.get(channelGen), resources.get(dependency.getDestination())); + } + } + + } finally { + graph.getModel().endUpdate(); + } + setTreeLayout(); + + return graph; + } + + 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(); + } + } +} diff --git a/AlgebraicDataflowArchitectureModel/src/graphicalrefactor/views/ComboBoxCellEditor.java b/AlgebraicDataflowArchitectureModel/src/graphicalrefactor/views/ComboBoxCellEditor.java new file mode 100644 index 0000000..334ba7b --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/src/graphicalrefactor/views/ComboBoxCellEditor.java @@ -0,0 +1,155 @@ +package graphicalrefactor.views; + +import java.awt.Rectangle; +import java.util.EventObject; +import java.util.List; + +import javax.swing.BorderFactory; +import javax.swing.JComboBox; + +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.dataFlowModel.PushPullAttribute; +import models.dataFlowModel.PushPullValue; + +public class ComboBoxCellEditor 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 Object editingCell; + private EventObject trigger; + private JComboBox comboBox; + private mxGraphComponent graphComponent; + + public ComboBoxCellEditor(mxGraphComponent graphComponent) { + this.graphComponent = graphComponent; + } + + @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)) return; + + 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(); + } + } + } + + @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 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; + } + +} diff --git a/AlgebraicDataflowArchitectureModel/src/graphicalrefactor/views/GraphicalRefactor.java b/AlgebraicDataflowArchitectureModel/src/graphicalrefactor/views/GraphicalRefactor.java new file mode 100644 index 0000000..8c93eba --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/src/graphicalrefactor/views/GraphicalRefactor.java @@ -0,0 +1,68 @@ +package graphicalrefactor.views; + +import javax.swing.JFrame; + +import com.mxgraph.model.mxGeometry; +import com.mxgraph.swing.mxGraphComponent; +import com.mxgraph.swing.handler.mxRubberband; +import com.mxgraph.swing.view.mxICellEditor; +import com.mxgraph.view.mxGraph; + +import graphicalrefactor.editor.Editor; + +public class GraphicalRefactor extends JFrame { + private static final long serialVersionUID = -8690140317781055614L; + + private Editor editor; + private mxGraph graph; + private GraphicalRefactorMenuBar menuBar; + private mxGraphComponent graphComponent; + + public GraphicalRefactor() { + setTitle("Graphical Refactor"); + setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + + graph = new mxGraph() { + public boolean isPort(Object cell) { + mxGeometry geo = getCellGeometry(cell); + + return (geo != null) ? geo.isRelative() : false; + } + + public boolean isCellFoldable(Object cell, boolean collapse) { + return false; + } + }; + + graphComponent = new mxGraphComponent(graph) { + protected mxICellEditor createCellEditor() { + return new ComboBoxCellEditor(this); + } + }; + getContentPane().add(graphComponent); + new mxRubberband(graphComponent); + + editor = new Editor(graph); + + menuBar = new GraphicalRefactorMenuBar(this); + setJMenuBar(menuBar); + setSize(870, 640); + } + + public mxGraph getGraph() { + return graph; + } + + public mxGraphComponent getGraphComponent() { + return graphComponent; + } + + public Editor getEditor() { + return editor; + } + + public void setEditor(Editor editor) { + this.editor = editor; + } + +} diff --git a/AlgebraicDataflowArchitectureModel/src/graphicalrefactor/views/GraphicalRefactorMenuBar.java b/AlgebraicDataflowArchitectureModel/src/graphicalrefactor/views/GraphicalRefactorMenuBar.java new file mode 100644 index 0000000..bf80b1b --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/src/graphicalrefactor/views/GraphicalRefactorMenuBar.java @@ -0,0 +1,60 @@ +package graphicalrefactor.views; + +import javax.swing.JMenu; +import javax.swing.JMenuBar; + +import com.mxgraph.view.mxGraph; + +import graphicalrefactor.actions.AbstractEditorAction; +import graphicalrefactor.actions.CircleLayoutAction; +import graphicalrefactor.actions.ExitAction; +import graphicalrefactor.actions.OpenAction; +import graphicalrefactor.actions.PrototypeGenerateAction; +import graphicalrefactor.actions.SaveAction; +import graphicalrefactor.actions.TreeLayoutAction; +import graphicalrefactor.actions.ZoomInAction; +import graphicalrefactor.actions.ZoomOutAction; +import graphicalrefactor.editor.Editor; + +public class GraphicalRefactorMenuBar extends JMenuBar { + private static final long serialVersionUID = 4811536194182272888L; + + private GraphicalRefactor graphicalModelRefactor = null; + private OpenAction openAction = null; + private PrototypeGenerateAction prototypeGenerateAction = null; + private TreeLayoutAction treeLayoutAction = null; + private CircleLayoutAction circleLayoutAction = null; + + public GraphicalRefactorMenuBar(GraphicalRefactor graphicalModelRefactor) { + this.graphicalModelRefactor = graphicalModelRefactor; + JMenu menu = null; + menu = add(new JMenu("File")); + menu.add(openAction = new OpenAction(graphicalModelRefactor.getEditor())); + menu.addSeparator(); + menu.add(new SaveAction()); + menu.addSeparator(); + menu.add(new ExitAction()); + + menu = add(new JMenu("Layout")); + menu.add(treeLayoutAction = new TreeLayoutAction(graphicalModelRefactor.getEditor())); + menu.add(circleLayoutAction = new CircleLayoutAction(graphicalModelRefactor.getEditor())); + + menu = add(new JMenu("View")); + menu.add(new ZoomInAction(graphicalModelRefactor.getGraphComponent())); + menu.add(new ZoomOutAction(graphicalModelRefactor.getGraphComponent())); + + menu = add(new JMenu("Generate")); + menu.add(prototypeGenerateAction = new PrototypeGenerateAction(graphicalModelRefactor.getEditor())); + } + + public Editor getEditor() { + return graphicalModelRefactor.getEditor(); + } + + public void setEditor(Editor editor) { + openAction.setEditor(editor); + prototypeGenerateAction.setEditor(editor); + treeLayoutAction.setEditor(editor); + circleLayoutAction.setEditor(editor); + } +} diff --git a/AlgebraicDataflowArchitectureModel/src/models/dataConstraintModel/ChannelGenerator.java b/AlgebraicDataflowArchitectureModel/src/models/dataConstraintModel/ChannelGenerator.java index 8105369..1f1e01d 100644 --- a/AlgebraicDataflowArchitectureModel/src/models/dataConstraintModel/ChannelGenerator.java +++ b/AlgebraicDataflowArchitectureModel/src/models/dataConstraintModel/ChannelGenerator.java @@ -79,4 +79,8 @@ } return identifierTemplates; } + + public String toString() { + return channelName; + } } diff --git a/AlgebraicDataflowArchitectureModel/src/models/dataFlowModel/PushPullAttribute.java b/AlgebraicDataflowArchitectureModel/src/models/dataFlowModel/PushPullAttribute.java index fb1a076..4e7243f 100644 --- a/AlgebraicDataflowArchitectureModel/src/models/dataFlowModel/PushPullAttribute.java +++ b/AlgebraicDataflowArchitectureModel/src/models/dataFlowModel/PushPullAttribute.java @@ -1,22 +1,27 @@ package models.dataFlowModel; -import java.util.HashSet; -import java.util.Set; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; import models.EdgeAttribute; public class PushPullAttribute extends EdgeAttribute { - private Set options; + private List options; public PushPullAttribute() { - options = new HashSet<>(); + options = new ArrayList<>(); + } + + public PushPullAttribute(PushPullValue[] options) { + this.options = new ArrayList<>(Arrays.asList(options)); } - public Set getOptions() { + public List getOptions() { return options; } - public void setOptions(Set options) { + public void setOptions(List options) { this.options = options; } @@ -27,4 +32,17 @@ public void removeOption(PushPullValue option) { options.remove(option); } + + public String[] getOptionStrings() { + String[] optionString = new String[options.size()]; + for (int i = 0; i < options.size(); i++) { + optionString[i] = options.get(i).toString(); + } + return optionString; + } + + public String toString() { + if (options == null || options.size() == 0) return ""; + return options.get(0).toString(); + } } diff --git a/AlgebraicDataflowArchitectureModel/src/models/dataFlowModel/PushPullValue.java b/AlgebraicDataflowArchitectureModel/src/models/dataFlowModel/PushPullValue.java index f50e084..28307c6 100644 --- a/AlgebraicDataflowArchitectureModel/src/models/dataFlowModel/PushPullValue.java +++ b/AlgebraicDataflowArchitectureModel/src/models/dataFlowModel/PushPullValue.java @@ -3,5 +3,18 @@ public enum PushPullValue { PULL, PUSHorPULL, - PUSH + PUSH; + + public String toString() { + switch (this) { + case PUSHorPULL: + return "PUSH/PULL"; + case PUSH: + return "PUSH"; + case PULL: + return "PULL"; + default: + return ""; + } + } } diff --git a/AlgebraicDataflowArchitectureModel/src/tests/GraphicalViewer.java b/AlgebraicDataflowArchitectureModel/src/tests/GraphicalViewer.java new file mode 100644 index 0000000..95c7e05 --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/src/tests/GraphicalViewer.java @@ -0,0 +1,260 @@ +package tests; + + +import java.awt.Color; +import java.awt.Component; +import java.awt.Dimension; +import java.awt.Graphics; +import java.awt.Graphics2D; +import java.awt.Rectangle; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import java.util.EventObject; +import java.util.Map; + +import javax.swing.BorderFactory; +import javax.swing.CellRendererPane; +import javax.swing.JComboBox; +import javax.swing.JFrame; +import javax.swing.JLabel; +import javax.swing.JScrollPane; +import javax.swing.border.BevelBorder; + +import com.mxgraph.canvas.mxICanvas; +import com.mxgraph.canvas.mxImageCanvas; +import com.mxgraph.model.mxCell; +import com.mxgraph.model.mxGeometry; +import com.mxgraph.model.mxIGraphModel; +import com.mxgraph.shape.mxITextShape; +import com.mxgraph.swing.mxGraphComponent; +import com.mxgraph.swing.handler.mxRubberband; +import com.mxgraph.swing.view.mxCellEditor; +import com.mxgraph.swing.view.mxICellEditor; +import com.mxgraph.swing.view.mxInteractiveCanvas; +import com.mxgraph.util.mxConstants; +import com.mxgraph.util.mxPoint; +import com.mxgraph.util.mxUtils; +import com.mxgraph.view.mxCellState; +import com.mxgraph.view.mxGraph; + +public class GraphicalViewer extends JFrame +{ + + /** + * + */ + private static final long serialVersionUID = -844106998814982739L; + + final int PORT_DIAMETER = 8; + final int PORT_RADIUS = PORT_DIAMETER / 2; + + public GraphicalViewer() + { + super("Graphical Viewer"); + + // Demonstrates the use of a Swing component for rendering vertices. + // Note: Use the heavyweight feature to allow for event handling in + // the Swing component that is used for rendering the vertex. + + mxGraph graph = new mxGraph() { + public boolean isPort(Object cell) { + mxGeometry geo = getCellGeometry(cell); + + return (geo != null) ? geo.isRelative() : false; + } + + public boolean isCellFoldable(Object cell, boolean collapse) { + return false; + } + }; + + Object parent = graph.getDefaultParent(); + + graph.getModel().beginUpdate(); + try { + mxGeometry geo1 = new mxGeometry(0, 0.5, PORT_DIAMETER, PORT_DIAMETER); + geo1.setOffset(new mxPoint(-PORT_RADIUS, -PORT_RADIUS)); + geo1.setRelative(true); + + mxGeometry geo2 = new mxGeometry(1.0, 0.5, PORT_DIAMETER, PORT_DIAMETER); + geo2.setOffset(new mxPoint(-PORT_RADIUS, -PORT_RADIUS)); + geo2.setRelative(true); + + Object c1 = graph.insertVertex(parent, null, "c1", 150, 20, 30, 30); + mxCell c1_in = new mxCell(null, geo1, "shape=ellipse;perimter=ellipsePerimeter"); + c1_in.setVertex(true); + graph.addCell(c1_in, c1); + mxCell c1_out = new mxCell(null, geo2, "shape=ellipse;perimter=ellipsePerimeter"); + c1_out.setVertex(true); + graph.addCell(c1_out, c1); + + Object c2 = graph.insertVertex(parent, null, "c2", 150, 100, 30, 30); + mxCell c2_in = new mxCell(null, geo1, "shape=ellipse;perimter=ellipsePerimeter"); + c2_in.setVertex(true); + graph.addCell(c2_in, c2); + mxCell c2_out = new mxCell(null, geo2, "shape=ellipse;perimter=ellipsePerimeter"); + c2_out.setVertex(true); + graph.addCell(c2_out, c2); + + Object payment = graph.insertVertex(parent, null, "payment", 20, 20, 80, 30, "shape=ellipse;perimeter=ellipsePerimeter"); + Object points = graph.insertVertex(parent, null, "points", 240, 20, 80, 30, "shape=ellipse;perimeter=ellipsePerimeter"); + Object history = graph.insertVertex(parent, null, "history", 240, 150, 80, 30, "shape=ellipse;perimeter=ellipsePerimeter"); + + graph.insertEdge(parent, null, "PUSH/PULL", payment, c1_in); + graph.insertEdge(parent, null, "", c1_out, points); + + graph.insertEdge(parent, null, "PUSH/PULL", payment, c2_in); + graph.insertEdge(parent, null, "", c2_out, history); + } finally { + graph.getModel().endUpdate(); + } + + mxGraphComponent graphComponent = new mxGraphComponent(graph) { + protected mxICellEditor createCellEditor() { + final mxGraphComponent graphComponent = this; + return new 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 Object editingCell; + private EventObject trigger; + private JComboBox comboBox; + + @Override + public Object getEditingCell() { + return editingCell; + } + + @Override + public void startEditing(Object cell, EventObject evt) { + if (editingCell != null) { + stopEditing(true); + } + + 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()); + if (comboBox == null) { + comboBox = new JComboBox<>(new String[]{"PUSH", "PULL"}); + comboBox.setBorder(BorderFactory.createEmptyBorder()); + comboBox.setOpaque(false); + } + comboBox.setBounds(getEditorBounds(state, scale)); + comboBox.setVisible(true); + graphComponent.getGraphControl().add(comboBox, 0); + comboBox.updateUI(); + } + } + + @Override + public void stopEditing(boolean cancel) { + if (editingCell != null) { + comboBox.transferFocusUpCycle(); + Object cell = editingCell; + editingCell = null; + if (!cancel) { + EventObject trig = trigger; + trigger = null; + graphComponent.labelChanged(cell, getCurrentValue(), 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; + } + }; + } +// +// public Component[] createComponents(mxCellState state) { +// if (getGraph().getModel().isEdge(state.getCell())) +// { +// return new Component[] { new JComboBox(new String[]{"PUSH", "PULL"}) }; +// } +// +// return null; +// } + }; + + graphComponent.getGraphControl().addMouseListener(new MouseAdapter() { + + public void mouseReleased(MouseEvent e) { + Object cell = graphComponent.getCellAt(e.getX(), e.getY()); + + if (cell != null) { + System.out.println("cell="+graph.getLabel(cell)); + } + } + }); + getContentPane().add(graphComponent); + } + + public static void main(String[] args) { + GraphicalViewer frame = new GraphicalViewer(); + frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + frame.setSize(400, 320); + frame.setVisible(true); + } + +}