summaryrefslogtreecommitdiff
path: root/src/main/java/com/c2kernel/graph
diff options
context:
space:
mode:
Diffstat (limited to 'src/main/java/com/c2kernel/graph')
-rw-r--r--src/main/java/com/c2kernel/graph/controller/AutoScrollController.java41
-rw-r--r--src/main/java/com/c2kernel/graph/controller/DeletionController.java92
-rw-r--r--src/main/java/com/c2kernel/graph/controller/EdgeConstructionController.java253
-rw-r--r--src/main/java/com/c2kernel/graph/controller/MultiSelectionDragController.java571
-rw-r--r--src/main/java/com/c2kernel/graph/controller/StartVertexController.java79
-rw-r--r--src/main/java/com/c2kernel/graph/controller/VertexConstructionController.java47
-rw-r--r--src/main/java/com/c2kernel/graph/event/ClearedEvent.java6
-rw-r--r--src/main/java/com/c2kernel/graph/event/EdgeRemovedEvent.java6
-rw-r--r--src/main/java/com/c2kernel/graph/event/EdgesChangedEvent.java6
-rw-r--r--src/main/java/com/c2kernel/graph/event/ElasticBandResizedEvent.java6
-rw-r--r--src/main/java/com/c2kernel/graph/event/ElasticBandSetEvent.java6
-rw-r--r--src/main/java/com/c2kernel/graph/event/EntireModelChangedEvent.java6
-rw-r--r--src/main/java/com/c2kernel/graph/event/ForcedNotifyEvent.java6
-rw-r--r--src/main/java/com/c2kernel/graph/event/GraphModelEvent.java7
-rw-r--r--src/main/java/com/c2kernel/graph/event/GraphModelResizedEvent.java6
-rw-r--r--src/main/java/com/c2kernel/graph/event/NewEdgeEndPointChangedEvent.java6
-rw-r--r--src/main/java/com/c2kernel/graph/event/SelectionChangedEvent.java9
-rw-r--r--src/main/java/com/c2kernel/graph/event/SelectionMovedEvent.java7
-rw-r--r--src/main/java/com/c2kernel/graph/event/StartVertexIdChangedEvent.java6
-rw-r--r--src/main/java/com/c2kernel/graph/event/VertexAddedEvent.java6
-rw-r--r--src/main/java/com/c2kernel/graph/event/VertexCreatedEvent.java6
-rw-r--r--src/main/java/com/c2kernel/graph/event/VertexMovedEvent.java6
-rw-r--r--src/main/java/com/c2kernel/graph/event/VertexRemovedEvent.java6
-rw-r--r--src/main/java/com/c2kernel/graph/event/VerticesChangedEvent.java6
-rw-r--r--src/main/java/com/c2kernel/graph/layout/DefaultGraphLayoutGenerator.java116
-rw-r--r--src/main/java/com/c2kernel/graph/layout/IntegerWrapper.java13
-rw-r--r--src/main/java/com/c2kernel/graph/model/DirectedEdge.java99
-rw-r--r--src/main/java/com/c2kernel/graph/model/EdgeFactory.java14
-rw-r--r--src/main/java/com/c2kernel/graph/model/ElasticBand.java17
-rw-r--r--src/main/java/com/c2kernel/graph/model/GraphModel.java900
-rw-r--r--src/main/java/com/c2kernel/graph/model/GraphModelCastorData.java29
-rw-r--r--src/main/java/com/c2kernel/graph/model/GraphModelManager.java143
-rw-r--r--src/main/java/com/c2kernel/graph/model/GraphPoint.java18
-rw-r--r--src/main/java/com/c2kernel/graph/model/Graphable.java55
-rw-r--r--src/main/java/com/c2kernel/graph/model/GraphableEdge.java71
-rw-r--r--src/main/java/com/c2kernel/graph/model/GraphableVertex.java261
-rw-r--r--src/main/java/com/c2kernel/graph/model/Selection.java35
-rw-r--r--src/main/java/com/c2kernel/graph/model/TypeNameAndConstructionInfo.java24
-rw-r--r--src/main/java/com/c2kernel/graph/model/Vertex.java308
-rw-r--r--src/main/java/com/c2kernel/graph/model/VertexFactory.java16
-rw-r--r--src/main/java/com/c2kernel/graph/model/VertexOutlineCreator.java10
-rw-r--r--src/main/java/com/c2kernel/graph/traversal/GraphTraversal.java85
-rw-r--r--src/main/java/com/c2kernel/graph/view/DefaultDirectedEdgeRenderer.java75
-rw-r--r--src/main/java/com/c2kernel/graph/view/DefaultVertexRenderer.java60
-rw-r--r--src/main/java/com/c2kernel/graph/view/DirectedEdgeRenderer.java11
-rw-r--r--src/main/java/com/c2kernel/graph/view/EditorModeListener.java8
-rw-r--r--src/main/java/com/c2kernel/graph/view/EditorPanel.java104
-rw-r--r--src/main/java/com/c2kernel/graph/view/EditorToolBar.java346
-rw-r--r--src/main/java/com/c2kernel/graph/view/GraphPanel.java272
-rw-r--r--src/main/java/com/c2kernel/graph/view/PropertyTable.java40
-rw-r--r--src/main/java/com/c2kernel/graph/view/PropertyTableModel.java135
-rw-r--r--src/main/java/com/c2kernel/graph/view/SelectedVertexPanel.java27
-rw-r--r--src/main/java/com/c2kernel/graph/view/VertexPropertyPanel.java259
-rw-r--r--src/main/java/com/c2kernel/graph/view/VertexRenderer.java11
54 files changed, 4758 insertions, 0 deletions
diff --git a/src/main/java/com/c2kernel/graph/controller/AutoScrollController.java b/src/main/java/com/c2kernel/graph/controller/AutoScrollController.java
new file mode 100644
index 0000000..aa04609
--- /dev/null
+++ b/src/main/java/com/c2kernel/graph/controller/AutoScrollController.java
@@ -0,0 +1,41 @@
+package com.c2kernel.graph.controller;
+
+import java.awt.Point;
+import java.awt.Rectangle;
+import java.awt.event.MouseEvent;
+import java.awt.event.MouseMotionListener;
+
+import com.c2kernel.graph.view.GraphPanel;
+
+
+public class AutoScrollController implements MouseMotionListener
+{
+ private GraphPanel mGraphPanel = null;
+
+
+ public void setGraphPanel(GraphPanel graphPanel)
+ {
+ mGraphPanel = graphPanel;
+ mGraphPanel.addMouseMotionListener(this);
+ }
+
+
+ @Override
+ public void mouseDragged(MouseEvent me)
+ {
+ Point mousePoint = null;
+
+
+ if(mGraphPanel != null)
+ {
+ mousePoint = me.getPoint();
+ mGraphPanel.scrollRectToVisible(new Rectangle(mousePoint.x, mousePoint.y, 1, 1));
+ }
+ }
+
+
+ @Override
+ public void mouseMoved(MouseEvent me)
+ {
+ }
+}
diff --git a/src/main/java/com/c2kernel/graph/controller/DeletionController.java b/src/main/java/com/c2kernel/graph/controller/DeletionController.java
new file mode 100644
index 0000000..44ea990
--- /dev/null
+++ b/src/main/java/com/c2kernel/graph/controller/DeletionController.java
@@ -0,0 +1,92 @@
+package com.c2kernel.graph.controller;
+
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.event.KeyAdapter;
+import java.awt.event.KeyEvent;
+import java.util.Observable;
+import java.util.Observer;
+
+import javax.swing.JButton;
+
+import com.c2kernel.graph.event.SelectionChangedEvent;
+import com.c2kernel.graph.model.DirectedEdge;
+import com.c2kernel.graph.model.GraphModelManager;
+import com.c2kernel.graph.model.Vertex;
+
+
+// The deletion controller is responsible for deleting the present
+// selection within the graph.
+//
+// The controller listens to:
+// * The graph model to determine if there is a selection
+// * The delete button
+// * The graph panel for the typing of the delete key
+//
+// The controller modifies:
+// * The graph model to delete the current selection
+// * The delete button to enable it only when there is a selection
+public class DeletionController extends KeyAdapter implements Observer, ActionListener
+{
+ private GraphModelManager mGraphModelManager = null;
+ private JButton mDeleteButton = null;
+
+
+ public void setGraphModelManager(GraphModelManager graphModelManager)
+ {
+ mGraphModelManager = graphModelManager;
+ mGraphModelManager.addObserver(this);
+ }
+
+
+ public void setDeleteButton(JButton deleteButton)
+ {
+ mDeleteButton = deleteButton;
+ mDeleteButton.addActionListener(this);
+ }
+
+
+ // Invoked by the graph model
+ @Override
+ public void update(Observable o, Object arg)
+ {
+ SelectionChangedEvent event = null;
+ DirectedEdge selectedEdge = null;
+ Vertex[] selectedVertices = null;
+
+
+ // If the selected edge has changed
+ if(arg instanceof SelectionChangedEvent && mDeleteButton != null && mGraphModelManager.isEditable())
+ {
+ // Enable the button if a single edge or single vertex is selected
+ event = (SelectionChangedEvent)arg;
+
+ selectedEdge = event.mSelection.mEdge;
+ selectedVertices = event.mSelection.mVertices;
+
+ mDeleteButton.setEnabled((selectedEdge != null) || (selectedVertices != null));
+ }
+ }
+
+
+ // Invoked by the graph panel
+ @Override
+ public void keyPressed(KeyEvent e)
+ {
+ if(e.getKeyCode() == KeyEvent.VK_DELETE && mGraphModelManager.isEditable())
+ {
+ mGraphModelManager.getModel().deleteSelection();
+ }
+ }
+
+
+ // Invoked by the delete button
+ @Override
+ public void actionPerformed(ActionEvent ae)
+ {
+ if(mGraphModelManager != null && mGraphModelManager.isEditable())
+ {
+ mGraphModelManager.getModel().deleteSelection();
+ }
+ }
+}
diff --git a/src/main/java/com/c2kernel/graph/controller/EdgeConstructionController.java b/src/main/java/com/c2kernel/graph/controller/EdgeConstructionController.java
new file mode 100644
index 0000000..00ea45b
--- /dev/null
+++ b/src/main/java/com/c2kernel/graph/controller/EdgeConstructionController.java
@@ -0,0 +1,253 @@
+package com.c2kernel.graph.controller;
+
+import java.awt.Point;
+import java.awt.event.MouseAdapter;
+import java.awt.event.MouseEvent;
+
+import com.c2kernel.graph.model.GraphModelManager;
+import com.c2kernel.graph.model.GraphPoint;
+import com.c2kernel.graph.model.Vertex;
+import com.c2kernel.graph.view.EditorModeListener;
+import com.c2kernel.graph.view.EditorToolBar;
+
+
+public class EdgeConstructionController extends MouseAdapter implements EditorModeListener
+{
+ private GraphModelManager mGraphModelManager = null;
+ private EditorToolBar mEditorToolBar = null;
+
+
+ /**********/
+ /* States */
+ /**********/
+ private final Integer kOtherMode = new Integer(0);
+ private final Integer kWaitOrigin = new Integer(1);
+ private final Integer kWaitTerminus = new Integer(2);
+
+
+ /**********/
+ /* Events */
+ /**********/
+ private final int kEdgeEntered = 0;
+ private final int kOtherEntered = 1;
+ private final int kPressOnVertex = 2;
+ private final int kDrag = 3;
+ private final int kReleaseOnTerminus = 4;
+ private final int kReleaseOnNothing = 5;
+
+
+ /***********/
+ /* Actions */
+ /***********/
+
+ private interface Action
+ {
+ public void doIt(Object data);
+ }
+
+
+ private Action mSetOriginVertex = new Action()
+ {
+ @Override
+ public void doIt(Object data)
+ {
+ if(mGraphModelManager != null)
+ {
+ mGraphModelManager.getModel().setNewEdgeOriginVertex((Vertex)data);
+ }
+ }
+ };
+
+
+ private Action mSetEndPoint = new Action()
+ {
+ @Override
+ public void doIt(Object data)
+ {
+ if(mGraphModelManager != null)
+ {
+ mGraphModelManager.getModel().setNewEdgeEndPoint((Point)data);
+ }
+ }
+ };
+
+
+ private Action mClearEdge = new Action()
+ {
+ @Override
+ public void doIt(Object data)
+ {
+ if(mGraphModelManager != null)
+ {
+ mGraphModelManager.getModel().setNewEdgeOriginVertex(null);
+ mGraphModelManager.getModel().setNewEdgeEndPoint(null);
+ }
+ }
+ };
+
+
+ private Action mCreateEdge = new Action()
+ {
+ @Override
+ public void doIt(Object data)
+ {
+ if((mGraphModelManager != null) && (mEditorToolBar != null) && mGraphModelManager.isEditable())
+ {
+ mGraphModelManager.getModel().createDirectedEdge
+ (
+ mGraphModelManager.getModel().getNewEdgeOriginVertex(),
+ (Vertex)data,
+ mEditorToolBar.getSelectedEdgeType()
+ );
+ mGraphModelManager.getModel().setNewEdgeOriginVertex(null);
+ mGraphModelManager.getModel().setNewEdgeEndPoint(null);
+ }
+ }
+ };
+
+
+ /***********************************/
+ /* Finite State Transition Network */
+ /***********************************/
+
+ private Object[][][] mFSTN =
+ {// OtherMode WaitOrigin WaitTerminus
+ /* EdgeEntered */ {{null, kWaitOrigin}, null , null },
+ /* OtherEntered */ { null , {null , kOtherMode} , null },
+ /* PressOnVertex */ { null , {mSetOriginVertex, kWaitTerminus}, null },
+ /* Drag */ { null , null , {mSetEndPoint, null} },
+ /* ReleaseOnTerminus */ { null , null , {mCreateEdge , kWaitOrigin}},
+ /* ReleaseOnNothing */ { null , null , {mClearEdge , kWaitOrigin}}
+ };
+
+
+ /*****************/
+ /* Current state */
+ /*****************/
+
+ private Integer mState = kOtherMode;
+
+
+ /**************************/
+ /* Event processing logic */
+ /**************************/
+
+ private void processEvent(int event, Object data)
+ {
+ Object[] transition = mFSTN[event][mState.intValue()];
+ Action action = null;
+ Integer nextState = null;
+
+ if(transition != null)
+ {
+ action = (Action)transition[0];
+ nextState = (Integer)transition[1];
+
+ if(action != null)
+ {
+ action.doIt(data);
+ }
+
+ if(nextState != null)
+ {
+ mState = nextState;
+ }
+ }
+ }
+
+
+ /********************/
+ /* Public interface */
+ /********************/
+
+ public void setGraphModelManager(GraphModelManager graphModelManager)
+ {
+ mGraphModelManager = graphModelManager;
+ }
+
+
+ public void setEditorToolBar(EditorToolBar editorToolBar)
+ {
+ mEditorToolBar = editorToolBar;
+ mEditorToolBar.addEditorModeListener(this);
+ }
+
+
+ @Override
+ public void editorModeChanged(String idOfNewMode)
+ {
+ if(idOfNewMode.equals("Edge"))
+ {
+ processEvent(kEdgeEntered, null);
+ }
+ else
+ {
+ processEvent(kOtherEntered, null);
+ }
+ }
+
+
+ @Override
+ public void mousePressed(MouseEvent me)
+ {
+ Vertex vertex = null;
+ Point mousePoint = null;
+
+ if(mGraphModelManager != null)
+ {
+ // Determine if there is a vertex under the mouse cursor
+ mousePoint = me.getPoint();
+ vertex = mGraphModelManager.getModel().getVertex(new GraphPoint(mousePoint.x, mousePoint.y));
+
+ // If the mouse has been pressed on a vertex
+ if(vertex != null)
+ {
+ processEvent(kPressOnVertex, vertex);
+ }
+ }
+ }
+
+
+ @Override
+ public void mouseReleased(MouseEvent me)
+ {
+ Vertex vertex = null;
+ Point mousePoint = null;
+
+ if(mGraphModelManager != null)
+ {
+ // Determine if there is a vertex under the mouse cursor
+ mousePoint = me.getPoint();
+ vertex = mGraphModelManager.getModel().getVertex(new GraphPoint(mousePoint.x, mousePoint.y));
+
+ // If the mouse has been released on a vertex which is not the origin vertex
+ if((vertex != null) && (vertex != mGraphModelManager.getModel().getNewEdgeOriginVertex()))
+ {
+ processEvent(kReleaseOnTerminus, vertex);
+ }
+ else
+ {
+ processEvent(kReleaseOnNothing, null);
+ }
+ }
+ }
+
+
+ @Override
+ public void mouseExited(MouseEvent me)
+ {
+ }
+
+
+ @Override
+ public void mouseDragged(MouseEvent me)
+ {
+ processEvent(kDrag, me.getPoint());
+ }
+
+
+ @Override
+ public void mouseMoved(MouseEvent me)
+ {
+ }
+}
diff --git a/src/main/java/com/c2kernel/graph/controller/MultiSelectionDragController.java b/src/main/java/com/c2kernel/graph/controller/MultiSelectionDragController.java
new file mode 100644
index 0000000..eda5c1c
--- /dev/null
+++ b/src/main/java/com/c2kernel/graph/controller/MultiSelectionDragController.java
@@ -0,0 +1,571 @@
+package com.c2kernel.graph.controller;
+
+import java.awt.Point;
+import java.awt.event.InputEvent;
+import java.awt.event.KeyEvent;
+import java.awt.event.KeyListener;
+import java.awt.event.MouseAdapter;
+import java.awt.event.MouseEvent;
+
+import com.c2kernel.graph.model.DirectedEdge;
+import com.c2kernel.graph.model.ElasticBand;
+import com.c2kernel.graph.model.GraphModelManager;
+import com.c2kernel.graph.model.GraphPoint;
+import com.c2kernel.graph.model.GraphableVertex;
+import com.c2kernel.graph.model.Selection;
+import com.c2kernel.graph.model.Vertex;
+import com.c2kernel.graph.view.EditorModeListener;
+
+
+public class MultiSelectionDragController
+extends MouseAdapter
+implements EditorModeListener, KeyListener
+{
+ private class ResizeInf
+ {
+ public int mMousePressedX = 0;
+ public int mMousePressedY = 0;
+ public Vertex mSelectedVertex = null;
+ public GraphPoint[] mOldOutline = null;
+ public int mCentreX = 0;
+ public int mCentreY = 0;
+ public int mOldHeight = 0;
+ public int mOldWidth = 0;
+ }
+ private ResizeInf mResizeInf = new ResizeInf();
+
+ private class DispForSelection
+ {
+ public int mXDisp = 0;
+ public int mYDisp = 0;
+ }
+ private DispForSelection mDispForSelection = null;
+
+ private class VertexAndDisp
+ {
+ public Vertex mVertex = null;
+ public int mXDisp = 0;
+ public int mYDisp = 0;
+ }
+
+ protected GraphModelManager mGraphModelManager = null;
+
+
+ /**********/
+ /* States */
+ /**********/
+ protected final Integer kOtherMode = new Integer(0);
+ protected final Integer kWaiting = new Integer(1);
+ protected final Integer kResizing = new Integer(2);
+ protected final Integer kDraggingSelection = new Integer(3);
+ protected final Integer kStretching = new Integer(4);
+
+
+ /**********/
+ /* Events */
+ /**********/
+ protected final int kSelectEntered = 0;
+ protected final int kOtherEntered = 1;
+ protected final int kPressOnEdge = 2;
+ protected final int kPressOnVertex = 3;
+ protected final int kPressOnSelection = 4;
+ protected final int kPressOnResizePad = 5;
+ protected final int kCTRLPressOnVertex = 6;
+ protected final int kCTRL_A = 7;
+ protected final int kPressOnNothing = 8;
+ protected final int kDrag = 9;
+ protected final int kRelease = 10;
+ protected final int kZoomIn = 11;
+
+ /***********/
+ /* Actions */
+ /***********/
+
+ protected interface Action
+ {
+ public void doIt(Object data);
+ }
+
+
+ protected Action mStoreResizeInf = new Action()
+ {
+ @Override
+ public void doIt(Object data)
+ {
+ Point mousePoint = (Point)data;
+ GraphPoint centre = null;
+
+ mResizeInf.mMousePressedX = mousePoint.x;
+ mResizeInf.mMousePressedY = mousePoint.y;
+ mResizeInf.mSelectedVertex = mGraphModelManager.getModel().getSelection().mVertices[0];
+ mResizeInf.mOldOutline = mResizeInf.mSelectedVertex.getOutlinePoints();
+ centre = mResizeInf.mSelectedVertex.getCentrePoint();
+ mResizeInf.mCentreX = centre.x;
+ mResizeInf.mCentreY = centre.y;
+ mResizeInf.mOldHeight = mResizeInf.mSelectedVertex.getHeight();
+ mResizeInf.mOldWidth = mResizeInf.mSelectedVertex.getWidth();
+ }
+ };
+
+
+ protected Action mResizeVertex = new Action()
+ {
+ @Override
+ public void doIt(Object data)
+ {
+ Point mousePoint = (Point)data;
+ int resizeX = 0;
+ int resizeY = 0;
+
+
+ // Calculate how much the old outline should be resized
+ resizeX = mousePoint.x - mResizeInf.mMousePressedX;
+ resizeY = mousePoint.y - mResizeInf.mMousePressedY;
+
+ // Clip the resize so that outline does not get any
+ // smaller than 10 x 10 pixels
+ if(resizeX < -mResizeInf.mOldWidth/2 + 10)
+ {
+ resizeX = -mResizeInf.mOldWidth/2 + 10;
+ }
+
+ if(resizeY < -mResizeInf.mOldHeight/2 + 10)
+ {
+ resizeY = -mResizeInf.mOldHeight/2 + 10;
+ }
+
+ if (mGraphModelManager.isEditable()) {
+ mResizeInf.mSelectedVertex.setOutlinePoints(newOutline(resizeX, resizeY));
+ mGraphModelManager.forceNotify();
+ }
+ }
+
+
+ private GraphPoint[] newOutline(int resizeX, int resizeY)
+ {
+ GraphPoint[] newOutline = new GraphPoint[mResizeInf.mOldOutline.length];
+ int x = 0;
+ int y = 0;
+ int i = 0;
+
+
+ for(i=0; i<newOutline.length; i++)
+ {
+ if(mResizeInf.mOldOutline[i].x > mResizeInf.mCentreX)
+ {
+ x = mResizeInf.mOldOutline[i].x + resizeX;
+ }
+ else if(mResizeInf.mOldOutline[i].x < mResizeInf.mCentreX)
+ {
+ x = mResizeInf.mOldOutline[i].x - resizeX;
+ }
+ else
+ {
+ x = mResizeInf.mOldOutline[i].x;
+ }
+
+ if(mResizeInf.mOldOutline[i].y > mResizeInf.mCentreY)
+ {
+ y = mResizeInf.mOldOutline[i].y + resizeY;
+ }
+ else if(mResizeInf.mOldOutline[i].y < mResizeInf.mCentreY)
+ {
+ y = mResizeInf.mOldOutline[i].y - resizeY;
+ }
+ else
+ {
+ y = mResizeInf.mOldOutline[i].y;
+ }
+
+ newOutline[i] = new GraphPoint(x, y);
+ }
+
+ return newOutline;
+ }
+ };
+
+
+ protected Action mSelectEdge = new Action()
+ {
+ @Override
+ public void doIt(Object data)
+ {
+ Selection selection = new Selection((DirectedEdge)data, null, 0, 0, 0, 0);
+
+ mGraphModelManager.getModel().setSelection(selection);
+ }
+ };
+
+
+ protected Action mSelectVertexAndStoreDisp = new Action()
+ {
+ @Override
+ public void doIt(Object data)
+ {
+ VertexAndDisp vertexAndDisp = (VertexAndDisp)data;
+ GraphPoint centrePoint = vertexAndDisp.mVertex.getCentrePoint();
+ Selection selection = new Selection(null,
+ new Vertex[] {vertexAndDisp.mVertex},
+ centrePoint.x,
+ centrePoint.y,
+ centrePoint.x,
+ centrePoint.y);
+
+ mGraphModelManager.getModel().setSelection(selection);
+ mDispForSelection = new DispForSelection();
+ mDispForSelection.mXDisp = vertexAndDisp.mXDisp;
+ mDispForSelection.mYDisp = vertexAndDisp.mYDisp;
+ }
+ };
+
+
+ protected Action mStoreDisp = new Action()
+ {
+ @Override
+ public void doIt(Object data)
+ {
+ mDispForSelection = (DispForSelection)data;
+ }
+ };
+
+
+ protected Action mToggleVertex = new Action()
+ {
+ @Override
+ public void doIt(Object data)
+ {
+ Vertex vertex = (Vertex)data;
+
+ if(mGraphModelManager.getModel().inSelection(vertex))
+ {
+ mGraphModelManager.getModel().removeFromSelection(vertex);
+ }
+ else
+ {
+ mGraphModelManager.getModel().addToSelection(vertex);
+ }
+ }
+ };
+
+
+ protected Action mSelectAll = new Action()
+ {
+ @Override
+ public void doIt(Object data)
+ {
+ mGraphModelManager.getModel().selectAll();
+ }
+ };
+
+
+ protected Action mCreateBand = new Action()
+ {
+ @Override
+ public void doIt(Object data)
+ {
+ Point fixedCorner = (Point)data;
+
+ mGraphModelManager.getModel().setElasticBand(new ElasticBand(fixedCorner, fixedCorner));
+ }
+ };
+
+
+ protected Action mMoveSelection = new Action()
+ {
+ @Override
+ public void doIt(Object data)
+ {
+ Point mousePoint = (Point)data;
+ int topLeftX = mousePoint.x - mDispForSelection.mXDisp;
+ int topLeftY = mousePoint.y - mDispForSelection.mYDisp;
+ if (mGraphModelManager.isEditable()) {
+ mGraphModelManager.getModel().moveAbsoluteSelection(topLeftX, topLeftY);
+ }
+ }
+ };
+
+
+ protected Action mResizeBand = new Action()
+ {
+ @Override
+ public void doIt(Object data)
+ {
+ mGraphModelManager.getModel().resizeElasticBand((Point)data);
+ }
+ };
+
+
+ protected Action mSelectContents = new Action()
+ {
+ @Override
+ public void doIt(Object data)
+ {
+ mGraphModelManager.getModel().selectContentsOfElasticBand();
+ }
+ };
+
+ protected Action mZoomIn = new Action()
+ {
+ @Override
+ public void doIt(Object data) // data is the clicked vertex
+ {
+ // Need to get child graph model out of the vertex before we can zoom in
+ if (data instanceof Vertex) {
+ Vertex zoomTo = (Vertex)data;
+ if (((GraphableVertex)zoomTo).getIsComposite()) mGraphModelManager.zoomIn(zoomTo);
+ }
+ }
+ };
+
+ /***********************************/
+ /* Finite State Transition Network */
+ /***********************************/
+
+ protected Object[][][] mFSTN =
+ {// OtherMode Waiting Resizing DraggingSelection Stretching
+ /* SelectEntered */ {{null, kWaiting}, null , null , null , null },
+ /* OtherEntered */ { null , {null , kOtherMode }, null , null , null },
+ /* PressOnEdge */ { null , {mSelectEdge , null }, null , null , null },
+ /* PressOnVertex */ { null , {mSelectVertexAndStoreDisp, kDraggingSelection}, null , null , null },
+ /* PressOnSelection */ { null , {mStoreDisp , kDraggingSelection}, null , null , null },
+ /* PressOnResizePad */ { null , {mStoreResizeInf , kResizing }, null , null , null },
+ /* CTRLPressOnVertex */ { null , {mToggleVertex , null }, null , null , null },
+ /* CTRL_A */ { null , {mSelectAll , null }, null , null , null },
+ /* PressOnNothing */ { null , {mCreateBand , kStretching }, null , null , null },
+ /* Drag */ { null , null , {mResizeVertex, null }, {mMoveSelection, null }, {mResizeBand , null }},
+ /* Release */ { null , null , {null , kWaiting}, {null , kWaiting}, {mSelectContents, kWaiting}},
+ /* Double Click */ { null , {mZoomIn , null }, null , null , null },
+ };
+
+
+ /*****************/
+ /* Current state */
+ /*****************/
+
+ private Integer mState = kWaiting;
+
+
+ /**************************/
+ /* Event processing logic */
+ /**************************/
+
+ protected void processEvent(int event, Object data)
+ {
+ Object[] transition = mFSTN[event][mState.intValue()];
+ Action action = null;
+ Integer nextState = null;
+
+ if(transition != null)
+ {
+ action = (Action)transition[0];
+ nextState = (Integer)transition[1];
+
+ if(action != null)
+ {
+ action.doIt(data);
+ }
+
+ if(nextState != null)
+ {
+ mState = nextState;
+ }
+ }
+ }
+
+
+ /********************/
+ /* Public interface */
+ /********************/
+
+ public void setGraphModelManager(GraphModelManager graphModelManager)
+ {
+ mGraphModelManager = graphModelManager;
+ }
+
+
+ @Override
+ public void editorModeChanged(String idOfNewMode)
+ {
+ if(idOfNewMode.equals("Select"))
+ {
+ processEvent(kSelectEntered, null);
+ }
+ else
+ {
+ processEvent(kOtherEntered, null);
+ }
+ }
+
+
+ @Override
+ public void mousePressed(MouseEvent me)
+ {
+ int modifiers = me.getModifiers();
+
+ if(mGraphModelManager != null)
+ {
+ if((modifiers & InputEvent.CTRL_MASK) == 0)
+ {
+ mousePressedWithoutCTRL(me.getPoint());
+ }
+ else
+ {
+ mousePressedWithCTRL(me.getPoint());
+ }
+ }
+ }
+
+ @Override
+ public void mouseClicked(MouseEvent me)
+ {
+ if (me.getClickCount() == 2) { // want double click
+ Point clickedSpot = me.getPoint();
+ GraphPoint mouseGPoint = new GraphPoint(clickedSpot.x, clickedSpot.y);
+ Vertex clicked = mGraphModelManager.getModel().getVertex(mouseGPoint);
+ if (clicked != null)
+ processEvent(kZoomIn, clicked);
+ }
+ }
+
+ private void mousePressedWithoutCTRL(Point mousePoint)
+ {
+ GraphPoint mouseGPoint = new GraphPoint(mousePoint.x, mousePoint.y);
+ DirectedEdge edge = mGraphModelManager.getModel().getEdge(mouseGPoint);
+ Vertex vertex = mGraphModelManager.getModel().getVertex(mouseGPoint);
+ GraphPoint vertexCentrePoint = null;
+ VertexAndDisp vertexAndDisp = null;
+ Selection selection = null;
+ DispForSelection dispForSelection = null;
+
+
+ // In order of priority:
+ // 1. Click on resize pad
+ // 2. Click on vertex
+ // 3. Click on edge
+ if(onResizePad(mouseGPoint))
+ {
+ processEvent(kPressOnResizePad, mousePoint);
+ }
+ else if(vertex != null)
+ {
+ if(mGraphModelManager.getModel().inSelection(vertex))
+ {
+ selection = mGraphModelManager.getModel().getSelection();
+ dispForSelection = new DispForSelection();
+ dispForSelection.mXDisp = mousePoint.x - selection.mTopLeftX;
+ dispForSelection.mYDisp = mousePoint.y - selection.mTopLeftY;
+
+ processEvent(kPressOnSelection, dispForSelection);
+ }
+ else
+ {
+ vertexCentrePoint = vertex.getCentrePoint();
+
+ vertexAndDisp = new VertexAndDisp();
+ vertexAndDisp.mVertex = vertex;
+ vertexAndDisp.mXDisp = mousePoint.x - vertexCentrePoint.x;
+ vertexAndDisp.mYDisp = mousePoint.y - vertexCentrePoint.y;
+
+ processEvent(kPressOnVertex, vertexAndDisp);
+ }
+ }
+ // vertex == null
+ else
+ {
+ if(edge == null)
+ {
+ processEvent(kPressOnNothing, mousePoint);
+ }
+ else
+ {
+ processEvent(kPressOnEdge, edge);
+ }
+ }
+ }
+
+
+ private boolean onResizePad(GraphPoint mouseGPoint)
+ {
+ Selection selection = mGraphModelManager.getModel().getSelection();
+ GraphPoint vertexCentre = null;
+ int bottomRightX = 0;
+ int bottomRightY = 0;
+
+
+ if(selection.mVertices == null) return false;
+
+ if(selection.mVertices.length == 1)
+ {
+ vertexCentre = selection.mVertices[0].getCentrePoint();
+ if (vertexCentre == null) return false;
+ bottomRightX = vertexCentre.x + selection.mVertices[0].getWidth()/2;
+ bottomRightY = vertexCentre.y + selection.mVertices[0].getHeight()/2;
+
+ return
+ (
+ (mouseGPoint.x > bottomRightX) &&
+ (mouseGPoint.x < bottomRightX + 10) &&
+ (mouseGPoint.y > bottomRightY) &&
+ (mouseGPoint.y < bottomRightY + 10)
+ );
+ }
+ else
+ {
+ return false;
+ }
+ }
+
+
+ private void mousePressedWithCTRL(Point mousePoint)
+ {
+ Vertex vertex = mGraphModelManager.getModel().getVertex(new GraphPoint(mousePoint.x, mousePoint.y));
+
+ if(vertex != null)
+ {
+ processEvent(kCTRLPressOnVertex, vertex);
+ }
+ }
+
+
+ @Override
+ public void mouseReleased(MouseEvent me)
+ {
+ processEvent(kRelease, null);
+ }
+
+
+ @Override
+ public void mouseMoved(MouseEvent me)
+ {
+ }
+
+
+ @Override
+ public void mouseDragged(MouseEvent e)
+ {
+ processEvent(kDrag, e.getPoint());
+ }
+
+
+ @Override
+ public void keyPressed(KeyEvent e)
+ {
+ if((e.getKeyCode() == KeyEvent.VK_A) && e.isControlDown())
+ {
+ processEvent(kCTRL_A, null);
+ }
+ }
+
+
+ @Override
+ public void keyReleased(KeyEvent e)
+ {
+ }
+
+
+ @Override
+ public void keyTyped(KeyEvent e)
+ {
+ }
+
+}
diff --git a/src/main/java/com/c2kernel/graph/controller/StartVertexController.java b/src/main/java/com/c2kernel/graph/controller/StartVertexController.java
new file mode 100644
index 0000000..3984cb7
--- /dev/null
+++ b/src/main/java/com/c2kernel/graph/controller/StartVertexController.java
@@ -0,0 +1,79 @@
+package com.c2kernel.graph.controller;
+
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.util.Observable;
+import java.util.Observer;
+
+import javax.swing.JButton;
+
+import com.c2kernel.graph.event.SelectionChangedEvent;
+import com.c2kernel.graph.model.GraphModelManager;
+import com.c2kernel.graph.model.Vertex;
+
+
+// The start vertex controller is responsible for selecting
+// the vertex at the start of the graph.
+//
+// The controller listens to:
+// * The graph model to determine if there is a single
+// vertex selected
+// * The start vertex button
+//
+// The controller modifies:
+// * The graph model to select the start vertex
+// * The start button to enable it only when there is a
+// single vertex selected
+public class StartVertexController implements Observer, ActionListener
+{
+ private GraphModelManager mGraphModelManager = null;
+ private JButton mStartButton = null;
+
+
+ public void setGraphModelManager(GraphModelManager graphModelManager)
+ {
+ mGraphModelManager = graphModelManager;
+ mGraphModelManager.addObserver(this);
+ }
+
+
+ public void setStartButton(JButton startButton)
+ {
+ mStartButton = startButton;
+ mStartButton.addActionListener(this);
+ }
+
+
+ @Override
+ public void update(Observable o, Object arg)
+ {
+ SelectionChangedEvent event = null;
+ Vertex[] selectedVertices = null;
+
+ // If the selected vertex has changed
+ if(arg instanceof SelectionChangedEvent && mStartButton != null)
+ {
+ event = (SelectionChangedEvent)arg;
+ selectedVertices = event.mSelection.mVertices;
+
+ if(selectedVertices == null)
+ {
+ mStartButton.setEnabled(false);
+ }
+ else if (mGraphModelManager.isEditable())
+ {
+ mStartButton.setEnabled(selectedVertices.length == 1);
+ }
+ }
+ }
+
+
+ @Override
+ public void actionPerformed(ActionEvent ae)
+ {
+ if(mGraphModelManager != null)
+ {
+ mGraphModelManager.getModel().setSelectedVertexToBeStart();
+ }
+ }
+}
diff --git a/src/main/java/com/c2kernel/graph/controller/VertexConstructionController.java b/src/main/java/com/c2kernel/graph/controller/VertexConstructionController.java
new file mode 100644
index 0000000..1eb91f6
--- /dev/null
+++ b/src/main/java/com/c2kernel/graph/controller/VertexConstructionController.java
@@ -0,0 +1,47 @@
+package com.c2kernel.graph.controller;
+
+import java.awt.event.MouseAdapter;
+import java.awt.event.MouseEvent;
+
+import com.c2kernel.graph.model.GraphModelManager;
+import com.c2kernel.graph.view.EditorModeListener;
+import com.c2kernel.graph.view.EditorToolBar;
+
+
+public class VertexConstructionController extends MouseAdapter implements EditorModeListener
+{
+ private GraphModelManager mGraphModelManager = null;
+ private EditorToolBar mEditorToolBar = null;
+ private boolean mCreatingVertices = false;
+
+
+ public void setGraphModelManager(GraphModelManager graphModelManager)
+ {
+ mGraphModelManager = graphModelManager;
+ }
+
+
+ public void setEditorToolBar(EditorToolBar editorToolBar)
+ {
+ mEditorToolBar = editorToolBar;
+ mEditorToolBar.addEditorModeListener(this);
+ }
+
+
+ @Override
+ public void editorModeChanged(String idOfNewMode)
+ {
+ mCreatingVertices = idOfNewMode.equals("Vertex");
+ }
+
+
+ @Override
+ public void mouseClicked(MouseEvent me)
+ {
+ if(mCreatingVertices && (mGraphModelManager != null) && (mEditorToolBar != null) && mGraphModelManager.isEditable())
+ {
+ mGraphModelManager.getModel().createVertex(me.getPoint(), mEditorToolBar.getSelectedVertexType());
+ mEditorToolBar.enterSelectMode();
+ }
+ }
+}
diff --git a/src/main/java/com/c2kernel/graph/event/ClearedEvent.java b/src/main/java/com/c2kernel/graph/event/ClearedEvent.java
new file mode 100644
index 0000000..128e671
--- /dev/null
+++ b/src/main/java/com/c2kernel/graph/event/ClearedEvent.java
@@ -0,0 +1,6 @@
+package com.c2kernel.graph.event;
+
+
+public class ClearedEvent extends GraphModelEvent
+{
+}
diff --git a/src/main/java/com/c2kernel/graph/event/EdgeRemovedEvent.java b/src/main/java/com/c2kernel/graph/event/EdgeRemovedEvent.java
new file mode 100644
index 0000000..d895132
--- /dev/null
+++ b/src/main/java/com/c2kernel/graph/event/EdgeRemovedEvent.java
@@ -0,0 +1,6 @@
+package com.c2kernel.graph.event;
+
+
+public class EdgeRemovedEvent extends GraphModelEvent
+{
+}
diff --git a/src/main/java/com/c2kernel/graph/event/EdgesChangedEvent.java b/src/main/java/com/c2kernel/graph/event/EdgesChangedEvent.java
new file mode 100644
index 0000000..7835836
--- /dev/null
+++ b/src/main/java/com/c2kernel/graph/event/EdgesChangedEvent.java
@@ -0,0 +1,6 @@
+package com.c2kernel.graph.event;
+
+
+public class EdgesChangedEvent extends GraphModelEvent
+{
+}
diff --git a/src/main/java/com/c2kernel/graph/event/ElasticBandResizedEvent.java b/src/main/java/com/c2kernel/graph/event/ElasticBandResizedEvent.java
new file mode 100644
index 0000000..cb8ae3e
--- /dev/null
+++ b/src/main/java/com/c2kernel/graph/event/ElasticBandResizedEvent.java
@@ -0,0 +1,6 @@
+package com.c2kernel.graph.event;
+
+
+public class ElasticBandResizedEvent extends GraphModelEvent
+{
+}
diff --git a/src/main/java/com/c2kernel/graph/event/ElasticBandSetEvent.java b/src/main/java/com/c2kernel/graph/event/ElasticBandSetEvent.java
new file mode 100644
index 0000000..6211513
--- /dev/null
+++ b/src/main/java/com/c2kernel/graph/event/ElasticBandSetEvent.java
@@ -0,0 +1,6 @@
+package com.c2kernel.graph.event;
+
+
+public class ElasticBandSetEvent extends GraphModelEvent
+{
+}
diff --git a/src/main/java/com/c2kernel/graph/event/EntireModelChangedEvent.java b/src/main/java/com/c2kernel/graph/event/EntireModelChangedEvent.java
new file mode 100644
index 0000000..6e13e8b
--- /dev/null
+++ b/src/main/java/com/c2kernel/graph/event/EntireModelChangedEvent.java
@@ -0,0 +1,6 @@
+package com.c2kernel.graph.event;
+
+
+public class EntireModelChangedEvent extends GraphModelEvent
+{
+}
diff --git a/src/main/java/com/c2kernel/graph/event/ForcedNotifyEvent.java b/src/main/java/com/c2kernel/graph/event/ForcedNotifyEvent.java
new file mode 100644
index 0000000..d8dd646
--- /dev/null
+++ b/src/main/java/com/c2kernel/graph/event/ForcedNotifyEvent.java
@@ -0,0 +1,6 @@
+package com.c2kernel.graph.event;
+
+
+public class ForcedNotifyEvent extends GraphModelEvent
+{
+}
diff --git a/src/main/java/com/c2kernel/graph/event/GraphModelEvent.java b/src/main/java/com/c2kernel/graph/event/GraphModelEvent.java
new file mode 100644
index 0000000..95cd6fb
--- /dev/null
+++ b/src/main/java/com/c2kernel/graph/event/GraphModelEvent.java
@@ -0,0 +1,7 @@
+package com.c2kernel.graph.event;
+
+import java.io.Serializable;
+
+public abstract class GraphModelEvent implements Serializable
+{
+}
diff --git a/src/main/java/com/c2kernel/graph/event/GraphModelResizedEvent.java b/src/main/java/com/c2kernel/graph/event/GraphModelResizedEvent.java
new file mode 100644
index 0000000..20980c3
--- /dev/null
+++ b/src/main/java/com/c2kernel/graph/event/GraphModelResizedEvent.java
@@ -0,0 +1,6 @@
+package com.c2kernel.graph.event;
+
+
+public class GraphModelResizedEvent extends GraphModelEvent
+{
+}
diff --git a/src/main/java/com/c2kernel/graph/event/NewEdgeEndPointChangedEvent.java b/src/main/java/com/c2kernel/graph/event/NewEdgeEndPointChangedEvent.java
new file mode 100644
index 0000000..d1bb6f2
--- /dev/null
+++ b/src/main/java/com/c2kernel/graph/event/NewEdgeEndPointChangedEvent.java
@@ -0,0 +1,6 @@
+package com.c2kernel.graph.event;
+
+
+public class NewEdgeEndPointChangedEvent extends GraphModelEvent
+{
+}
diff --git a/src/main/java/com/c2kernel/graph/event/SelectionChangedEvent.java b/src/main/java/com/c2kernel/graph/event/SelectionChangedEvent.java
new file mode 100644
index 0000000..f95e6d3
--- /dev/null
+++ b/src/main/java/com/c2kernel/graph/event/SelectionChangedEvent.java
@@ -0,0 +1,9 @@
+package com.c2kernel.graph.event;
+
+import com.c2kernel.graph.model.Selection;
+
+
+public class SelectionChangedEvent extends GraphModelEvent
+{
+ public Selection mSelection = null;
+}
diff --git a/src/main/java/com/c2kernel/graph/event/SelectionMovedEvent.java b/src/main/java/com/c2kernel/graph/event/SelectionMovedEvent.java
new file mode 100644
index 0000000..2d892a9
--- /dev/null
+++ b/src/main/java/com/c2kernel/graph/event/SelectionMovedEvent.java
@@ -0,0 +1,7 @@
+package com.c2kernel.graph.event;
+
+
+
+public class SelectionMovedEvent extends GraphModelEvent
+{
+}
diff --git a/src/main/java/com/c2kernel/graph/event/StartVertexIdChangedEvent.java b/src/main/java/com/c2kernel/graph/event/StartVertexIdChangedEvent.java
new file mode 100644
index 0000000..f875626
--- /dev/null
+++ b/src/main/java/com/c2kernel/graph/event/StartVertexIdChangedEvent.java
@@ -0,0 +1,6 @@
+package com.c2kernel.graph.event;
+
+
+public class StartVertexIdChangedEvent extends GraphModelEvent
+{
+}
diff --git a/src/main/java/com/c2kernel/graph/event/VertexAddedEvent.java b/src/main/java/com/c2kernel/graph/event/VertexAddedEvent.java
new file mode 100644
index 0000000..353aacb
--- /dev/null
+++ b/src/main/java/com/c2kernel/graph/event/VertexAddedEvent.java
@@ -0,0 +1,6 @@
+package com.c2kernel.graph.event;
+
+
+public class VertexAddedEvent extends GraphModelEvent
+{
+}
diff --git a/src/main/java/com/c2kernel/graph/event/VertexCreatedEvent.java b/src/main/java/com/c2kernel/graph/event/VertexCreatedEvent.java
new file mode 100644
index 0000000..e72ca4a
--- /dev/null
+++ b/src/main/java/com/c2kernel/graph/event/VertexCreatedEvent.java
@@ -0,0 +1,6 @@
+package com.c2kernel.graph.event;
+
+
+public class VertexCreatedEvent extends GraphModelEvent
+{
+}
diff --git a/src/main/java/com/c2kernel/graph/event/VertexMovedEvent.java b/src/main/java/com/c2kernel/graph/event/VertexMovedEvent.java
new file mode 100644
index 0000000..807ca36
--- /dev/null
+++ b/src/main/java/com/c2kernel/graph/event/VertexMovedEvent.java
@@ -0,0 +1,6 @@
+package com.c2kernel.graph.event;
+
+
+public class VertexMovedEvent extends GraphModelEvent
+{
+}
diff --git a/src/main/java/com/c2kernel/graph/event/VertexRemovedEvent.java b/src/main/java/com/c2kernel/graph/event/VertexRemovedEvent.java
new file mode 100644
index 0000000..e24700d
--- /dev/null
+++ b/src/main/java/com/c2kernel/graph/event/VertexRemovedEvent.java
@@ -0,0 +1,6 @@
+package com.c2kernel.graph.event;
+
+
+public class VertexRemovedEvent extends GraphModelEvent
+{
+}
diff --git a/src/main/java/com/c2kernel/graph/event/VerticesChangedEvent.java b/src/main/java/com/c2kernel/graph/event/VerticesChangedEvent.java
new file mode 100644
index 0000000..5d83834
--- /dev/null
+++ b/src/main/java/com/c2kernel/graph/event/VerticesChangedEvent.java
@@ -0,0 +1,6 @@
+package com.c2kernel.graph.event;
+
+
+public class VerticesChangedEvent extends GraphModelEvent
+{
+}
diff --git a/src/main/java/com/c2kernel/graph/layout/DefaultGraphLayoutGenerator.java b/src/main/java/com/c2kernel/graph/layout/DefaultGraphLayoutGenerator.java
new file mode 100644
index 0000000..8ab91ef
--- /dev/null
+++ b/src/main/java/com/c2kernel/graph/layout/DefaultGraphLayoutGenerator.java
@@ -0,0 +1,116 @@
+package com.c2kernel.graph.layout;
+
+import java.util.Vector;
+
+import com.c2kernel.graph.model.DirectedEdge;
+import com.c2kernel.graph.model.GraphModel;
+import com.c2kernel.graph.model.GraphPoint;
+import com.c2kernel.graph.model.Vertex;
+import com.c2kernel.utils.Logger;
+
+public class DefaultGraphLayoutGenerator {
+ private static int mTopMargin = 100;
+ private static int mLeftMargin = 100;
+ private static int mHorzGap = 180;
+ private static int mVertGap = 100;
+
+ private DefaultGraphLayoutGenerator() {
+ }
+
+ public static void layoutGraph(GraphModel graphModel) {
+ Vertex start = graphModel.getStartVertex();
+ Vector<Vector<Vertex>> rowVector = new Vector<Vector<Vertex>>(10, 10);
+ int[] midPoints = null;
+ IntegerWrapper valueOfLargestMidPoint = new IntegerWrapper(0);
+ if (start == null) {
+ Logger.msg(1,"Error graph must have a starting vertex to be layed out");
+ return;
+ }
+ graphModel.clearTags(start);
+ visitVertex(graphModel, start, 0, rowVector, start);
+ midPoints = new int[rowVector.size()];
+ calculateRowMidPoints(rowVector, midPoints, valueOfLargestMidPoint);
+ fillInVertexLocations(graphModel, rowVector, valueOfLargestMidPoint, midPoints);
+ fillInEdgeLocations(graphModel);
+ graphModel.forceNotify();
+ }
+
+ private static void visitVertex(GraphModel graphModel, Vertex vertex, int rowIndex, Vector<Vector<Vertex>> rowVector, Object tag) {
+ int i = 0;
+ Vertex[] children = graphModel.getOutVertices(vertex);
+ vertex.setTag(tag);
+ addVertexToRow(vertex, rowIndex, rowVector);
+ for (i = 0; i < children.length; i++) {
+ if (!(children[i].hasTag(tag))) {
+ visitVertex(graphModel, children[i], rowIndex + 1, rowVector, tag);
+ }
+ }
+ }
+
+ private static void addVertexToRow(Vertex vertex, int rowIndex, Vector<Vector<Vertex>> rowVector) {
+ Vector<Vertex> rowsVertices = null;
+ // If there is no vector of vertices already created for this row,
+ // then create one
+ if (rowVector.size() == rowIndex) {
+ rowVector.add(new Vector<Vertex>(10, 10));
+ }
+ // Add the vertex to the row's vector of vertices
+ rowsVertices = rowVector.elementAt(rowIndex);
+ rowsVertices.add(vertex);
+ }
+
+ private static void calculateRowMidPoints(Vector<Vector<Vertex>> rowVector, int[] midPoints, IntegerWrapper valueOfLargestMidPoint) {
+ Vector<Vertex> rowsVertices = null;
+ int rowsWidth = 0;
+ int i = 0;
+ for (i = 0; i < midPoints.length; i++) {
+ rowsVertices = rowVector.elementAt(i);
+ rowsWidth = mHorzGap * (rowsVertices.size() - 1);
+ midPoints[i] = rowsWidth / 2;
+ if (midPoints[i] > valueOfLargestMidPoint.mValue) {
+ valueOfLargestMidPoint.mValue = midPoints[i];
+ }
+ }
+ }
+
+ private static void fillInVertexLocations(GraphModel graphModel, Vector<Vector<Vertex>> rowVector,
+ IntegerWrapper valueOfLargestMidPoint, int[] midPoints) {
+ Vector<Vertex> rowsVertices = null;
+ Vertex vertex = null;
+ int rowIndex = 0;
+ int column = 0;
+ int rowsLeftMargin = 0;
+ GraphPoint point = new GraphPoint(0, 0);
+ for (rowIndex = 0; rowIndex < rowVector.size(); rowIndex++) {
+ rowsVertices = rowVector.elementAt(rowIndex);
+ rowsLeftMargin = mLeftMargin + valueOfLargestMidPoint.mValue - midPoints[rowIndex];
+ for (column = 0; column < rowsVertices.size(); column++) {
+ vertex = rowsVertices.elementAt(column);
+ point.x = rowsLeftMargin + column * mHorzGap;
+ point.y = mTopMargin + rowIndex * mVertGap;
+ vertex.moveAbsolute(point);
+ graphModel.checkSize(vertex);
+ }
+ }
+ }
+
+ private static void fillInEdgeLocations(GraphModel graphModel) {
+ Vertex[] vertices = graphModel.getVertices();
+ GraphPoint centrePoint = null;
+ DirectedEdge[] inEdges = null;
+ DirectedEdge[] outEdges = null;
+ int i = 0;
+ int j = 0;
+ for (i = 0; i < vertices.length; i++) {
+ centrePoint = vertices[i].getCentrePoint();
+ inEdges = graphModel.getInEdges(vertices[i]);
+ outEdges = graphModel.getOutEdges(vertices[i]);
+ for (j = 0; j < inEdges.length; j++) {
+ inEdges[j].setTerminusPoint(centrePoint);
+ }
+ for (j = 0; j < outEdges.length; j++) {
+ outEdges[j].setOriginPoint(centrePoint);
+ }
+ }
+ }
+}
diff --git a/src/main/java/com/c2kernel/graph/layout/IntegerWrapper.java b/src/main/java/com/c2kernel/graph/layout/IntegerWrapper.java
new file mode 100644
index 0000000..aaee858
--- /dev/null
+++ b/src/main/java/com/c2kernel/graph/layout/IntegerWrapper.java
@@ -0,0 +1,13 @@
+package com.c2kernel.graph.layout;
+
+
+public class IntegerWrapper
+{
+ public int mValue = 0;
+
+
+ public IntegerWrapper(int value)
+ {
+ mValue = value;
+ }
+}
diff --git a/src/main/java/com/c2kernel/graph/model/DirectedEdge.java b/src/main/java/com/c2kernel/graph/model/DirectedEdge.java
new file mode 100644
index 0000000..830d70d
--- /dev/null
+++ b/src/main/java/com/c2kernel/graph/model/DirectedEdge.java
@@ -0,0 +1,99 @@
+package com.c2kernel.graph.model;
+
+import java.io.Serializable;
+
+
+
+public abstract class DirectedEdge implements Serializable
+{
+ // Persistent data
+ private int mId = -1;
+ private GraphPoint mOriginPoint = new GraphPoint(0, 0);
+ private GraphPoint mTerminusPoint = new GraphPoint(0, 0);
+ private int mOriginVertexId = -1;
+ private int mTerminusVertexId = -1;
+
+
+ public void setID(int id)
+ {
+ mId = id;
+ }
+
+
+ public int getID()
+ {
+ return mId;
+ }
+
+
+ public void setOriginPoint(GraphPoint p)
+ {
+ mOriginPoint = p;
+ }
+
+
+ public GraphPoint getOriginPoint()
+ {
+ return mOriginPoint;
+ }
+
+
+ public void setTerminusPoint(GraphPoint p)
+ {
+ mTerminusPoint = p;
+ }
+
+
+ public GraphPoint getTerminusPoint()
+ {
+ return mTerminusPoint;
+ }
+
+
+ public boolean containsPoint(GraphPoint p)
+ {
+ int midX = mOriginPoint.x + (mTerminusPoint.x - mOriginPoint.x)/2;
+ int midY = mOriginPoint.y + (mTerminusPoint.y - mOriginPoint.y)/2;
+ int minX = midX - 10;
+ int minY = midY - 10;
+ int maxX = midX + 10;
+ int maxY = midY + 10;
+
+ return (p.x >= minX) && (p.x <= maxX) && (p.y >= minY) && (p.y <= maxY);
+ }
+
+
+ public void setOriginVertexId(int id)
+ {
+ mOriginVertexId = id;
+ }
+
+
+ public int getOriginVertexId()
+ {
+ return mOriginVertexId;
+ }
+
+
+ public void setTerminusVertexId(int id)
+ {
+ mTerminusVertexId = id;
+ }
+
+
+ public int getTerminusVertexId()
+ {
+ return mTerminusVertexId;
+ }
+
+
+ public void setName(String name)
+ {
+ }
+
+
+ public String getName()
+ {
+ return null;
+ }
+}
diff --git a/src/main/java/com/c2kernel/graph/model/EdgeFactory.java b/src/main/java/com/c2kernel/graph/model/EdgeFactory.java
new file mode 100644
index 0000000..083f616
--- /dev/null
+++ b/src/main/java/com/c2kernel/graph/model/EdgeFactory.java
@@ -0,0 +1,14 @@
+package com.c2kernel.graph.model;
+
+
+
+public interface EdgeFactory
+{
+ public void create
+ (
+ GraphModelManager graphModelManager,
+ Vertex origin,
+ Vertex terminus,
+ TypeNameAndConstructionInfo typeNameAndConstructionInfo
+ );
+}
diff --git a/src/main/java/com/c2kernel/graph/model/ElasticBand.java b/src/main/java/com/c2kernel/graph/model/ElasticBand.java
new file mode 100644
index 0000000..38497ef
--- /dev/null
+++ b/src/main/java/com/c2kernel/graph/model/ElasticBand.java
@@ -0,0 +1,17 @@
+package com.c2kernel.graph.model;
+
+import java.awt.Point;
+
+
+public class ElasticBand
+{
+ public Point mFixedCorner = null;
+ public Point mMovingCorner = null;
+
+
+ public ElasticBand(Point fixedCorner, Point movingCorner)
+ {
+ mFixedCorner = fixedCorner;
+ mMovingCorner = movingCorner;
+ }
+}
diff --git a/src/main/java/com/c2kernel/graph/model/GraphModel.java b/src/main/java/com/c2kernel/graph/model/GraphModel.java
new file mode 100644
index 0000000..47f368d
--- /dev/null
+++ b/src/main/java/com/c2kernel/graph/model/GraphModel.java
@@ -0,0 +1,900 @@
+package com.c2kernel.graph.model;
+
+import java.awt.Point;
+import java.awt.Polygon;
+import java.io.Serializable;
+import java.util.Hashtable;
+import java.util.Vector;
+
+import com.c2kernel.graph.event.ClearedEvent;
+import com.c2kernel.graph.event.EdgeRemovedEvent;
+import com.c2kernel.graph.event.EdgesChangedEvent;
+import com.c2kernel.graph.event.ElasticBandResizedEvent;
+import com.c2kernel.graph.event.ElasticBandSetEvent;
+import com.c2kernel.graph.event.ForcedNotifyEvent;
+import com.c2kernel.graph.event.GraphModelEvent;
+import com.c2kernel.graph.event.GraphModelResizedEvent;
+import com.c2kernel.graph.event.NewEdgeEndPointChangedEvent;
+import com.c2kernel.graph.event.SelectionChangedEvent;
+import com.c2kernel.graph.event.SelectionMovedEvent;
+import com.c2kernel.graph.event.StartVertexIdChangedEvent;
+import com.c2kernel.graph.event.VertexAddedEvent;
+import com.c2kernel.graph.event.VertexCreatedEvent;
+import com.c2kernel.graph.event.VertexMovedEvent;
+import com.c2kernel.graph.event.VertexRemovedEvent;
+import com.c2kernel.graph.event.VerticesChangedEvent;
+import com.c2kernel.utils.Logger;
+
+public class GraphModel implements Serializable{
+ /* Persistant data */
+
+ private int mWidth = 0;
+ private int mHeight = 0;
+ private int mNextId = 0;
+ protected int mStartVertexId = -1;
+ protected Hashtable<String, Vertex> mVertexHashtable = new Hashtable<String, Vertex>();
+ protected Hashtable<String, DirectedEdge> mEdgeHashtable = new Hashtable<String, DirectedEdge>();
+ private GraphableVertex mContainingVertex;
+
+ /* Transient data */
+
+ // There should always be a Selection object
+ protected Selection mSelection = new Selection(null, null, 0, 0, 0, 0);
+ protected Vertex mNewEdgeOriginVertex = null;
+ protected Point mNewEdgeEndPoint = null;
+ private ElasticBand mElasticBand = null;
+ private GraphModelManager mManager = null;
+
+ /* External factories */
+
+ private VertexFactory mExternalVertexFactory = null;
+ private EdgeFactory mExternalEdgeFactory = null;
+
+ /* Vertex outline creator */
+
+ private VertexOutlineCreator mVertexOutlineCreator = null;
+
+ /* Notification Events */
+
+ private ClearedEvent mClearedEvent = new ClearedEvent();
+ private EdgeRemovedEvent mEdgeRemovedEvent = new EdgeRemovedEvent();
+ private EdgesChangedEvent mEdgesChangedEvent = new EdgesChangedEvent();
+ private ForcedNotifyEvent mForcedNotifyEvent = new ForcedNotifyEvent();
+ private NewEdgeEndPointChangedEvent mNewEdgeEndPointChangedEvent = new NewEdgeEndPointChangedEvent();
+ private SelectionChangedEvent mSelectionChangedEvent = new SelectionChangedEvent();
+ private StartVertexIdChangedEvent mStartVertexIdChangedEvent = new StartVertexIdChangedEvent();
+ private VertexAddedEvent mVertexAddedEvent = new VertexAddedEvent();
+ private VertexCreatedEvent mVertexCreatedEvent = new VertexCreatedEvent();
+ private VertexMovedEvent mVertexMovedEvent = new VertexMovedEvent();
+ private SelectionMovedEvent mSelectionMovedEvent = new SelectionMovedEvent();
+ private VertexRemovedEvent mVertexRemovedEvent = new VertexRemovedEvent();
+ private VerticesChangedEvent mVerticesChangedEvent = new VerticesChangedEvent();
+ private ElasticBandSetEvent mElasticBandSetEvent = new ElasticBandSetEvent();
+ private ElasticBandResizedEvent mElasticBandResizedEvent = new ElasticBandResizedEvent();
+ private GraphModelResizedEvent mGraphModelResizedEvent = new GraphModelResizedEvent();
+
+ // Calling this constructor does not create a vertex outline creator
+ // which is required by the method addVertexAndCreateId()
+
+ private static int count=0;
+
+ // count instances for debugging
+ private int number;
+
+ public GraphModel() {
+ number=++count;
+
+ }
+
+ public int getNumber() {
+ return number;
+ }
+
+ private void setChanged() {
+ if (mManager != null)
+ mManager.setChanged();
+ }
+
+ private void notifyObservers(GraphModelEvent ev) {
+ if (mManager != null)
+ mManager.notifyObservers(ev);
+ }
+
+ public void setNextId(int id) {
+ mNextId = id;
+ }
+
+ public int getNextId() {
+ return mNextId;
+ }
+
+ public void setManager(GraphModelManager mgr) {
+ mManager = mgr;
+ }
+
+ public GraphModelManager getManager() {
+ return mManager;
+ }
+
+ public GraphModel(VertexOutlineCreator vertexOutlineCreator) {
+ mVertexOutlineCreator = vertexOutlineCreator;
+ }
+
+ public void setWidth(int width) {
+
+ mWidth = width;
+ }
+
+ public int getWidth() {
+ return mWidth;
+ }
+
+ public void setHeight(int height) {
+
+ mHeight = height;
+ }
+
+ public int getHeight() {
+ return mHeight;
+ }
+
+ public void checkSize(Vertex v) {
+ boolean resized = false;
+ GraphPoint centre = v.getCentrePoint();
+ if (getWidth() < centre.x + v.getWidth()/2 +10 ) {
+ setWidth( centre.x + v.getWidth()/2 +10 );
+ resized = true;
+ }
+
+ if (getHeight() < centre.y + v.getHeight()/2 +10 ) {
+ setHeight(centre.y + v.getHeight()/2 +10 );
+ resized = true;
+ }
+
+ if (resized) {
+ setChanged();
+ notifyObservers(mGraphModelResizedEvent);
+ }
+
+ }
+
+ public void setStartVertexId(int id) {
+ mStartVertexId = id;
+ }
+
+ public int getStartVertexId() {
+ return mStartVertexId;
+ }
+
+ public Vertex getStartVertex() {
+ return resolveVertex(getStartVertexId());
+ }
+
+ /**
+ * @return Returns the mParentVertex.
+ */
+ public GraphableVertex getContainingVertex() {
+ return mContainingVertex;
+ }
+ /**
+ * @param parentVertex The mParentVertex to set.
+ */
+ public void setContainingVertex(GraphableVertex vertex) {
+ mContainingVertex = vertex;
+ }
+
+ public void setVertices(Vertex[] vertices) {
+ mVertexHashtable = new Hashtable<String, Vertex>();
+ for (Vertex vertice : vertices) {
+ mVertexHashtable.put(String.valueOf(vertice.getID()), vertice);
+ checkSize(vertice);
+
+ }
+ setChanged();
+ notifyObservers(mVerticesChangedEvent);
+ }
+
+ public Vertex[] getVertices() {
+ Object[] vertexObjs = mVertexHashtable.values().toArray();
+ Vertex[] vertices = new Vertex[vertexObjs.length];
+ int i = 0;
+ for (i = 0; i < vertices.length; i++) {
+ vertices[i] = (Vertex)vertexObjs[i];
+ }
+ return vertices;
+ }
+
+ public void setEdges(DirectedEdge[] edges) {
+ mEdgeHashtable = new Hashtable<String, DirectedEdge>();
+ for (DirectedEdge edge : edges) {
+ mEdgeHashtable.put(String.valueOf(edge.getID()), edge);
+ }
+ setChanged();
+ notifyObservers(mEdgesChangedEvent);
+ }
+
+ public DirectedEdge[] getEdges() {
+ Object[] edgeObjs = mEdgeHashtable.values().toArray();
+ DirectedEdge[] edges = new DirectedEdge[edgeObjs.length];
+ int i = 0;
+ for (i = 0; i < edges.length; i++) {
+ edges[i] = (DirectedEdge)edgeObjs[i];
+ }
+ return edges;
+ }
+
+ // If the specified point is within more than one vertex,
+ // then the smallest vertex is returned.
+ public Vertex getVertex(GraphPoint p) {
+ Object[] vertexObjs = mVertexHashtable.values().toArray();
+ Vertex vertex = null;
+ Vector<Vertex> vertexVector = new Vector<Vertex>(10, 10);
+ int numVerticesFound = 0;
+ Vertex smallestVertex = null;
+ int sizeOfSmallestVertex = 0;
+ int sizeOfVertex = 0;
+ int i = 0;
+ for (i = 0; i < vertexObjs.length; i++) {
+ vertex = (Vertex)vertexObjs[i];
+ if (vertex.containsPoint(p)) {
+ vertexVector.add(vertex);
+ }
+ }
+ numVerticesFound = vertexVector.size();
+ if (numVerticesFound == 0) {
+ return null;
+ }
+ else {
+ smallestVertex = vertexVector.elementAt(0);
+ sizeOfSmallestVertex = smallestVertex.getHeight() * smallestVertex.getWidth();
+ // Determine the smallest vertex
+ for (i = 1; i < numVerticesFound; i++) {
+ vertex = vertexVector.elementAt(i);
+ sizeOfVertex = vertex.getHeight() * vertex.getWidth();
+ if (sizeOfVertex < sizeOfSmallestVertex) {
+ smallestVertex = vertex;
+ sizeOfSmallestVertex = sizeOfVertex;
+ }
+ }
+ return smallestVertex;
+ }
+ }
+
+ public Vertex getVertexById(int id) {
+ return mVertexHashtable.get(String.valueOf(id));
+ }
+
+ public DirectedEdge getEdge(GraphPoint p) {
+ Object[] edgeObjs = mEdgeHashtable.values().toArray();
+ DirectedEdge edge = null;
+ int i = 0;
+ for (i = 0; i < edgeObjs.length; i++) {
+ edge = (DirectedEdge)edgeObjs[i];
+ if (edge.containsPoint(p)) {
+ return edge;
+ }
+ }
+ return null;
+ }
+
+ public int addEdgeAndCreateId(DirectedEdge e, int originId, int terminusId) {
+ return addEdgeAndCreateId(e, resolveVertex(originId), resolveVertex(terminusId));
+ }
+
+ public int addEdgeAndCreateId(DirectedEdge e, Vertex origin, Vertex terminus) {
+ e.setID(mNextId);
+ e.setOriginVertexId(origin.getID());
+ e.setOriginPoint(origin.getCentrePoint());
+ e.setTerminusVertexId(terminus.getID());
+ e.setTerminusPoint(terminus.getCentrePoint());
+ origin.addOutEdgeId(mNextId);
+ terminus.addInEdgeId(mNextId);
+ mEdgeHashtable.put(String.valueOf(mNextId), e);
+ mNextId++;
+ return mNextId - 1;
+ }
+
+ // Removes an edge, but does not modify the selection
+ public void removeEdge(DirectedEdge e) {
+ Vertex origin = getOrigin(e);
+ Vertex terminus = getTerminus(e);
+ int edgeId = e.getID();
+ // Remove the id of the edge from the origin and terminus vertices
+ origin.removeOutEdgeId(edgeId);
+ terminus.removeInEdgeId(edgeId);
+ // Remove the edge
+ mEdgeHashtable.remove(String.valueOf(e.getID()));
+ setChanged();
+ notifyObservers(mEdgeRemovedEvent);
+ }
+
+ public int addVertexAndCreateId(Vertex v, Point location) {
+ return addVertexAndCreateId(v, new GraphPoint(location.x, location.y));
+ }
+
+ public int addVertexAndCreateId(Vertex v, GraphPoint location) {
+ if (location!= null)
+ {
+ if (mVertexOutlineCreator == null) {
+ Logger.msg(1,"You cannot add a vertex with no outline creator");
+ return -1;
+
+ }
+ mVertexHashtable.put(String.valueOf(mNextId), v);
+ placeVertex(v, location);
+ }
+ v.setID(mNextId);
+ return mNextId++;
+ }
+
+ public void placeVertex(Vertex v, GraphPoint location) {
+ v.setCentrePoint(location);
+ if (mVertexOutlineCreator != null) {
+ mVertexOutlineCreator.setOutline(v);
+ }
+ setChanged();
+ notifyObservers(mVertexAddedEvent);
+ checkSize(v);
+ }
+
+ // Removes a vertex, but does not modify the selection
+ public void removeVertex(Vertex v) {
+ DirectedEdge[] inEdges = getInEdges(v);
+ DirectedEdge[] outEdges = getOutEdges(v);
+ Vertex origin = null;
+ Vertex terminus = null;
+ int edgeId = -1;
+ int i = 0;
+ // For each in edge
+ for (i = 0; i < inEdges.length; i++) {
+ edgeId = inEdges[i].getID();
+ origin = getOrigin(inEdges[i]);
+ // Remove the id of the edge from the origin vertex
+ origin.removeOutEdgeId(edgeId);
+ // Remove the edge
+ mEdgeHashtable.remove(String.valueOf(edgeId));
+ }
+ // Remove all the out edges
+ for (i = 0; i < outEdges.length; i++) {
+ edgeId = outEdges[i].getID();
+ terminus = getTerminus(outEdges[i]);
+ // Remove the id of the edge from the terminus vertex
+ terminus.removeInEdgeId(edgeId);
+ // Remove the edge
+ mEdgeHashtable.remove(String.valueOf(edgeId));
+ }
+ // Remove the vertex
+ mVertexHashtable.remove(String.valueOf(v.getID()));
+ setChanged();
+ notifyObservers(mVertexRemovedEvent);
+ }
+
+ public void moveAbsoluteVertex(Vertex v, GraphPoint p) {
+ // Make sure the new position stays within the graph
+ if (p.x < 0) p.x = 0;
+ if (p.y < 0) p.y = 0;
+ if (p.x > mWidth) p.x = mWidth;
+ if (p.y > mHeight) p.y = mHeight;
+ moveAbsoluteVertexAndConnectingEdges(v, p);
+ setChanged();
+ notifyObservers(mVertexMovedEvent);
+ }
+
+ private void moveAbsoluteVertexAndConnectingEdges(Vertex v, GraphPoint p) {
+ DirectedEdge[] inEdges = getInEdges(v);
+ DirectedEdge[] outEdges = getOutEdges(v);
+ int i = 0;
+ // Move the vertex to the new position
+ v.moveAbsolute(p);
+ // Move the ends of the incoming edges to the new position
+ for (i = 0; i < inEdges.length; i++) {
+ inEdges[i].setTerminusPoint(p);
+ }
+ // Move the ends of the outgoing edges to the new position
+ for (i = 0; i < outEdges.length; i++) {
+ outEdges[i].setOriginPoint(p);
+ }
+ checkSize(v);
+ }
+
+ public void moveAbsoluteSelection(int newTopLeftX, int newTopLeftY) {
+ int selectionHeight = mSelection.mBottomRightY - mSelection.mTopLeftY;
+ int selectionWidth = mSelection.mBottomRightX - mSelection.mTopLeftX;
+ int bottomRightX = newTopLeftX + selectionWidth;
+ int bottomRightY = newTopLeftY + selectionHeight;
+ GraphPoint oldCentrePoint = null;
+ GraphPoint newCentrePoint = null;
+ int distXFromTopLeft = 0;
+ int distYFromTopLeft = 0;
+ int i = 0;
+ // Make sure the selection does not move
+ // outside the boundaries of the graph
+ if (newTopLeftX < 0) newTopLeftX = 0;
+ if (newTopLeftY < 0) newTopLeftY = 0;
+ if (bottomRightX > mWidth) newTopLeftX = mWidth - selectionWidth;
+ if (bottomRightY > mHeight) newTopLeftY = mHeight - selectionHeight;
+ // For each selected vertex
+ for (i = 0; i < mSelection.mVertices.length; i++) {
+ // Calculate the new centre point of the vertex.
+ // First calculate the distance of the centre point
+ // from the old top left hand corner of the selection,
+ // then move the point to the new top left hand
+ // corner plus the distance.
+ oldCentrePoint = mSelection.mVertices[i].getCentrePoint();
+ distXFromTopLeft = oldCentrePoint.x - mSelection.mTopLeftX;
+ distYFromTopLeft = oldCentrePoint.y - mSelection.mTopLeftY;
+ newCentrePoint = new GraphPoint(newTopLeftX + distXFromTopLeft, newTopLeftY + distYFromTopLeft);
+ moveAbsoluteVertexAndConnectingEdges(mSelection.mVertices[i], newCentrePoint);
+ }
+ // Update the top left and bottom right corners
+ mSelection.mTopLeftX = newTopLeftX;
+ mSelection.mTopLeftY = newTopLeftY;
+ mSelection.mBottomRightX = newTopLeftX + selectionWidth;
+ mSelection.mBottomRightY = newTopLeftY + selectionHeight;
+ setChanged();
+ notifyObservers(mSelectionMovedEvent);
+ }
+
+ public Vertex resolveVertex(int id) {
+ return mVertexHashtable.get(String.valueOf(id));
+ }
+
+ public DirectedEdge resolveEdge(int id) {
+ return mEdgeHashtable.get(String.valueOf(id));
+ }
+
+ public DirectedEdge[] getInEdges(Vertex v) {
+ int[] ids = v.getInEdgeIds();
+ return resolveEdges(ids);
+ }
+
+ public DirectedEdge[] getOutEdges(Vertex v) {
+ int[] ids = v.getOutEdgeIds();
+ return resolveEdges(ids);
+ }
+
+ private DirectedEdge[] resolveEdges(int[] ids) {
+ DirectedEdge[] edges = new DirectedEdge[ids.length];
+ int i = 0;
+ for (i = 0; i < ids.length; i++) {
+ edges[i] = resolveEdge(ids[i]);
+ }
+ return edges;
+ }
+
+ public Vertex getOrigin(DirectedEdge e) {
+ return resolveVertex(e.getOriginVertexId());
+ }
+
+ public Vertex getTerminus(DirectedEdge e) {
+ return resolveVertex(e.getTerminusVertexId());
+ }
+
+ public Vertex[] getInVertices(Vertex v) {
+ DirectedEdge[] inEdges = getInEdges(v);
+ Vertex[] inVertices = new Vertex[inEdges.length];
+ int i = 0;
+ for (i = 0; i < inEdges.length; i++) {
+ inVertices[i] = getOrigin(inEdges[i]);
+ }
+ return inVertices;
+ }
+
+ public Vertex[] getOutVertices(Vertex v) {
+ DirectedEdge[] outEdges = getOutEdges(v);
+ Vertex[] outVertices = new Vertex[outEdges.length];
+ int i = 0;
+ for (i = 0; i < outEdges.length; i++) {
+ outVertices[i] = getTerminus(outEdges[i]);
+ }
+ return outVertices;
+ }
+
+ public DirectedEdge[] getConnectingEdges(int originVertexId, int terminusVertexId) {
+ Vertex origin = resolveVertex(originVertexId);
+ DirectedEdge[] outEdges = null;
+ int numEdgesFound = 0;
+ DirectedEdge[] edgesFound = null;
+ int i = 0;
+ int j = 0;
+ if (origin == null) return null;
+ outEdges = getOutEdges(origin);
+ for (i = 0; i < outEdges.length; i++) {
+ if (outEdges[i].getTerminusVertexId() == terminusVertexId) {
+ numEdgesFound++;
+ }
+ }
+ edgesFound = new DirectedEdge[numEdgesFound];
+ for (i = 0; i < outEdges.length; i++) {
+ if (outEdges[i].getTerminusVertexId() == terminusVertexId) {
+ edgesFound[j] = outEdges[i];
+ j++;
+ }
+ }
+ return edgesFound;
+ }
+
+ public void clearTags(Object tag) {
+ Vertex vertex = null;
+ Object[] vertexObjs = mVertexHashtable.values().toArray();
+ int i = 0;
+ for (i = 0; i < vertexObjs.length; i++) {
+ vertex = (Vertex)vertexObjs[i];
+ vertex.clearTag(tag);
+ }
+ }
+
+ public void forceNotify() {
+ setChanged();
+ notifyObservers(mForcedNotifyEvent);
+ }
+
+ public void clear() {
+ mVertexHashtable = new Hashtable<String, Vertex>();
+ mEdgeHashtable = new Hashtable<String, DirectedEdge>();
+ mStartVertexId = -1;
+ setChanged();
+ notifyObservers(mClearedEvent);
+ }
+
+ public void setSelection(Selection s) {
+ // If the there is a change
+ if (selectionChanged(s)) {
+ mSelection = s;
+ mSelectionChangedEvent.mSelection = s;
+ setChanged();
+ notifyObservers(mSelectionChangedEvent);
+ }
+ }
+
+ private boolean selectionChanged(Selection newValue) {
+ int i = 0;
+ if (mSelection.mEdge != newValue.mEdge) {
+ return true;
+ }
+ if (mSelection.mVertices == null) {
+ if (newValue.mVertices == null) {
+ return false;
+ }
+ else {
+ return true;
+ }
+ }
+ else {
+ if (newValue.mVertices == null) {
+ return true;
+ }
+ else {
+ if (mSelection.mVertices.length != newValue.mVertices.length) {
+ return true;
+ }
+ for (i = 0; i < mSelection.mVertices.length; i++) {
+ if (mSelection.mVertices[i] != newValue.mVertices[i]) {
+ return true;
+ }
+ }
+ return false;
+ }
+ }
+ }
+
+ public Selection getSelection() {
+ return mSelection;
+ }
+
+ public void setNewEdgeOriginVertex(Vertex v) {
+ mNewEdgeOriginVertex = v;
+ }
+
+ public Vertex getNewEdgeOriginVertex() {
+ return mNewEdgeOriginVertex;
+ }
+
+ public void setNewEdgeEndPoint(Point p) {
+ mNewEdgeEndPoint = p;
+ setChanged();
+ notifyObservers(mNewEdgeEndPointChangedEvent);
+ }
+
+ public Point getNewEdgeEndPoint() {
+ return mNewEdgeEndPoint;
+ }
+
+ public void setExternalVertexFactory(VertexFactory factory) {
+ mExternalVertexFactory = factory;
+ }
+
+ public void createVertex(Point location, TypeNameAndConstructionInfo typeNameAndConstructionInfo) {
+ if (mExternalVertexFactory != null) {
+ mExternalVertexFactory.create(mManager, location, typeNameAndConstructionInfo);
+ setChanged();
+ notifyObservers(mVertexCreatedEvent);
+ }
+ }
+
+ public void setExternalEdgeFactory(EdgeFactory factory) {
+ mExternalEdgeFactory = factory;
+ }
+
+ public void setVertexOutlineCreator(VertexOutlineCreator outlineCreator) {
+ mVertexOutlineCreator = outlineCreator;
+ }
+
+ public void createDirectedEdge(Vertex origin, Vertex terminus, TypeNameAndConstructionInfo typeNameAndConstructionInfo) {
+ if (mExternalEdgeFactory != null) {
+ mExternalEdgeFactory.create(mManager, origin, terminus, typeNameAndConstructionInfo);
+ }
+ }
+
+ public void selectAll() {
+ Vertex[] allVertices = getVertices();
+ if (allVertices.length > 0) {
+ mSelection.mEdge = null;
+ mSelection.mVertices = allVertices;
+ updateSelectionCorners();
+ mSelectionChangedEvent.mSelection = mSelection;
+ setChanged();
+ notifyObservers(mSelectionChangedEvent);
+ }
+ }
+
+ public void selectContentsOfElasticBand() {
+ if (mElasticBand == null) return;
+ Polygon bandPolygon = new Polygon();
+ Vertex[] allVertices = getVertices();
+ GraphPoint centrePoint = null;
+ Vector<Vertex> verticesInside = new Vector<Vertex>(10, 10);
+ int i = 0;
+ // Create a polygon representing the elastic band
+ bandPolygon.addPoint(mElasticBand.mFixedCorner.x, mElasticBand.mFixedCorner.y);
+ bandPolygon.addPoint(mElasticBand.mMovingCorner.x, mElasticBand.mFixedCorner.y);
+ bandPolygon.addPoint(mElasticBand.mMovingCorner.x, mElasticBand.mMovingCorner.y);
+ bandPolygon.addPoint(mElasticBand.mFixedCorner.x, mElasticBand.mMovingCorner.y);
+ // Create a vector of all of the vertices within the elastic band polygon
+ for (i = 0; i < allVertices.length; i++) {
+ centrePoint = allVertices[i].getCentrePoint();
+ if (bandPolygon.contains(centrePoint.x, centrePoint.y)) {
+ verticesInside.add(allVertices[i]);
+ }
+ }
+
+ // Select the vertices found within the elastic band polygon
+ if (verticesInside.size() == 0) {
+ mSelection.mTopLeftX = 0;
+ mSelection.mTopLeftY = 0;
+ mSelection.mBottomRightX = 0;
+ mSelection.mBottomRightY = 0;
+ mSelection.mEdge = null;
+ if (mContainingVertex != null)
+ verticesInside.add(mContainingVertex);
+ else
+ mSelection.mVertices = null;
+ }
+
+ if (verticesInside.size() > 0) {
+ mSelection.mEdge = null;
+ mSelection.mVertices = new Vertex[verticesInside.size()];
+ for (i = 0; i < verticesInside.size(); i++) {
+ mSelection.mVertices[i] = verticesInside.elementAt(i);
+ }
+ updateSelectionCorners();
+ }
+ // Remove the elastic band
+ mElasticBand = null;
+ mSelectionChangedEvent.mSelection = mSelection;
+ setChanged();
+ notifyObservers(mSelectionChangedEvent);
+ }
+
+ // Updates the top left and bottom right corners of the selection
+ private void updateSelectionCorners() {
+ Vertex vertex = mSelection.mVertices[0];
+ GraphPoint centrePoint = vertex.getCentrePoint();
+ if (centrePoint == null) return;
+ mSelection.mTopLeftX = centrePoint.x;
+ mSelection.mTopLeftY = centrePoint.y;
+ mSelection.mBottomRightX = centrePoint.x;
+ mSelection.mBottomRightY = centrePoint.y;
+ for (Vertex mVertice : mSelection.mVertices) {
+ vertex = mVertice;
+ centrePoint = vertex.getCentrePoint();
+ if (centrePoint.x < mSelection.mTopLeftX) {
+ mSelection.mTopLeftX = centrePoint.x;
+ }
+ if (centrePoint.y < mSelection.mTopLeftY) {
+ mSelection.mTopLeftY = centrePoint.y;
+ }
+ if (centrePoint.x > mSelection.mBottomRightX) {
+ mSelection.mBottomRightX = centrePoint.x;
+ }
+ if (centrePoint.y > mSelection.mBottomRightY) {
+ mSelection.mBottomRightY = centrePoint.y;
+ }
+ }
+ }
+
+ public void deleteSelection() {
+ int i = 0;
+ if (mSelection.mVertices != null) {
+ for (i = 0; i < mSelection.mVertices.length; i++) {
+ removeVertex(mSelection.mVertices[i]);
+ }
+ }
+ else if (mSelection.mEdge != null) {
+ removeEdge(mSelection.mEdge);
+ }
+ // Make sure nothing is selected
+ if ((mSelection.mEdge != null) || (mSelection.mVertices != null)) {
+ mSelection.mEdge = null;
+ mSelection.mVertices = null;
+ mSelectionChangedEvent.mSelection = mSelection;
+ setChanged();
+ notifyObservers(mSelectionChangedEvent);
+ }
+ }
+
+ public void setSelectedVertexToBeStart() {
+ if (mSelection.mVertices != null) {
+ if (mSelection.mVertices.length == 1) {
+ setStartVertexId(mSelection.mVertices[0].getID());
+ setChanged();
+ notifyObservers(mStartVertexIdChangedEvent);
+ }
+ }
+ }
+
+ public void setElasticBand(ElasticBand elasticBand) {
+ mElasticBand = elasticBand;
+ setChanged();
+ notifyObservers(mElasticBandSetEvent);
+ }
+
+ public ElasticBand getElasticBand() {
+ return mElasticBand;
+ }
+
+ public void resizeElasticBand(Point movingCorner) {
+ mElasticBand.mMovingCorner = movingCorner;
+ setChanged();
+ notifyObservers(mElasticBandResizedEvent);
+ }
+
+ public boolean inSelection(Vertex v) {
+ int i = 0;
+ if (mSelection.mVertices == null) {
+ return false;
+ }
+ else {
+ for (i = 0; i < mSelection.mVertices.length; i++) {
+ if (mSelection.mVertices[i] == v) {
+ return true;
+ }
+ }
+ return false;
+ }
+ }
+
+ // Only use this method to remove one vertex.
+ // If you wish to remove more, it would
+ // propably be more efficient to create a
+ // new Selection object.
+ public void removeFromSelection(Vertex v) {
+ Vertex[] vertices = null;
+ int i = 0;
+ int j = 0;
+ if (mSelection.mVertices.length == 1) {
+ mSelection.mVertices = null;
+ mSelection.mTopLeftX = 0;
+ mSelection.mTopLeftY = 0;
+ mSelection.mBottomRightX = 0;
+ mSelection.mBottomRightY = 0;
+ }
+ else {
+ vertices = new Vertex[mSelection.mVertices.length - 1];
+ for (i = 0; i < mSelection.mVertices.length; i++) {
+ if (mSelection.mVertices[i] != v) {
+ vertices[j] = mSelection.mVertices[i];
+ j++;
+ }
+ }
+ mSelection.mVertices = vertices;
+ updateSelectionCorners();
+ }
+ setChanged();
+ notifyObservers(mSelectionChangedEvent);
+ }
+
+ // Only use this method to add one vertex.
+ // If you wish to add more, it would
+ // propably be more efficient to create a
+ // new Selection object.
+ public void addToSelection(Vertex v) {
+ Vertex[] vertices = new Vertex[mSelection.mVertices.length + 1];
+ GraphPoint centrePoint = null;
+ int i = 0;
+ if (mSelection.mVertices == null) {
+ centrePoint = v.getCentrePoint();
+ mSelection.mVertices = new Vertex[] { v };
+ mSelection.mTopLeftX = centrePoint.x;
+ mSelection.mTopLeftY = centrePoint.y;
+ mSelection.mBottomRightX = centrePoint.x;
+ mSelection.mBottomRightY = centrePoint.y;
+ }
+ else {
+ for (i = 0; i < mSelection.mVertices.length; i++) {
+ vertices[i] = mSelection.mVertices[i];
+ }
+ vertices[mSelection.mVertices.length] = v;
+ mSelection.mVertices = vertices;
+ updateSelectionCorners();
+ }
+ setChanged();
+ notifyObservers(mSelectionChangedEvent);
+ }
+
+ public void resetVertexOutlines() {
+ Vertex[] vertices = getVertices();
+ int i = 0;
+ for (i = 0; i < vertices.length; i++) {
+ mVertexOutlineCreator.setOutline(vertices[i]);
+ }
+ }
+
+ public void setGraphModelCastorData(GraphModelCastorData data) {
+ Class<?> vertexOutlineCreatorClass = null;
+ int i = 0;
+ // Create the vertex outline creator
+ if (data.mClassNameOfVertexOutlineCreator.equals("")) {
+ mVertexOutlineCreator = null;
+ }
+ else {
+ try {
+ vertexOutlineCreatorClass = Class.forName(data.mClassNameOfVertexOutlineCreator);
+ mVertexOutlineCreator = (VertexOutlineCreator)vertexOutlineCreatorClass.newInstance();
+ }
+ catch (Exception e) {
+ e.printStackTrace();
+ mVertexOutlineCreator = null;
+ }
+ }
+ // Create and populate the vertex hashtable
+ mVertexHashtable = new Hashtable<String, Vertex>();
+ for (i = 0; i < data.mVertexImpls.length; i++) {
+ mVertexHashtable.put(String.valueOf(data.mVertexImpls[i].getID()), data.mVertexImpls[i]);
+ checkSize(data.mVertexImpls[i]);
+ }
+ // Create and populate the edge hastable
+ mEdgeHashtable = new Hashtable<String, DirectedEdge>();
+ for (i = 0; i < data.mEdgeImpls.length; i++) {
+ mEdgeHashtable.put(String.valueOf(data.mEdgeImpls[i].getID()), data.mEdgeImpls[i]);
+ }
+ // Set the start vertex id and the id generation counter
+ mStartVertexId = data.mStartVertexId;
+ mNextId = data.mNextId;
+ }
+
+ public GraphModelCastorData getGraphModelCastorData() {
+ Object[] vertexObjs = mVertexHashtable.values().toArray();
+ Vertex[] vertexImpls = new Vertex[vertexObjs.length];
+ Object[] edgeObjs = mEdgeHashtable.values().toArray();
+ DirectedEdge[] directedEdgeImpls = new DirectedEdge[edgeObjs.length];
+ String className = null;
+ int i = 0;
+ // Put in the vertices
+ for (i = 0; i < vertexImpls.length; i++) {
+ vertexImpls[i] = (Vertex)vertexObjs[i];
+ }
+ // Put in the edges
+ for (i = 0; i < directedEdgeImpls.length; i++) {
+ directedEdgeImpls[i] = (DirectedEdge)edgeObjs[i];
+ }
+ // Determine the class name of the vertex outline creator
+ if (mVertexOutlineCreator == null) {
+ className = "";
+ }
+ else {
+ className = mVertexOutlineCreator.getClass().getName();
+ }
+ return new GraphModelCastorData(className, vertexImpls, directedEdgeImpls, mStartVertexId, mNextId);
+ }
+}
diff --git a/src/main/java/com/c2kernel/graph/model/GraphModelCastorData.java b/src/main/java/com/c2kernel/graph/model/GraphModelCastorData.java
new file mode 100644
index 0000000..7717c33
--- /dev/null
+++ b/src/main/java/com/c2kernel/graph/model/GraphModelCastorData.java
@@ -0,0 +1,29 @@
+package com.c2kernel.graph.model;
+
+
+public class GraphModelCastorData
+{
+ public String mClassNameOfVertexOutlineCreator = "";
+ public Vertex[] mVertexImpls = {};
+ public DirectedEdge[] mEdgeImpls = {};
+ public int mStartVertexId = 0;
+ public int mNextId = 0;
+
+
+ public GraphModelCastorData()
+ {
+ }
+
+ public GraphModelCastorData(String classNameOfVertexOutlineCreator,
+ Vertex[] vertexImpls,
+ DirectedEdge[] edgeImpls,
+ int startVertexId,
+ int nextId)
+ {
+ mClassNameOfVertexOutlineCreator = classNameOfVertexOutlineCreator;
+ mVertexImpls = vertexImpls;
+ mEdgeImpls = edgeImpls;
+ mStartVertexId = startVertexId;
+ mNextId = nextId;
+ }
+}
diff --git a/src/main/java/com/c2kernel/graph/model/GraphModelManager.java b/src/main/java/com/c2kernel/graph/model/GraphModelManager.java
new file mode 100644
index 0000000..68d47e0
--- /dev/null
+++ b/src/main/java/com/c2kernel/graph/model/GraphModelManager.java
@@ -0,0 +1,143 @@
+package com.c2kernel.graph.model;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.Observable;
+import java.util.Stack;
+
+import com.c2kernel.graph.event.EntireModelChangedEvent;
+import com.c2kernel.graph.event.ForcedNotifyEvent;
+import com.c2kernel.graph.event.GraphModelEvent;
+import com.c2kernel.utils.Logger;
+
+
+public class GraphModelManager extends Observable
+{
+
+ private GraphModel mGraphModel;
+ private EdgeFactory mEdgeFactory;
+ private VertexFactory mVertexFactory;
+ private VertexOutlineCreator mVertexOutlineCreator;
+ private EntireModelChangedEvent mEntireModelChangedEvent = new EntireModelChangedEvent();
+ private ForcedNotifyEvent mForcedNotifyEvent = new ForcedNotifyEvent();
+ private Stack<GraphModel> mParentModels = new Stack<GraphModel>();
+ private ArrayList<Integer> mParentIds = new ArrayList<Integer>();
+ private boolean mEditable = true;
+
+ // Calling this constructor does not create a vertex outline creator
+ // which is required by the method addVertexAndCreateId()
+ public GraphModelManager()
+ {
+ mGraphModel = new GraphModel();
+ mGraphModel.setManager(this);
+ }
+
+ public GraphModelManager(GraphModel newModel) {
+ newModel.setManager(this);
+ mGraphModel = newModel;
+ }
+
+ public void replace(GraphModel newModel) {
+ mParentModels.clear();
+
+ //zoom back to where we were
+ for (Iterator<Integer> iter = mParentIds.iterator(); iter.hasNext();) {
+ Integer parentId = iter.next();
+ GraphableVertex childModelVertex = (GraphableVertex)newModel.getVertexById(parentId.intValue());
+ if (childModelVertex == null) { // we've been deleted, stay here
+ Logger.msg(7, "Didn't find "+parentId+" in new model tree. Stopping here.");
+ do { iter.remove(); } while (iter.hasNext());
+ break;
+ }
+ else {
+ mParentModels.push(newModel);
+ Logger.msg(7, "Pushing model and switching to "+parentId);
+ newModel = childModelVertex.getChildGraphModel();
+ }
+ }
+ setModel(newModel);
+ }
+
+ public void setModel(GraphModel newModel) {
+ // reset transient data
+ newModel.mSelection = new Selection(null, null, 0, 0, 0, 0);
+ newModel.mNewEdgeOriginVertex = null;
+ newModel.mNewEdgeEndPoint = null;
+
+ // copy factories over
+ newModel.setExternalEdgeFactory(mEdgeFactory);
+ newModel.setExternalVertexFactory(mVertexFactory);
+ newModel.setVertexOutlineCreator(mVertexOutlineCreator);
+ mVertexFactory.setCreationContext(newModel.getContainingVertex());
+ newModel.setManager(this);
+ mGraphModel.setManager(null);
+ mGraphModel = newModel;
+
+ // notify
+ setChanged();
+ notifyObservers(mEntireModelChangedEvent);
+ }
+
+ public void zoomIn(Vertex child) {
+ GraphModel childModel = child.getChildGraphModel();
+ if (childModel != null) {
+ mParentModels.push(mGraphModel);
+ mParentIds.add(new Integer(child.getID()));
+ setModel(childModel);
+ Logger.msg(7, "ZoomIn - Stack size: "+mParentModels.size()+" ids:"+mParentIds.size());
+ }
+ }
+
+ public void zoomOut() {
+ if (!mParentModels.empty()) {
+ setModel(mParentModels.pop());
+ mParentIds.remove(mParentIds.size()-1);
+ }
+ Logger.msg(7, "ZoomOut - Stack size: "+mParentModels.size()+" ids:"+mParentIds.size());
+
+ }
+
+ public void forceNotify()
+ {
+ setChanged();
+ notifyObservers(mForcedNotifyEvent);
+ }
+
+ public GraphModel getModel() {
+ return mGraphModel;
+ }
+
+ public void setExternalEdgeFactory(EdgeFactory newEdgeFactory) {
+ mEdgeFactory = newEdgeFactory;
+ mGraphModel.setExternalEdgeFactory(newEdgeFactory);
+ }
+
+ public void setExternalVertexFactory(VertexFactory newVertexFactory) {
+ mVertexFactory = newVertexFactory;
+ mGraphModel.setExternalVertexFactory(newVertexFactory);
+ }
+
+ public void setVertexOutlineCreator(VertexOutlineCreator newVertexOutlineCreator) {
+ mVertexOutlineCreator = newVertexOutlineCreator;
+ mGraphModel.setVertexOutlineCreator(newVertexOutlineCreator);
+ }
+
+ @Override
+ protected void setChanged() {
+ super.setChanged();
+ }
+
+ protected void notifyObservers(GraphModelEvent ev) {
+ super.notifyObservers(ev);
+ }
+
+ public void setEditable(boolean editable) {
+ mEditable = editable;
+ }
+
+ public boolean isEditable() {
+ return mEditable;
+ }
+
+
+}
diff --git a/src/main/java/com/c2kernel/graph/model/GraphPoint.java b/src/main/java/com/c2kernel/graph/model/GraphPoint.java
new file mode 100644
index 0000000..f2aa165
--- /dev/null
+++ b/src/main/java/com/c2kernel/graph/model/GraphPoint.java
@@ -0,0 +1,18 @@
+package com.c2kernel.graph.model;
+
+import java.io.Serializable;
+
+public class GraphPoint implements Serializable{
+
+ public int x;
+ public int y;
+
+ public GraphPoint() {
+ x=0; y=0;
+ }
+
+ public GraphPoint(int x, int y) {
+ this.x = x;
+ this.y = y;
+ }
+}
diff --git a/src/main/java/com/c2kernel/graph/model/Graphable.java b/src/main/java/com/c2kernel/graph/model/Graphable.java
new file mode 100644
index 0000000..ed55271
--- /dev/null
+++ b/src/main/java/com/c2kernel/graph/model/Graphable.java
@@ -0,0 +1,55 @@
+package com.c2kernel.graph.model;
+
+/**
+* @version $Revision: 1.6 $ $Date: 2003/05/12 13:10:20 $
+* @author $Author: abranson $
+*/
+
+import com.c2kernel.utils.CastorHashMap;
+
+abstract public class Graphable extends Vertex
+{
+
+ protected CastorHashMap mProperties = null;
+ public GraphModel children;
+
+ public void setProperties(CastorHashMap props)
+ {
+ mProperties = props;
+ }
+
+ public CastorHashMap getProperties()
+ {
+ return mProperties;
+ }
+ /** @associates Graphable that is directly containing it*/
+ private Graphable parent;
+
+ /**
+ * Returns the parent.
+ * @return Graphable
+ */
+ public Graphable getParent()
+ {
+ return parent;
+ }
+
+ /**
+ * Sets the parent.
+ * @param parent The parent to set
+ */
+ public void setParent(Graphable parent)
+ {
+ this.parent = parent;
+ }
+ @Override
+ public GraphModel getChildGraphModel() {
+ return children;
+ }
+
+ @Override
+ public Object getCreationContext() {
+ return this;
+ }
+
+}
diff --git a/src/main/java/com/c2kernel/graph/model/GraphableEdge.java b/src/main/java/com/c2kernel/graph/model/GraphableEdge.java
new file mode 100644
index 0000000..23499be
--- /dev/null
+++ b/src/main/java/com/c2kernel/graph/model/GraphableEdge.java
@@ -0,0 +1,71 @@
+package com.c2kernel.graph.model;
+
+import com.c2kernel.utils.CastorHashMap;
+import com.c2kernel.utils.KeyValuePair;
+
+/**
+* @version $Revision: 1.2 $ $Date: 2003/05/12 13:10:20 $
+* @author $Author: abranson $
+*/
+public abstract class GraphableEdge extends DirectedEdge
+{
+
+ private GraphableVertex mParent;
+ private CastorHashMap mProperties = null;
+
+ public GraphableEdge()
+ {
+ mProperties = new CastorHashMap();
+ }
+
+ public GraphableEdge(GraphableVertex pre, GraphableVertex nex)
+ {
+ mProperties = new CastorHashMap();
+ setParent(pre.getParent());
+ pre.getParent().getChildrenGraphModel().addEdgeAndCreateId(this, pre, nex);
+ }
+
+ /**
+ * Returns the parent.
+ * @return GraphableVertex
+ */
+ public GraphableVertex getParent()
+ {
+ return mParent;
+ }
+
+ /**
+ * Sets the parent.
+ * @param parent The parent to set
+ */
+ public void setParent(GraphableVertex parent)
+ {
+ mParent = parent;
+ }
+
+ /**
+ * Returns the properties.
+ * @return CastorHashMap
+ */
+ public CastorHashMap getProperties()
+ {
+ return mProperties;
+ }
+
+ /**
+ * Sets the properties.
+ * @param properties The properties to set
+ */
+ public void setProperties(CastorHashMap properties)
+ {
+ mProperties = properties;
+ }
+
+ public KeyValuePair[] getKeyValuePairs() {
+ return mProperties.getKeyValuePairs();
+ }
+
+ public void setKeyValuePairs(KeyValuePair[] pairs) {
+ mProperties.setKeyValuePairs(pairs);
+ }
+}
diff --git a/src/main/java/com/c2kernel/graph/model/GraphableVertex.java b/src/main/java/com/c2kernel/graph/model/GraphableVertex.java
new file mode 100644
index 0000000..fc04743
--- /dev/null
+++ b/src/main/java/com/c2kernel/graph/model/GraphableVertex.java
@@ -0,0 +1,261 @@
+package com.c2kernel.graph.model;
+/**
+* @version $Revision: 1.24 $ $Date: 2005/10/05 07:39:37 $
+* @author $Author: abranson $
+*/
+import java.awt.Point;
+
+import com.c2kernel.utils.CastorHashMap;
+import com.c2kernel.utils.KeyValuePair;
+public abstract class GraphableVertex extends Vertex
+{
+ private CastorHashMap mProperties = null;
+ private boolean mIsLayoutable;
+ protected boolean mIsComposite;
+ private GraphModel mChildrenGraphModel;
+ public GraphableVertex()
+ {
+ mProperties = new CastorHashMap();
+ }
+ public void setProperties(CastorHashMap props)
+ {
+ mProperties = props;
+ }
+ public CastorHashMap getProperties()
+ {
+ return mProperties;
+ }
+ public KeyValuePair[] getKeyValuePairs()
+ {
+ return mProperties.getKeyValuePairs();
+ }
+ public void setKeyValuePairs(KeyValuePair[] pairs)
+ {
+ mProperties.setKeyValuePairs(pairs);
+ }
+ /** @associates Graphable that is directly containing it*/
+ private GraphableVertex parent;
+ /**
+ * Returns the parent.
+ * @return Graphable
+ */
+ public GraphableVertex getParent()
+ {
+ return parent;
+ }
+ /**
+ * Sets the parent.
+ * @param parent The parent to set
+ */
+ public void setParent(GraphableVertex parent)
+ {
+ if (this.equals(parent))
+ throw new ExceptionInInitializerError();
+ this.parent = parent;
+ }
+ @Override
+ public GraphModel getChildGraphModel()
+ {
+ return mChildrenGraphModel;
+ }
+ @Override
+ public Object getCreationContext()
+ {
+ return this;
+ }
+ public Vertex[] getOutGraphables()
+ {
+ if (parent == null)
+ return new Vertex[0]; // none if no parent
+ return parent.mChildrenGraphModel.getOutVertices(this);
+ }
+ public DirectedEdge[] getOutEdges()
+ {
+ if (parent == null)
+ return new DirectedEdge[0]; // none if no parent
+ return parent.mChildrenGraphModel.getOutEdges(this);
+ }
+ public DirectedEdge[] getInEdges()
+ {
+ if (parent == null)
+ return new DirectedEdge[0]; // none if no parent
+ DirectedEdge[] edges = getParent().mChildrenGraphModel.getInEdges(this);
+ if (edges != null)
+ return edges;
+ else
+ return new DirectedEdge[0];
+ }
+ public GraphableVertex[] getChildren()
+ {
+ return getLayoutableChildren();
+ }
+
+ public DirectedEdge[] getChildrenEdges()
+ {
+ if (getIsComposite())
+ {
+ return getChildGraphModel().getEdges();
+ }
+ return null;
+ }
+
+ public GraphableVertex[] getLayoutableChildren()
+ {
+ if (getIsComposite())
+ {
+ Vertex[] vs = mChildrenGraphModel.getVertices();
+ GraphableVertex[] gvs = new GraphableVertex[vs.length];
+ for (int i = 0; i < vs.length; i++)
+ {
+ gvs[i] = (GraphableVertex) vs[i];
+ }
+ return gvs;
+ }
+ return null;
+ }
+ // deprecated methods
+ public GraphableVertex[] getCNonLayoutableChildren() {
+ return new GraphableVertex[0];
+ }
+ public void setCNonLayoutableChildren(GraphableVertex[] dummy) { }
+
+ /**@returns the Graphable searched or null if not this or children*/
+ public GraphableVertex search(String ids)
+ {
+ if (getName().equals(ids))
+ return this;
+ if (String.valueOf(getID()).equals(ids))
+ return this;
+ if (getIsComposite())
+ {
+ GraphableVertex[] graphables = getChildren();
+ if (ids.startsWith(String.valueOf(getID())))
+ ids = ids.substring(ids.indexOf("/") + 1);
+ else if (ids.startsWith(getName()))
+ ids = ids.substring(getName().length() + 1);
+ else if (ids.startsWith(getPath()))
+ ids = ids.substring(getPath().length() + 1);
+ else
+ return null;
+
+ for (GraphableVertex graphable : graphables) {
+ GraphableVertex grap = graphable.search(ids);
+ if (grap != null) return grap;
+ }
+ }
+ return null;
+ }
+ /**
+ * Returns the isLayoutable.
+ * @return boolean
+ */
+ public boolean getIsLayoutable()
+ {
+ return mIsLayoutable;
+ }
+ /**
+ * Sets the isLayoutable.
+ * @param isLayoutable The isLayoutable to set
+ */
+ public void setIsLayoutable(boolean isLayoutable)
+ {
+ mIsLayoutable = isLayoutable;
+ }
+ /**
+ * Returns the isComposite.
+ * @return boolean
+ */
+ public boolean getIsComposite()
+ {
+ return mIsComposite;
+ }
+ /**
+ * Sets the isComposite.
+ * @param isComposite The isComposite to set
+ */
+ public void setIsComposite(boolean isComposite)
+ {
+ mIsComposite = isComposite;
+ }
+ public void addChild(GraphableVertex graphableVertex, Point p)
+ {
+ addChild(graphableVertex, new GraphPoint(p.x, p.y));
+ }
+ public void addChild(GraphableVertex graphableVertex, GraphPoint g)
+ {
+ getChildGraphModel().addVertexAndCreateId(graphableVertex, g);
+ graphableVertex.setParent(this);
+ }
+ /**
+ * Returns the childrenGraph.
+ * @return GraphModel
+ */
+ public GraphModel getChildrenGraphModel()
+ {
+ return mChildrenGraphModel;
+ }
+ /**
+ * Sets the childrenGraph.
+ * @param childrenGraph The childrenGraph to set
+ */
+ public void setChildrenGraphModel(GraphModel childrenGraph)
+ {
+ mChildrenGraphModel = childrenGraph;
+ DirectedEdge[] edges = mChildrenGraphModel.getEdges();
+ GraphableVertex[] graphables = this.getLayoutableChildren();
+ if (graphables != null)
+ for (GraphableVertex graphable : graphables)
+ graphable.setParent(this);
+ if (edges != null)
+ for (DirectedEdge edge : edges)
+ ((GraphableEdge) edge).setParent(this);
+ childrenGraph.setContainingVertex(this);
+ }
+
+ /**
+ * @see com.c2kernel.graph.model.Vertex#getCentrePoint()
+ */
+ @Override
+ public GraphPoint getCentrePoint()
+ {
+ if (!getIsLayoutable())
+ return null;
+ return super.getCentrePoint();
+ }
+ /**
+ * @see com.c2kernel.graph.model.Vertex#getInEdgeIds()
+ */
+ @Override
+ public int[] getInEdgeIds()
+ {
+ if (!getIsLayoutable())
+ return null;
+ return super.getInEdgeIds();
+ }
+ /**
+ * @see com.c2kernel.graph.model.Vertex#getOutEdgeIds()
+ */
+ @Override
+ public int[] getOutEdgeIds()
+ {
+ if (!getIsLayoutable())
+ return null;
+ return super.getOutEdgeIds();
+ }
+ /**
+ * @see com.c2kernel.graph.model.Vertex#getOutlinePoints()
+ */
+ @Override
+ public GraphPoint[] getOutlinePoints()
+ {
+ if (!getIsLayoutable())
+ return null;
+ return super.getOutlinePoints();
+ }
+ public String getPath()
+ {
+ if (getName() != null && !getName().equals(""))
+ return getParent().getPath() + "/" + getName();
+ return getParent().getPath() + "/" + getID();
+ }
+} \ No newline at end of file
diff --git a/src/main/java/com/c2kernel/graph/model/Selection.java b/src/main/java/com/c2kernel/graph/model/Selection.java
new file mode 100644
index 0000000..dcc7b46
--- /dev/null
+++ b/src/main/java/com/c2kernel/graph/model/Selection.java
@@ -0,0 +1,35 @@
+package com.c2kernel.graph.model;
+
+import java.io.Serializable;
+
+
+
+public class Selection implements Serializable
+{
+ // Either a single edge can be selected or
+ // one or more vertices can be selected.
+ // It is impossible to select an edge and a
+ // vertex at the same time.
+ public DirectedEdge mEdge = null;
+ public Vertex[] mVertices = null;
+ public int mTopLeftX = 0;
+ public int mTopLeftY = 0;
+ public int mBottomRightX = 0;
+ public int mBottomRightY = 0;
+
+
+ public Selection(DirectedEdge edge,
+ Vertex[] vertices,
+ int topLeftX,
+ int topLeftY,
+ int bottomRightX,
+ int bottomRightY)
+ {
+ mEdge = edge;
+ mVertices = vertices;
+ mTopLeftX = topLeftX;
+ mTopLeftY = topLeftY;
+ mBottomRightX = bottomRightX;
+ mBottomRightY = bottomRightY;
+ }
+}
diff --git a/src/main/java/com/c2kernel/graph/model/TypeNameAndConstructionInfo.java b/src/main/java/com/c2kernel/graph/model/TypeNameAndConstructionInfo.java
new file mode 100644
index 0000000..e5b6c3d
--- /dev/null
+++ b/src/main/java/com/c2kernel/graph/model/TypeNameAndConstructionInfo.java
@@ -0,0 +1,24 @@
+package com.c2kernel.graph.model;
+
+import java.io.Serializable;
+
+
+public class TypeNameAndConstructionInfo implements Serializable
+{
+ public String mName = null;
+ public Object mInfo = null;
+
+
+ public TypeNameAndConstructionInfo(String name, Object info)
+ {
+ mName = name;
+ mInfo = info;
+ }
+
+
+ @Override
+ public String toString()
+ {
+ return mName;
+ }
+}
diff --git a/src/main/java/com/c2kernel/graph/model/Vertex.java b/src/main/java/com/c2kernel/graph/model/Vertex.java
new file mode 100644
index 0000000..ccef437
--- /dev/null
+++ b/src/main/java/com/c2kernel/graph/model/Vertex.java
@@ -0,0 +1,308 @@
+package com.c2kernel.graph.model;
+
+import java.awt.Polygon;
+import java.io.Serializable;
+import java.util.Vector;
+
+
+public class Vertex implements Serializable
+{
+ private int mId = -1;
+ private String mName = "";
+ private GraphPoint mCentrePoint = new GraphPoint(0, 0);
+ private int mHeight = 0;
+ private int mWidth = 0;
+ private Vector<Integer> mInEdgeIdVector = new Vector<Integer>();
+ private Vector<Integer> mOutEdgeIdVector = new Vector<Integer>();
+ private Vector<Object> mTags = new Vector<Object>();
+
+ // The Java Polygon class is used to determine if a point
+ // lies within the outline of a vertex. Unfortunately
+ // both the polygon and the set of outline points need to
+ // kept in memory because a polygon never has 0 points
+ // which is required by Castor's unmarshall object mechanism
+ private Polygon mOutlinePolygon = new Polygon();
+ private GraphPoint[] mOutlinePoints = new GraphPoint[0];
+
+
+ private GraphModel graphModel;
+
+ public void setID(int id)
+ {
+ mId = id;
+ }
+
+
+ public int getID()
+ {
+ return mId;
+ }
+
+
+ public void setName(String n)
+ {
+ mName = n;
+ }
+
+
+ public String getName()
+ {
+ return mName;
+ }
+
+
+ public void setCentrePoint(GraphPoint p)
+ {
+ mCentrePoint = p;
+ }
+
+
+ public GraphPoint getCentrePoint()
+ {
+ return mCentrePoint;
+ }
+
+
+ public void setHeight(int h)
+ {
+ mHeight = h;
+ }
+
+
+ public int getHeight()
+ {
+ return mHeight;
+ }
+
+
+ public void setWidth(int w)
+ {
+ mWidth = w;
+ }
+
+
+ public int getWidth()
+ {
+ return mWidth;
+ }
+
+
+ // Sets the outline points and re-calculates the
+ // height and width
+ public void setOutlinePoints(GraphPoint[] outline)
+ {
+ int topLeftX = outline[0].x;
+ int topLeftY = outline[0].y;
+ int bottomRightX = 0;
+ int bottomRightY = 0;
+ int i = 0;
+
+ mOutlinePoints = outline;
+
+ // Construct a polygon in the outline of the vertex
+ // and calculate the top left and bottom right corners
+ mOutlinePolygon = new Polygon();
+
+ for(i=0; i<outline.length; i++)
+ {
+ mOutlinePolygon.addPoint(outline[i].x, outline[i].y);
+
+ if(outline[i].x < topLeftX)
+ {
+ topLeftX = outline[i].x;
+ }
+
+ if(outline[i].y < topLeftY)
+ {
+ topLeftY = outline[i].y;
+ }
+
+ if(outline[i].x > bottomRightX)
+ {
+ bottomRightX = outline[i].x;
+ }
+
+
+ if(outline[i].y > bottomRightY)
+ {
+ bottomRightY = outline[i].y;
+ }
+ }
+
+ // Set the height and width
+ mHeight = bottomRightY - topLeftY;
+ mWidth = bottomRightX - topLeftX;
+ }
+
+
+ public GraphPoint[] getOutlinePoints()
+ {
+ return mOutlinePoints;
+ }
+
+ public void moveAbsolute(GraphPoint p)
+ {
+ int deltaX = p.x - mCentrePoint.x;
+ int deltaY = p.y - mCentrePoint.y;
+ int i = 0;
+
+ // Update the outline points and the polygon
+ for(i=0; i<mOutlinePoints.length; i++)
+ {
+ mOutlinePoints[i].x += deltaX;
+ mOutlinePoints[i].y += deltaY;
+ }
+
+ mOutlinePolygon.translate(deltaX, deltaY);
+
+ mCentrePoint.x = p.x;
+ mCentrePoint.y = p.y;
+ }
+
+
+ public boolean containsPoint(GraphPoint p)
+ {
+ return mOutlinePolygon.contains(p.x, p.y);
+ }
+
+
+ public void setInEdgeIds(int[] ids)
+ {
+ int i = 0;
+
+ mInEdgeIdVector = new Vector<Integer>(10, 10);
+ for(i=0; i<ids.length; i++)
+ mInEdgeIdVector.add(new Integer(ids[i]));
+ }
+
+
+ public int[] getInEdgeIds()
+ {
+ return integerVectorToIntArray(mInEdgeIdVector);
+ }
+
+
+ public void setOutEdgeIds(int[] ids)
+ {
+ int i = 0;
+
+ mOutEdgeIdVector = new Vector<Integer>(10, 10);
+ for(i=0; i<ids.length; i++)
+ mOutEdgeIdVector.add(new Integer(ids[i]));
+ }
+
+
+ public int[] getOutEdgeIds()
+ {
+ return integerVectorToIntArray(mOutEdgeIdVector);
+ }
+
+
+ private static int[] integerVectorToIntArray(Vector<Integer> vector)
+ {
+ int[] array = new int[vector.size()];
+ Integer integer = null;
+ int i = 0;
+
+ for(i=0; i<array.length; i++)
+ {
+ integer = vector.elementAt(i);
+ array[i] = integer.intValue();
+ }
+
+ return array;
+ }
+
+
+ public void addInEdgeId(int id)
+ {
+ mInEdgeIdVector.add(new Integer(id));
+ }
+
+
+ public void removeInEdgeId(int id)
+ {
+ Integer integer = null;
+ int i = 0;
+
+ for(i=0; i<mInEdgeIdVector.size(); i++)
+ {
+ integer = mInEdgeIdVector.elementAt(i);
+
+ if(integer.intValue() == id)
+ {
+ mInEdgeIdVector.removeElementAt(i);
+ return;
+ }
+ }
+ }
+
+
+ public void addOutEdgeId(int id)
+ {
+ mOutEdgeIdVector.add(new Integer(id));
+ }
+
+
+ public void removeOutEdgeId(int id)
+ {
+ Integer integer = null;
+ int i = 0;
+
+ for(i=0; i<mOutEdgeIdVector.size(); i++)
+ {
+ integer = mOutEdgeIdVector.elementAt(i);
+
+ if(integer.intValue() == id)
+ {
+ mOutEdgeIdVector.removeElementAt(i);
+ return;
+ }
+ }
+ }
+
+
+ public void setTag(Object o)
+ {
+ mTags.add(o);
+ }
+
+
+ public boolean hasTag(Object o)
+ {
+ return mTags.contains(o);
+ }
+
+ public void clearTag(Object o)
+ {
+ mTags.remove(o);
+ }
+
+
+ public GraphModel getChildGraphModel() {
+ return null;
+ }
+
+ public Object getCreationContext() {
+ return null;
+ }
+
+
+ public GraphModel getGraphModel()
+ {
+ return graphModel;
+ }
+
+ public void setGraphModel(GraphModel graphModel)
+ {
+ this.graphModel = graphModel;
+ }
+
+ public boolean isJoin() {
+ return false;
+ }
+ public boolean isLoop() {
+ return false;
+ }
+
+}
diff --git a/src/main/java/com/c2kernel/graph/model/VertexFactory.java b/src/main/java/com/c2kernel/graph/model/VertexFactory.java
new file mode 100644
index 0000000..550367e
--- /dev/null
+++ b/src/main/java/com/c2kernel/graph/model/VertexFactory.java
@@ -0,0 +1,16 @@
+package com.c2kernel.graph.model;
+
+import java.awt.Point;
+
+
+public interface VertexFactory
+{
+ public void create
+ (
+ GraphModelManager graphModelManager,
+ Point location,
+ TypeNameAndConstructionInfo typeNameAndConstructionInfo
+ );
+
+ public void setCreationContext(Object newContext);
+}
diff --git a/src/main/java/com/c2kernel/graph/model/VertexOutlineCreator.java b/src/main/java/com/c2kernel/graph/model/VertexOutlineCreator.java
new file mode 100644
index 0000000..627395e
--- /dev/null
+++ b/src/main/java/com/c2kernel/graph/model/VertexOutlineCreator.java
@@ -0,0 +1,10 @@
+package com.c2kernel.graph.model;
+
+
+
+// Classes that implement this interface must
+// have a parameter less constructor
+public interface VertexOutlineCreator
+{
+ public void setOutline(Vertex vertex);
+}
diff --git a/src/main/java/com/c2kernel/graph/traversal/GraphTraversal.java b/src/main/java/com/c2kernel/graph/traversal/GraphTraversal.java
new file mode 100644
index 0000000..0d9c819
--- /dev/null
+++ b/src/main/java/com/c2kernel/graph/traversal/GraphTraversal.java
@@ -0,0 +1,85 @@
+package com.c2kernel.graph.traversal;
+
+
+import java.util.Vector;
+
+import com.c2kernel.graph.model.GraphModel;
+import com.c2kernel.graph.model.Vertex;
+
+
+public class GraphTraversal
+{
+ public static final int kUp = 1;
+ public static final int kDown = 2;
+
+
+ private GraphTraversal()
+ {
+ }
+
+
+ public static Vertex[] getTraversal(GraphModel graphModel, Vertex startVertex, int direction, boolean ignoreBackLinks)
+ {
+ Vector<Vertex> path = new Vector<Vertex>(10, 10);
+
+ graphModel.clearTags(startVertex);
+ visitVertex(startVertex, graphModel, path, direction, startVertex, ignoreBackLinks);
+
+ return vectorToVertexArray(path);
+ }
+
+
+ private static void visitVertex(Vertex vertex, GraphModel graphModel, Vector<Vertex> path, int direction, Object tag, boolean ignoreBackLinks)
+ {
+ Vertex[] children = null;
+ int i = 0;
+
+ if(direction == kDown)
+ {
+ children = graphModel.getOutVertices(vertex);
+ }
+ else
+ {
+ children = graphModel.getInVertices(vertex);
+ }
+
+ vertex.setTag(tag);
+ path.add(vertex);
+
+ for(i=0; i<children.length; i++)
+ {
+ if(!(children[i].hasTag(tag)))
+ {
+ boolean skipBackLink = false;
+ if ( ignoreBackLinks &&
+ ((vertex.isJoin() && direction == kUp) ||
+ (vertex.isLoop() && direction == kDown))) {
+ Vertex[] following = getTraversal(graphModel, children[i], direction, false);
+ for (Vertex element : following) {
+ if (element == vertex) {
+ skipBackLink = true;
+ break;
+ }
+ }
+ }
+ if (!skipBackLink)
+ visitVertex(children[i], graphModel, path, direction, tag, ignoreBackLinks);
+ }
+ }
+ }
+
+
+ private static Vertex[] vectorToVertexArray(Vector<Vertex> vector)
+ {
+ Vertex[] vertices = new Vertex[vector.size()];
+ int i = 0;
+
+
+ for(i=0; i<vertices.length; i++)
+ {
+ vertices[i] = vector.elementAt(i);
+ }
+
+ return vertices;
+ }
+}
diff --git a/src/main/java/com/c2kernel/graph/view/DefaultDirectedEdgeRenderer.java b/src/main/java/com/c2kernel/graph/view/DefaultDirectedEdgeRenderer.java
new file mode 100644
index 0000000..2882141
--- /dev/null
+++ b/src/main/java/com/c2kernel/graph/view/DefaultDirectedEdgeRenderer.java
@@ -0,0 +1,75 @@
+package com.c2kernel.graph.view;
+
+import java.awt.Graphics2D;
+import java.awt.Paint;
+import java.awt.Shape;
+import java.awt.geom.AffineTransform;
+import java.awt.geom.GeneralPath;
+
+import com.c2kernel.graph.model.DirectedEdge;
+import com.c2kernel.graph.model.GraphPoint;
+
+
+public class DefaultDirectedEdgeRenderer implements DirectedEdgeRenderer
+{
+ private GeneralPath mArrowTemplate = new GeneralPath();
+ private Paint mLinePaint = null;
+
+
+ public DefaultDirectedEdgeRenderer(Paint linePaint)
+ {
+ mLinePaint = linePaint;
+
+ mArrowTemplate.moveTo(-5, 5);
+ mArrowTemplate.lineTo( 0, 0);
+ mArrowTemplate.lineTo( 5, 5);
+ }
+
+
+ @Override
+ public void draw(Graphics2D g2d, DirectedEdge directedEdge)
+ {
+ GraphPoint originPoint = directedEdge.getOriginPoint();
+ GraphPoint terminusPoint = directedEdge.getTerminusPoint();
+ GraphPoint midPoint = new GraphPoint();
+ AffineTransform transform = new AffineTransform();
+ Shape arrow = null;
+
+ g2d.setPaint(mLinePaint);
+ g2d.drawLine(originPoint.x, originPoint.y, terminusPoint.x, terminusPoint.y);
+
+ midPoint.x = originPoint.x + (terminusPoint.x - originPoint.x)/2;
+ midPoint.y = originPoint.y + (terminusPoint.y - originPoint.y)/2;
+
+ transform.translate(midPoint.x, midPoint.y);
+ transform.rotate(calcArrowAngle(originPoint.x, originPoint.y, terminusPoint.x, terminusPoint.y));
+
+ arrow = mArrowTemplate.createTransformedShape(transform);
+
+ g2d.draw(arrow);
+ }
+
+
+ private static double calcArrowAngle(int originX, int originY, int terminusX, int terminusY) {
+ double width = terminusX - originX;
+ double height = terminusY - originY;
+
+ if((width == 0) && (height > 0)) return Math.PI;
+
+ if((width == 0) && (height < 0)) return 0;
+
+ if((width > 0) && (height == 0)) return Math.PI/2.0;
+
+ if((width < 0) && (height == 0)) return -1.0 * Math.PI/2.0;
+
+ if((width > 0) && (height > 0)) return Math.PI/2.0 + Math.atan(Math.abs(height)/Math.abs(width));
+
+ if((width > 0) && (height < 0)) return Math.atan(Math.abs(width)/Math.abs(height));
+
+ if((width < 0) && (height < 0)) return -1.0 * Math.atan(Math.abs(width)/Math.abs(height));
+
+ if((width < 0) && (height > 0)) return -1.0 * (Math.PI/2.0 + Math.atan(Math.abs(height)/Math.abs(width)));
+
+ return 0.0;
+ }
+}
diff --git a/src/main/java/com/c2kernel/graph/view/DefaultVertexRenderer.java b/src/main/java/com/c2kernel/graph/view/DefaultVertexRenderer.java
new file mode 100644
index 0000000..e9b92d0
--- /dev/null
+++ b/src/main/java/com/c2kernel/graph/view/DefaultVertexRenderer.java
@@ -0,0 +1,60 @@
+package com.c2kernel.graph.view;
+
+import java.awt.FontMetrics;
+import java.awt.Graphics2D;
+import java.awt.Paint;
+import java.awt.Polygon;
+
+import com.c2kernel.graph.model.GraphPoint;
+import com.c2kernel.graph.model.Vertex;
+
+
+public class DefaultVertexRenderer implements VertexRenderer
+{
+ private Paint mLinePaint = null;
+ private Paint mTextPaint = null;
+ private Paint mFillPaint = null;
+
+
+ public DefaultVertexRenderer(Paint linePaint, Paint textPaint, Paint fillPaint)
+ {
+ mLinePaint = linePaint;
+ mTextPaint = textPaint;
+ mFillPaint = fillPaint;
+ }
+
+
+ @Override
+ public void draw(Graphics2D g2d, Vertex vertex)
+ {
+ GraphPoint[] outlinePoints = vertex.getOutlinePoints();
+ GraphPoint centrePoint = vertex.getCentrePoint();
+ Polygon outline = new Polygon();
+
+ String vertexName = vertex.getName();
+ FontMetrics metrics = g2d.getFontMetrics();
+ int textWidth = metrics.stringWidth(vertexName);
+ int textHeight = metrics.getHeight();
+ int textX = centrePoint.x - textWidth/2;
+ int textY = centrePoint.y + textHeight/3;
+
+ int i = 0;
+
+
+ // Construct a shape in the outline of the vertex
+ for(i=0; i<outlinePoints.length; i++)
+ {
+ outline.addPoint(outlinePoints[i].x, outlinePoints[i].y);
+ }
+
+ // Fill and then draw the outline
+ g2d.setPaint(mFillPaint);
+ g2d.fill(outline);
+ g2d.setPaint(mLinePaint);
+ g2d.draw(outline);
+
+ // Write the name of the vertex in the centre of the outline
+ g2d.setPaint(mTextPaint);
+ g2d.drawString(vertexName, textX, textY);
+ }
+}
diff --git a/src/main/java/com/c2kernel/graph/view/DirectedEdgeRenderer.java b/src/main/java/com/c2kernel/graph/view/DirectedEdgeRenderer.java
new file mode 100644
index 0000000..6937922
--- /dev/null
+++ b/src/main/java/com/c2kernel/graph/view/DirectedEdgeRenderer.java
@@ -0,0 +1,11 @@
+package com.c2kernel.graph.view;
+
+import java.awt.Graphics2D;
+
+import com.c2kernel.graph.model.DirectedEdge;
+
+
+public interface DirectedEdgeRenderer
+{
+ public void draw(Graphics2D g2d, DirectedEdge directedEdge);
+}
diff --git a/src/main/java/com/c2kernel/graph/view/EditorModeListener.java b/src/main/java/com/c2kernel/graph/view/EditorModeListener.java
new file mode 100644
index 0000000..c3a4a8a
--- /dev/null
+++ b/src/main/java/com/c2kernel/graph/view/EditorModeListener.java
@@ -0,0 +1,8 @@
+package com.c2kernel.graph.view;
+
+
+
+public interface EditorModeListener
+{
+ public void editorModeChanged(String idOfNewMode);
+}
diff --git a/src/main/java/com/c2kernel/graph/view/EditorPanel.java b/src/main/java/com/c2kernel/graph/view/EditorPanel.java
new file mode 100644
index 0000000..fb25b68
--- /dev/null
+++ b/src/main/java/com/c2kernel/graph/view/EditorPanel.java
@@ -0,0 +1,104 @@
+package com.c2kernel.graph.view;
+import java.awt.BorderLayout;
+import java.awt.Dimension;
+
+import javax.swing.JButton;
+import javax.swing.JPanel;
+import javax.swing.JScrollPane;
+
+import com.c2kernel.graph.controller.AutoScrollController;
+import com.c2kernel.graph.controller.EdgeConstructionController;
+import com.c2kernel.graph.controller.MultiSelectionDragController;
+import com.c2kernel.graph.controller.VertexConstructionController;
+import com.c2kernel.graph.model.EdgeFactory;
+import com.c2kernel.graph.model.GraphModelManager;
+import com.c2kernel.graph.model.TypeNameAndConstructionInfo;
+import com.c2kernel.graph.model.VertexFactory;
+import com.c2kernel.graph.model.VertexOutlineCreator;
+public class EditorPanel extends JPanel
+{
+ // Graph Model
+ public final GraphModelManager mGraphModelManager = new GraphModelManager();
+ // Graph View
+ public GraphPanel mGraphPanel = null;
+ protected JScrollPane mGraphScrollPane = null;
+ // Graph Controllers
+ protected MultiSelectionDragController mMultiSelectionDragController = new MultiSelectionDragController();
+ protected VertexConstructionController mVertexConstructionController = new VertexConstructionController();
+ protected EdgeConstructionController mEdgeConstructionController = new EdgeConstructionController();
+ protected AutoScrollController mAutoScrollController = new AutoScrollController();
+ // Tool bar
+ protected EditorToolBar mEditorToolBar = null;
+ protected EditorPanel()
+ {
+ }
+ public EditorPanel(EdgeFactory eFactory, VertexFactory vFactory, VertexOutlineCreator vOutlineCreator, boolean edgeCreationMode, // True
+ // if
+ // edges
+ // can
+ // be
+ // created
+ JButton[] otherButtons, GraphPanel graphPanel)
+ {
+ // Create the graph panel and editor tool bar
+ setDoubleBuffered(true);
+ mGraphPanel = graphPanel;
+ mGraphPanel.setGraphModelManager(mGraphModelManager);
+ mGraphScrollPane = new JScrollPane(mGraphPanel);
+ mGraphModelManager.setExternalEdgeFactory(eFactory);
+ mGraphModelManager.setExternalVertexFactory(vFactory);
+ mGraphModelManager.setVertexOutlineCreator(vOutlineCreator);
+ mEditorToolBar = new EditorToolBar(edgeCreationMode, otherButtons, graphPanel);
+ mEditorToolBar.setGraphModelManager(mGraphModelManager);
+ mEditorToolBar.setGraphPanel(mGraphPanel);
+ createLayout();
+ // The graph panel observes the graph model
+ mGraphModelManager.addObserver(mGraphPanel);
+ // The multi selection drag controller modifies the graph model
+ // and listens to the graph panel and editor tool bar
+ mMultiSelectionDragController.setGraphModelManager(mGraphModelManager);
+ mGraphPanel.addMouseListener(mMultiSelectionDragController);
+ mGraphPanel.addMouseMotionListener(mMultiSelectionDragController);
+ mGraphPanel.addKeyListener(mMultiSelectionDragController);
+ mEditorToolBar.addEditorModeListener(mMultiSelectionDragController);
+ // The edge construction controller modifies the graph model
+ // and listens to the graph panel and editor tool bar
+ mEdgeConstructionController.setGraphModelManager(mGraphModelManager);
+ mGraphPanel.addMouseListener(mEdgeConstructionController);
+ mGraphPanel.addMouseMotionListener(mEdgeConstructionController);
+ mEdgeConstructionController.setEditorToolBar(mEditorToolBar);
+ // The vertex construction controller modifies the graph model
+ // and listens to the graph panel and editor tool bar
+ mVertexConstructionController.setGraphModelManager(mGraphModelManager);
+ mGraphPanel.addMouseListener(mVertexConstructionController);
+ mVertexConstructionController.setEditorToolBar(mEditorToolBar);
+ // The auto scroll controller listens to and modifies the
+ // graph panel
+ mAutoScrollController.setGraphPanel(mGraphPanel);
+ }
+
+ protected void createLayout()
+ {
+ setLayout(new BorderLayout());
+ add(mEditorToolBar, BorderLayout.NORTH);
+ mGraphPanel.setPreferredSize(new Dimension(mGraphModelManager.getModel().getWidth(), mGraphModelManager.getModel().getHeight()));
+ add(mGraphScrollPane, BorderLayout.CENTER);
+ }
+ public void enterSelectMode()
+ {
+ mEditorToolBar.enterSelectMode();
+ }
+ public void updateEdgeTypes(TypeNameAndConstructionInfo[] typeNameAndConstructionInfo)
+ {
+ mEditorToolBar.updateEdgeTypes(typeNameAndConstructionInfo);
+ }
+ public void updateVertexTypes(TypeNameAndConstructionInfo[] typeNameAndConstructionInfo)
+ {
+ mEditorToolBar.updateVertexTypes(typeNameAndConstructionInfo);
+ }
+ public void setEditable(boolean editable)
+ {
+ mGraphModelManager.setEditable(editable);
+ mEditorToolBar.setGraphEditable(editable);
+ }
+}
diff --git a/src/main/java/com/c2kernel/graph/view/EditorToolBar.java b/src/main/java/com/c2kernel/graph/view/EditorToolBar.java
new file mode 100644
index 0000000..61c7409
--- /dev/null
+++ b/src/main/java/com/c2kernel/graph/view/EditorToolBar.java
@@ -0,0 +1,346 @@
+package com.c2kernel.graph.view;
+import java.awt.Dimension;
+import java.awt.Graphics;
+import java.awt.Graphics2D;
+import java.awt.Image;
+import java.awt.Insets;
+import java.awt.Toolkit;
+import java.awt.datatransfer.Clipboard;
+import java.awt.datatransfer.ClipboardOwner;
+import java.awt.datatransfer.DataFlavor;
+import java.awt.datatransfer.Transferable;
+import java.awt.datatransfer.UnsupportedFlavorException;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.print.PageFormat;
+import java.awt.print.Printable;
+import java.awt.print.PrinterException;
+import java.awt.print.PrinterJob;
+import java.util.Vector;
+
+import javax.swing.Box;
+import javax.swing.BoxLayout;
+import javax.swing.ButtonGroup;
+import javax.swing.JButton;
+import javax.swing.JComboBox;
+import javax.swing.JToggleButton;
+
+import com.c2kernel.graph.controller.DeletionController;
+import com.c2kernel.graph.controller.StartVertexController;
+import com.c2kernel.graph.model.GraphModelManager;
+import com.c2kernel.graph.model.TypeNameAndConstructionInfo;
+import com.c2kernel.utils.Language;
+import com.c2kernel.utils.Logger;
+import com.c2kernel.utils.Resource;
+/**
+ * Tool bar with mode toggle buttons, start and delete buttons, and the possibility to add other arbitrary buttons at constructions time.
+ */
+public class EditorToolBar extends Box implements Printable
+{
+ protected boolean mEdgeCreationMode = false; // True if edges can be created
+ protected GraphPanel mGraphPanel = null;
+ // There is on mode button listener per mode button.
+ // When a mode button fires anaction performed event
+ // its corresponding listener notifies all of the
+ // editor mode listeners.
+ protected class ModeButtonListener implements ActionListener
+ {
+ protected String mModeId = null;
+ public ModeButtonListener(String modeId)
+ {
+ mModeId = modeId;
+ }
+ @Override
+ public void actionPerformed(ActionEvent ae)
+ {
+ notifyListeners(mModeId);
+ }
+ }
+ // Vertex types and ids
+ protected JComboBox mVertexTypeBox = new JComboBox();
+ // Edge types and ids
+ protected JComboBox mEdgeTypeBox = new JComboBox();
+ // Mode buttons
+ protected ButtonGroup mModeButtonGroup = new ButtonGroup();
+ protected JToggleButton mVertexModeButton = new JToggleButton(Resource.findImage("graph/newvertex.png"));
+ protected JToggleButton mSelectModeButton = new JToggleButton(Resource.findImage("graph/selection.gif"));
+ protected JToggleButton mEdgeModeButton = new JToggleButton(Resource.findImage("graph/edge.png"));
+ // Normal buttons
+ protected JButton[] mOtherButtons = null;
+ protected JButton mStartButton = new JButton(Resource.findImage("graph/start.png"));
+ protected JButton mDeleteButton = new JButton(Resource.findImage("graph/delete.png"));
+ protected JButton mPrintButton = new JButton(Resource.findImage("graph/print.png"));
+ protected JButton mCopyButton = new JButton(Resource.findImage("graph/copy.png"));
+ // Controllers
+ protected StartVertexController mStartVertexController = new StartVertexController();
+ protected DeletionController mDeletionController = new DeletionController();
+ // Editor mode listeners
+ protected Vector<EditorModeListener> mListenerVector = new Vector<EditorModeListener>(10, 10);
+ public EditorToolBar(boolean edgeCreationMode, // True if edges can be created
+ JButton[] otherButtons, GraphPanel graphP)
+ {
+ super(BoxLayout.X_AXIS);
+ mGraphPanel = graphP;
+ mEdgeCreationMode = edgeCreationMode;
+ mOtherButtons = otherButtons;
+ prepareModeButtons();
+ mStartVertexController.setStartButton(mStartButton);
+ mDeletionController.setDeleteButton(mDeleteButton);
+ createLayout();
+ createListeners();
+ }
+ protected void prepareModeButtons()
+ {
+ // Set the tool tip texts
+ mVertexModeButton.setToolTipText(Language.translate("Create vertex"));
+ mSelectModeButton.setToolTipText(Language.translate("Multi-select and drag"));
+ mEdgeModeButton.setToolTipText(Language.translate("Create edge"));
+ mStartButton.setToolTipText(Language.translate("Select the start vertex of the graph"));
+ mDeleteButton.setToolTipText(Language.translate("Delete the selection"));
+ mPrintButton.setToolTipText(Language.translate("Print this graph"));
+ mPrintButton.setToolTipText(Language.translate("Copy an image of this graph to the clipboard"));
+ // Set the button margins to 0
+ mVertexModeButton.setMargin(new Insets(0, 0, 0, 0));
+ mSelectModeButton.setMargin(new Insets(0, 0, 0, 0));
+ mEdgeModeButton.setMargin(new Insets(0, 0, 0, 0));
+ // The initial mode is select mode
+ mSelectModeButton.setSelected(true);
+ // Add the mode buttons to the mode button group
+ mModeButtonGroup.add(mVertexModeButton);
+ mModeButtonGroup.add(mSelectModeButton);
+ mModeButtonGroup.add(mEdgeModeButton);
+ // Add the action listeners
+ mVertexModeButton.addActionListener(new ModeButtonListener("Vertex"));
+ mSelectModeButton.addActionListener(new ModeButtonListener("Select"));
+ mEdgeModeButton.addActionListener(new ModeButtonListener("Edge"));
+ }
+ public void enterSelectMode()
+ {
+ mSelectModeButton.setSelected(true);
+ notifyListeners("Select");
+ }
+ public void updateVertexTypes(TypeNameAndConstructionInfo[] typeNameAndConstructionInfo)
+ {
+ int i = 0;
+ mVertexTypeBox.removeAllItems();
+ for (i = 0; i < typeNameAndConstructionInfo.length; i++)
+ {
+ mVertexTypeBox.addItem(typeNameAndConstructionInfo[i]);
+ }
+ }
+ public void updateEdgeTypes(TypeNameAndConstructionInfo[] typeNameAndConstructionInfo)
+ {
+ int i = 0;
+ mEdgeTypeBox.removeAllItems();
+ for (i = 0; i < typeNameAndConstructionInfo.length; i++)
+ {
+ mEdgeTypeBox.addItem(typeNameAndConstructionInfo[i]);
+ }
+ }
+ public TypeNameAndConstructionInfo getSelectedVertexType()
+ {
+ return (TypeNameAndConstructionInfo) mVertexTypeBox.getSelectedItem();
+ }
+ public TypeNameAndConstructionInfo getSelectedEdgeType()
+ {
+ return (TypeNameAndConstructionInfo) mEdgeTypeBox.getSelectedItem();
+ }
+ protected void createLayout()
+ {
+ int i = 0;
+ add(mSelectModeButton);
+ add(mVertexModeButton);
+ add(mVertexTypeBox);
+ add(Box.createHorizontalStrut(10));
+ if (mEdgeCreationMode)
+ {
+ add(mEdgeModeButton);
+ add(mEdgeTypeBox);
+ }
+ add(Box.createGlue());
+ mPrintButton.setEnabled(true);
+ mPrintButton.setMargin(new Insets(0, 0, 0, 0));
+ add(mPrintButton);
+ mCopyButton.setEnabled(true);
+ mCopyButton.setMargin(new Insets(0, 0, 0, 0));
+ add(mCopyButton);
+ mStartButton.setEnabled(false);
+ mStartButton.setMargin(new Insets(0, 0, 0, 0));
+ mDeleteButton.setEnabled(false);
+ mDeleteButton.setMargin(new Insets(0, 0, 0, 0));
+ add(mDeleteButton);
+ add(Box.createRigidArea(new Dimension(20, 0)));
+ add(mStartButton);
+ if (mOtherButtons != null)
+ {
+ for (i = 0; i < mOtherButtons.length; i++)
+ {
+ mOtherButtons[i].setMargin(new Insets(0, 0, 0, 0));
+ add(mOtherButtons[i]);
+ }
+ }
+ }
+ protected void createListeners()
+ {
+ // The vertex mode button should be selected if the
+ // user select a vertex type from the vertex type box
+ mVertexTypeBox.addActionListener(new ActionListener()
+ {
+ @Override
+ public void actionPerformed(ActionEvent ae)
+ {
+ mVertexModeButton.setSelected(true);
+ notifyListeners("Vertex");
+ }
+ });
+ // The edge mode button should be selected if the
+ // user select an edge type from the edge type box
+ mEdgeTypeBox.addActionListener(new ActionListener()
+ {
+ @Override
+ public void actionPerformed(ActionEvent ae)
+ {
+ mEdgeModeButton.setSelected(true);
+ notifyListeners("Edge");
+ }
+ });
+ mPrintButton.addActionListener(new ActionListener()
+ {
+ @Override
+ public void actionPerformed(ActionEvent ae)
+ {
+ PrinterJob _monJob = PrinterJob.getPrinterJob();
+ if (_monJob.printDialog())
+ _monJob.setPrintable(self());
+ try
+ {
+ _monJob.print();
+ }
+ catch (Exception ex)
+ {
+ }
+ }
+ });
+
+ try {
+ Class.forName("java.awt.datatransfer.DataFlavor").getDeclaredField("imageFlavor");
+ mCopyButton.addActionListener(new ActionListener()
+ {
+ @Override
+ public void actionPerformed(ActionEvent ae)
+ {
+ try
+ {
+ Image i = createImage(mGraphPanel.getWidth(),mGraphPanel.getHeight());
+ Graphics g = i.getGraphics();
+ mGraphPanel.paintComponent(g);
+ ImageTransferable it = new ImageTransferable(i, mGraphPanel.getWidth(), mGraphPanel.getHeight());
+ Toolkit.getDefaultToolkit().getSystemClipboard().setContents(it, it);
+ }
+ catch (Exception e)
+ {
+ Logger.error(e);
+ }
+ }
+ });
+ } catch (Exception ex) { //image clipboard transfer not supported
+ mCopyButton.setEnabled(false);
+ }
+ }
+
+ protected class ImageTransferable implements Transferable, ClipboardOwner {
+ Image image;
+ int width,height;
+ DataFlavor javaImg;
+ public ImageTransferable(Image image, int width, int height) {
+ this.image = image;
+ this.width = width;
+ this.height = height;
+ try {
+ javaImg = new DataFlavor("image/x-java-image; class=java.awt.Image", "AWT Image");
+ } catch (Exception ex){ }
+ }
+ @Override
+ public Object getTransferData(DataFlavor flavor) throws UnsupportedFlavorException {
+ if (!isDataFlavorSupported(flavor) || image == null) {
+ throw new UnsupportedFlavorException(flavor);
+ }
+ return image;
+ }
+
+ @Override
+ public boolean isDataFlavorSupported(DataFlavor flavor) {
+ boolean result = in(flavor, getTransferDataFlavors());
+ return result;
+ }
+
+ @Override
+ public DataFlavor[] getTransferDataFlavors() {
+ return new DataFlavor[] { javaImg };
+ }
+ protected boolean in(DataFlavor flavor, DataFlavor[] flavors) {
+ int f = 0;
+ while ((f < flavors.length) && !flavor.equals(flavors[f])) {
+ f++;
+ }
+ return f < flavors.length;
+ }
+ @Override
+ public void lostOwnership(Clipboard clipboard, Transferable contents) {
+ image = null;
+ }
+ }
+
+ protected void notifyListeners(String newModeId)
+ {
+ int i = 0;
+ EditorModeListener listener = null;
+ for (i = 0; i < mListenerVector.size(); i++)
+ {
+ listener = mListenerVector.elementAt(i);
+ listener.editorModeChanged(newModeId);
+ }
+ }
+ public void setGraphModelManager(GraphModelManager graphModelManager)
+ {
+ mStartVertexController.setGraphModelManager(graphModelManager);
+ mDeletionController.setGraphModelManager(graphModelManager);
+ }
+ public void setGraphPanel(GraphPanel graphPanel)
+ {
+ graphPanel.addKeyListener(mDeletionController);
+ }
+ public void addEditorModeListener(EditorModeListener listener)
+ {
+ mListenerVector.add(listener);
+ }
+ public void removeEditorModeListener(EditorModeListener listener)
+ {
+ mListenerVector.remove(listener);
+ }
+ public void setGraphEditable(boolean editable)
+ {
+ mVertexModeButton.setEnabled(editable);
+ mEdgeModeButton.setEnabled(editable);
+ }
+ public EditorToolBar self()
+ {
+ return this;
+ }
+ @Override
+ public int print(Graphics g, PageFormat pf, int i) throws PrinterException
+ {
+ if (i >= 1)
+ {
+ return Printable.NO_SUCH_PAGE;
+ }
+ Graphics2D g2d = (Graphics2D) g;
+ double scalex = pf.getImageableWidth() / mGraphPanel.getWidth();
+ double scaley = pf.getImageableHeight() / mGraphPanel.getHeight();
+ double scale = Math.min(Math.min(scalex, scaley), 1);
+ g2d.translate(pf.getImageableX(), pf.getImageableY());
+ g2d.scale(scale, scale);
+ mGraphPanel.printComponent(g2d);
+ return Printable.PAGE_EXISTS;
+ }
+}
diff --git a/src/main/java/com/c2kernel/graph/view/GraphPanel.java b/src/main/java/com/c2kernel/graph/view/GraphPanel.java
new file mode 100644
index 0000000..012fe25
--- /dev/null
+++ b/src/main/java/com/c2kernel/graph/view/GraphPanel.java
@@ -0,0 +1,272 @@
+package com.c2kernel.graph.view;
+import java.awt.BasicStroke;
+import java.awt.Color;
+import java.awt.Dimension;
+import java.awt.Graphics;
+import java.awt.Graphics2D;
+import java.awt.Image;
+import java.awt.Paint;
+import java.awt.Point;
+import java.awt.event.MouseAdapter;
+import java.awt.event.MouseEvent;
+import java.util.Observable;
+import java.util.Observer;
+
+import javax.swing.JPanel;
+
+import com.c2kernel.graph.event.EntireModelChangedEvent;
+import com.c2kernel.graph.event.GraphModelResizedEvent;
+import com.c2kernel.graph.model.DirectedEdge;
+import com.c2kernel.graph.model.ElasticBand;
+import com.c2kernel.graph.model.GraphModelManager;
+import com.c2kernel.graph.model.GraphPoint;
+import com.c2kernel.graph.model.Selection;
+import com.c2kernel.graph.model.Vertex;
+import com.c2kernel.utils.Resource;
+public class GraphPanel extends JPanel implements Observer
+{
+ protected final Paint mSelectionPaint = Color.black;
+ protected final Paint mStartPaint = Color.green;
+ protected final Image mResizePadImg = Resource.findImage("graph/resizepad.gif").getImage();
+ protected final BasicStroke mDashed =
+ new BasicStroke(1.0f, BasicStroke.CAP_BUTT, BasicStroke.JOIN_MITER, 10.0f, new float[] { 5.0f }, 0.0f);
+ protected GraphModelManager mGraphModelManager = null;
+ protected VertexRenderer mVertexRenderer = null;
+ protected DirectedEdgeRenderer mDirectedEdgeRenderer = null;
+ public GraphPanel(DirectedEdgeRenderer eRenderer, VertexRenderer vRenderer)
+ {
+ mVertexRenderer = vRenderer;
+ mDirectedEdgeRenderer = eRenderer;
+ // Request the keyboard focus if the mouse
+ // is pressed on the graph panel
+ addMouseListener(new MouseAdapter()
+ {
+ @Override
+ public void mousePressed(MouseEvent me)
+ {
+ requestFocus();
+ }
+ });
+ }
+ public void setGraphModelManager(GraphModelManager graphModelManager)
+ {
+ mGraphModelManager = graphModelManager;
+ }
+ @Override
+ public void update(Observable o, Object arg)
+ {
+ if (arg instanceof GraphModelResizedEvent || arg instanceof EntireModelChangedEvent)
+ {
+ setPreferredSize(new Dimension(mGraphModelManager.getModel().getWidth(), mGraphModelManager.getModel().getHeight()));
+ revalidate();
+ }
+ repaint();
+ }
+ @Override
+ public void paintComponent(Graphics g)
+ {
+ Graphics2D g2d = (Graphics2D) g;
+ DirectedEdge[] edges = null;
+ Vertex[] vertices = null;
+ Vertex startVertex = null;
+ Selection selection = null;
+ ElasticBand elasticBand = null;
+ Vertex newEdgeOriginVertex = null;
+ GraphPoint newEdgeOriginPoint = null;
+ Point newEdgeEndPoint = null;
+ GraphPoint vertexCentre = null;
+ int i = 0;
+ super.paintComponent(g);
+ if (mGraphModelManager != null)
+ {
+ // Get the edges and vertices from the model
+ edges = mGraphModelManager.getModel().getEdges();
+ vertices = mGraphModelManager.getModel().getVertices();
+ //graphable = mGraphModelManager.getModel().
+ // Draw the edges
+ for (i = 0; i < edges.length; i++)
+ {
+ mDirectedEdgeRenderer.draw(g2d, edges[i]);
+ }
+ // Draw the vertices
+ for (i = 0; i < vertices.length; i++)
+ {
+ mVertexRenderer.draw(g2d, vertices[i]);
+ }
+ g2d.setPaint(mStartPaint);
+ // Highlight the start vertex if there is one
+ startVertex = mGraphModelManager.getModel().getStartVertex();
+ if (startVertex != null)
+ {
+ drawVertexHighlight(g2d, startVertex, 1);
+ }
+ // Get the present selection
+ selection = mGraphModelManager.getModel().getSelection();
+ g2d.setPaint(mSelectionPaint);
+ // Draw the outline of the selected
+ // vertices if there are any
+ if (selection.mVertices != null)
+ {
+ g2d.setStroke(mDashed);
+ for (i = 0; i < selection.mVertices.length; i++)
+ {
+ if (selection.mVertices[i] != mGraphModelManager.getModel().getContainingVertex())
+ drawVertexHighlight(g2d, selection.mVertices[i], 5);
+ }
+ // Draw the resize pads if there is one and only one vertex selected
+ if (selection.mVertices.length == 1 &&
+ selection.mVertices[0] != mGraphModelManager.getModel().getContainingVertex())
+ {
+ vertexCentre = selection.mVertices[0].getCentrePoint();
+ g2d.drawImage(
+ mResizePadImg,
+ vertexCentre.x + selection.mVertices[0].getWidth() / 2,
+ vertexCentre.y + selection.mVertices[0].getHeight() / 2,
+ this);
+ }
+ }
+ // Draw the outline of the selected
+ // edge if there is one
+ if (selection.mEdge != null)
+ {
+ drawEdgeHighlight(g2d, selection.mEdge);
+ }
+ // Get the elastic band
+ elasticBand = mGraphModelManager.getModel().getElasticBand();
+ // Draw the elastic band if there
+ // is one
+ if (elasticBand != null)
+ {
+ g2d.drawLine(
+ elasticBand.mFixedCorner.x,
+ elasticBand.mFixedCorner.y,
+ elasticBand.mMovingCorner.x,
+ elasticBand.mFixedCorner.y);
+ g2d.drawLine(
+ elasticBand.mMovingCorner.x,
+ elasticBand.mFixedCorner.y,
+ elasticBand.mMovingCorner.x,
+ elasticBand.mMovingCorner.y);
+ g2d.drawLine(
+ elasticBand.mMovingCorner.x,
+ elasticBand.mMovingCorner.y,
+ elasticBand.mFixedCorner.x,
+ elasticBand.mMovingCorner.y);
+ g2d.drawLine(
+ elasticBand.mFixedCorner.x,
+ elasticBand.mMovingCorner.y,
+ elasticBand.mFixedCorner.x,
+ elasticBand.mFixedCorner.y);
+ }
+ // Draw the new edge under construction if there is one
+ newEdgeEndPoint = mGraphModelManager.getModel().getNewEdgeEndPoint();
+ newEdgeOriginVertex = mGraphModelManager.getModel().getNewEdgeOriginVertex();
+ if ((newEdgeEndPoint != null) && (newEdgeOriginVertex != null))
+ {
+ newEdgeOriginPoint = newEdgeOriginVertex.getCentrePoint();
+ g2d.setPaint(Color.black);
+ g2d.drawLine(newEdgeOriginPoint.x, newEdgeOriginPoint.y, newEdgeEndPoint.x, newEdgeEndPoint.y);
+ }
+ }
+ }
+ // Draws the highlight of the specified vertex the specified dist from its outline
+ protected void drawVertexHighlight(Graphics2D g2d, Vertex vertex, int dist)
+ {
+ GraphPoint[] outlinePoints = vertex.getOutlinePoints();
+ GraphPoint centrePoint = vertex.getCentrePoint();
+ int i = 0;
+ /*
+ * float dash1[] ={5.0f}; BasicStroke bs = new BasicStroke(5.0f, BasicStroke.CAP_BUTT,BasicStroke.JOIN_ROUND,10.0f, dash1,0.0f);
+ */
+ for (i = 0; i < outlinePoints.length - 1; i++)
+ {
+ drawShiftedLine(dist, g2d, centrePoint, outlinePoints[i].x, outlinePoints[i].y, outlinePoints[i + 1].x, outlinePoints[i + 1].y);
+ }
+ drawShiftedLine(
+ dist,
+ g2d,
+ centrePoint,
+ outlinePoints[outlinePoints.length - 1].x,
+ outlinePoints[outlinePoints.length - 1].y,
+ outlinePoints[0].x,
+ outlinePoints[0].y);
+ }
+ // Draws the specifed line the specified distance away from the specified centre point
+ private static void drawShiftedLine(int dist, Graphics2D g2d, GraphPoint centrePoint, int x1, int y1, int x2, int y2)
+ {
+ if (x1 > centrePoint.x)
+ x1 += dist;
+ if (x1 < centrePoint.x)
+ x1 -= dist;
+ if (y1 > centrePoint.y)
+ y1 += dist;
+ if (y1 < centrePoint.y)
+ y1 -= dist;
+ if (x2 > centrePoint.x)
+ x2 += dist;
+ if (x2 < centrePoint.x)
+ x2 -= dist;
+ if (y2 > centrePoint.y)
+ y2 += dist;
+ if (y2 < centrePoint.y)
+ y2 -= dist;
+ g2d.drawLine(x1, y1, x2, y2);
+ }
+ // Draws the highlight of the specified edge
+ protected void drawEdgeHighlight(Graphics2D g2d, DirectedEdge edge)
+ {
+ GraphPoint originPoint = edge.getOriginPoint();
+ GraphPoint terminusPoint = edge.getTerminusPoint();
+ int midX = originPoint.x + (terminusPoint.x - originPoint.x) / 2;
+ int midY = originPoint.y + (terminusPoint.y - originPoint.y) / 2;
+ int minX = midX - 10;
+ int minY = midY - 10;
+ int maxX = midX + 10;
+ int maxY = midY + 10;
+ g2d.drawLine(minX, minY, maxX, minY);
+ g2d.drawLine(maxX, minY, maxX, maxY);
+ g2d.drawLine(maxX, maxY, minX, maxY);
+ g2d.drawLine(minX, maxY, minX, minY);
+ }
+ @Override
+ public void printComponent(Graphics g)
+ {
+ super.paintComponent(g);
+ Graphics2D g2d = (Graphics2D) g;
+ DirectedEdge[] edges = null;
+ Vertex[] vertices = null;
+ Vertex startVertex = null;
+ int i = 0;
+ g.setColor(Color.white);
+ g2d.fillRect(0,0,getWidth(),getHeight());
+ if (mGraphModelManager != null)
+ {
+ // Get the edges and vertices from the model
+ edges = mGraphModelManager.getModel().getEdges();
+ vertices = mGraphModelManager.getModel().getVertices();
+ //graphable = mGraphModelManager.getModel().
+ // Draw the edges
+ for (i = 0; i < edges.length; i++)
+ {
+ mDirectedEdgeRenderer.draw(g2d, edges[i]);
+ }
+ // Draw the vertices
+ for (i = 0; i < vertices.length; i++)
+ {
+ mVertexRenderer.draw(g2d, vertices[i]);
+ }
+ g2d.setPaint(mStartPaint);
+ // Highlight the start vertex if there is one
+ startVertex = mGraphModelManager.getModel().getStartVertex();
+ if (startVertex != null)
+ {
+ drawVertexHighlight(g2d, startVertex, 1);
+ }
+ }
+ }
+
+ protected void superPaint(Graphics g)
+ {
+ super.paintComponent(g);
+ }
+}
diff --git a/src/main/java/com/c2kernel/graph/view/PropertyTable.java b/src/main/java/com/c2kernel/graph/view/PropertyTable.java
new file mode 100644
index 0000000..c1257aa
--- /dev/null
+++ b/src/main/java/com/c2kernel/graph/view/PropertyTable.java
@@ -0,0 +1,40 @@
+package com.c2kernel.graph.view;
+
+import javax.swing.JTable;
+import javax.swing.table.TableCellEditor;
+import javax.swing.table.TableCellRenderer;
+
+
+public class PropertyTable extends JTable
+{
+ public PropertyTable(PropertyTableModel tableModel)
+ {
+ super(tableModel);
+ }
+
+
+ @Override
+ public TableCellRenderer getCellRenderer(int row, int column) {
+
+
+ return getDefaultRenderer(getCellClass(row, column));
+
+ }
+
+ @Override
+public TableCellEditor getCellEditor(int row, int column) {
+
+ return getDefaultEditor(getCellClass(row, column));
+
+ }
+
+ private Class<?> getCellClass(int row, int column) {
+ Class<?> cellClass = String.class;
+
+ try {
+ cellClass = dataModel.getValueAt(row, column).getClass();
+ } catch (NullPointerException ex) { }
+
+ return cellClass;
+ }
+}
diff --git a/src/main/java/com/c2kernel/graph/view/PropertyTableModel.java b/src/main/java/com/c2kernel/graph/view/PropertyTableModel.java
new file mode 100644
index 0000000..b1e69b1
--- /dev/null
+++ b/src/main/java/com/c2kernel/graph/view/PropertyTableModel.java
@@ -0,0 +1,135 @@
+package com.c2kernel.graph.view;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.HashMap;
+
+import javax.swing.JOptionPane;
+import javax.swing.event.TableModelEvent;
+import javax.swing.table.AbstractTableModel;
+
+import com.c2kernel.utils.Language;
+
+/**************************************************************************
+ *
+ * $Revision: 1.4 $
+ * $Date: 2005/08/02 07:50:10 $
+ *
+ * Copyright (C) 2003 CERN - European Organization for Nuclear Research
+ * All rights reserved.
+ **************************************************************************/
+
+public class PropertyTableModel extends AbstractTableModel {
+
+ private String[] mColumnNames = { Language.translate("Name"), Language.translate("Value") };
+ HashMap<String, Object> sourceMap = new HashMap<String, Object>();
+ ArrayList<String> sortedNameList = new ArrayList<String>();
+ boolean isEditable = false;
+
+ public PropertyTableModel() {
+ super();
+ }
+
+ @Override
+ public int getColumnCount()
+ {
+ return mColumnNames.length;
+ }
+ @Override
+ public String getColumnName(int col)
+ {
+ return mColumnNames[col];
+ }
+ @Override
+ public int getRowCount()
+ {
+ synchronized (sourceMap) {
+ return sourceMap.size();
+ }
+ }
+ @Override
+ public Object getValueAt(int rowIndex, int colIndex)
+ {
+ synchronized (sourceMap) {
+ String rowName = sortedNameList.get(rowIndex);
+ if (colIndex == 0)
+ return rowName;
+ else
+ return sourceMap.get(rowName);
+ }
+ }
+
+ @Override
+ public void setValueAt(Object value, int rowIndex, int colIndex)
+ {
+ synchronized (sourceMap) {
+ if (colIndex == 0) return;
+ String rowName = sortedNameList.get(rowIndex);
+ Class<? extends Object> oldElement = sourceMap.get(rowName).getClass();
+ if (oldElement == Float.class && value.getClass() == String.class)
+ try {
+ value = Float.valueOf((String)value);
+ } catch (Exception ex) { }
+ if (value.getClass() != oldElement)
+ JOptionPane.showMessageDialog(null, "This property should contain a "+oldElement.getName()+" not a "+value.getClass().getName(), "Incorrect datatype", JOptionPane.ERROR_MESSAGE);
+ else {
+ sourceMap.put(rowName, value);
+ fireTableCellUpdated(rowIndex, colIndex);
+ }
+ }
+ }
+
+ public void setMap(HashMap<String, Object> props) {
+ synchronized (sourceMap) {
+ sourceMap = props;
+ sortedNameList = new ArrayList<String>(props.size());
+ for (String string : props.keySet())
+ sortedNameList.add(string);
+
+ Collections.sort(sortedNameList, new Comparator<String>() {
+ @Override
+ public int compare(String o1, String o2) {
+ return (o1.compareToIgnoreCase(o2));
+ }
+ });
+ }
+ fireTableChanged(new TableModelEvent(this));
+ }
+
+ @Override
+ public boolean isCellEditable(int row, int col)
+ {
+ return col==1 && isEditable;
+ }
+
+ /**
+ * @return Returns the isEditable.
+ */
+ public boolean isEditable() {
+ return isEditable;
+ }
+ /**
+ * @param isEditable The isEditable to set.
+ */
+ public void setEditable(boolean isEditable) {
+ this.isEditable = isEditable;
+ }
+
+ /**
+ * @param text
+ * @param object
+ */
+ public void addProperty(String text, Object object) {
+ sourceMap.put(text,object);
+ setMap(sourceMap);
+ }
+
+ /**
+ * @param object
+ */
+ public void delProperty(Object propName) {
+ sourceMap.remove(propName);
+ setMap(sourceMap);
+ }
+}
diff --git a/src/main/java/com/c2kernel/graph/view/SelectedVertexPanel.java b/src/main/java/com/c2kernel/graph/view/SelectedVertexPanel.java
new file mode 100644
index 0000000..966f527
--- /dev/null
+++ b/src/main/java/com/c2kernel/graph/view/SelectedVertexPanel.java
@@ -0,0 +1,27 @@
+package com.c2kernel.graph.view;
+
+import javax.swing.JPanel;
+
+import com.c2kernel.graph.model.Vertex;
+
+/**************************************************************************
+ *
+ * $Revision: 1.1 $
+ * $Date: 2005/05/12 10:12:52 $
+ *
+ * Copyright (C) 2003 CERN - European Organization for Nuclear Research
+ * All rights reserved.
+ **************************************************************************/
+
+
+
+public abstract class SelectedVertexPanel extends JPanel {
+
+ public SelectedVertexPanel() {
+ super();
+ }
+
+ public abstract void select(Vertex vert);
+
+ public abstract void clear();
+}
diff --git a/src/main/java/com/c2kernel/graph/view/VertexPropertyPanel.java b/src/main/java/com/c2kernel/graph/view/VertexPropertyPanel.java
new file mode 100644
index 0000000..4e3e711
--- /dev/null
+++ b/src/main/java/com/c2kernel/graph/view/VertexPropertyPanel.java
@@ -0,0 +1,259 @@
+package com.c2kernel.graph.view;
+
+import java.awt.GridBagConstraints;
+import java.awt.GridBagLayout;
+import java.awt.Insets;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.lang.reflect.Constructor;
+import java.util.HashMap;
+import java.util.Observable;
+import java.util.Observer;
+
+import javax.swing.Box;
+import javax.swing.JButton;
+import javax.swing.JComboBox;
+import javax.swing.JLabel;
+import javax.swing.JOptionPane;
+import javax.swing.JPanel;
+import javax.swing.JScrollPane;
+import javax.swing.JTextField;
+import javax.swing.event.TableModelEvent;
+import javax.swing.event.TableModelListener;
+
+import com.c2kernel.graph.event.EntireModelChangedEvent;
+import com.c2kernel.graph.event.SelectionChangedEvent;
+import com.c2kernel.graph.model.DirectedEdge;
+import com.c2kernel.graph.model.GraphModelManager;
+import com.c2kernel.graph.model.GraphableEdge;
+import com.c2kernel.graph.model.GraphableVertex;
+import com.c2kernel.graph.model.Vertex;
+import com.c2kernel.gui.tabs.EntityTabPane;
+import com.c2kernel.utils.Language;
+import com.c2kernel.utils.Logger;
+
+/**************************************************************************
+ *
+ * $Revision: 1.4 $
+ * $Date: 2005/09/09 12:19:28 $
+ *
+ * Copyright (C) 2003 CERN - European Organization for Nuclear Research
+ * All rights reserved.
+ **************************************************************************/
+
+public class VertexPropertyPanel extends JPanel implements Observer, TableModelListener, ActionListener {
+
+ private final PropertyTableModel mPropertyModel;
+ private final PropertyTable mPropertyTable;
+ private GraphModelManager mGraphModelManager;
+ private boolean isEditable = false;
+ GridBagLayout gridbag = new GridBagLayout();
+ protected JLabel selObjName;
+ protected JLabel selObjClass;
+ JButton addPropButton;
+ JButton delPropButton;
+ Box newPropBox;
+ private JTextField newPropName;
+ private JComboBox newPropType;
+ String[] typeOptions = { "String", "Boolean", "Integer", "Float" };
+ String[] typeInitVal = { "", "false", "0", "0.0"};
+ SelectedVertexPanel mSelPanel;
+
+ public VertexPropertyPanel() {
+ super();
+ setLayout(gridbag);
+ mPropertyModel = new PropertyTableModel();
+ mPropertyModel.addTableModelListener(this);
+ mPropertyTable = new PropertyTable(mPropertyModel);
+ }
+
+ /**
+ *
+ */
+
+ @Override
+ public void update(Observable o, Object arg) {
+ Vertex[] selectedVertices = null;
+ DirectedEdge selectedEdge = null;
+ // If the selection has changed
+ if (arg instanceof SelectionChangedEvent)
+ {
+ SelectionChangedEvent event = (SelectionChangedEvent) arg;
+ selectedVertices = event.mSelection.mVertices;
+ if (selectedVertices != null)
+ {
+ if (selectedVertices.length == 1)
+ {
+ setVertex(selectedVertices[0]);
+ return;
+ }
+ }
+ selectedEdge = event.mSelection.mEdge;
+ if (selectedEdge != null)
+ {
+ setEdge(selectedEdge);
+ return;
+ }
+ }
+ if (arg instanceof SelectionChangedEvent || arg instanceof EntireModelChangedEvent){
+ clear();
+ }
+ }
+
+
+ @Override
+ public void tableChanged(TableModelEvent e) {
+ if (mGraphModelManager!=null)
+ mGraphModelManager.forceNotify();
+
+ }
+
+ public void setVertex(Vertex vert) {
+ if (vert.getName().equals("domain"))
+ selObjName.setText("Domain Workflow");
+ else
+ selObjName.setText(vert.getName());
+ String className = vert.getClass().getName();
+ selObjClass.setText(className.substring(className.lastIndexOf('.')+1));
+ if (mSelPanel != null) mSelPanel.select(vert);
+ if (vert instanceof GraphableVertex) {
+ mPropertyModel.setMap(((GraphableVertex)vert).getProperties());
+ addPropButton.setEnabled(isEditable);
+ delPropButton.setEnabled(isEditable);
+ }
+ }
+
+ public void setEdge(DirectedEdge edge) {
+ selObjName.setText(edge.getName());
+ String className = edge.getClass().getName();
+ selObjClass.setText(className.substring(className.lastIndexOf('.')+1));
+ if (edge instanceof GraphableEdge) {
+ mPropertyModel.setMap(((GraphableEdge)edge).getProperties());
+ addPropButton.setEnabled(isEditable);
+ delPropButton.setEnabled(isEditable);
+ }
+ if (mSelPanel != null) mSelPanel.clear();
+ }
+
+ public void clear() {
+ selObjName.setText("");
+ selObjClass.setText("Nothing Selected");
+ mPropertyModel.setMap(new HashMap<String, Object>());
+ if (mSelPanel != null) mSelPanel.clear();
+ addPropButton.setEnabled(false);
+ delPropButton.setEnabled(false);
+ }
+
+ /**
+ * @param isEditable The isEditable to set.
+ */
+ public void setEditable(boolean editable) {
+ mPropertyModel.setEditable(editable);
+ isEditable = editable;
+ newPropBox.setVisible(editable);
+ }
+
+ public void setGraphModelManager(GraphModelManager manager) {
+ mGraphModelManager = manager;
+ manager.addObserver(this);
+ }
+
+ public void createLayout(SelectedVertexPanel selPanel)
+ {
+ GridBagConstraints c = new GridBagConstraints();
+ c.gridx = 0;
+ c.gridy = 0;
+ c.weightx = 1;
+ c.weighty = 0;
+ c.anchor = GridBagConstraints.NORTHWEST;
+ c.ipadx = 5;
+ c.ipady = 5;
+
+ selObjName = new JLabel();
+ selObjName.setFont(EntityTabPane.titleFont);
+ gridbag.setConstraints(selObjName, c);
+ add(selObjName);
+
+ c.gridy++;
+ selObjClass = new JLabel();
+ gridbag.setConstraints(selObjClass, c);
+ add(selObjClass);
+
+ c.gridy++;
+ JLabel title = new JLabel("Properties");
+ title.setFont(EntityTabPane.titleFont);
+ gridbag.setConstraints(title, c);
+ add(title);
+
+ c.gridy++;
+ c.fill = GridBagConstraints.BOTH;
+ c.weighty = 2;
+ JScrollPane scroll = new JScrollPane(mPropertyTable);
+ gridbag.setConstraints(scroll, c);
+ add(scroll);
+
+ newPropBox = Box.createHorizontalBox();
+ newPropBox.add(new JLabel(Language.translate("New :")));
+ newPropBox.add(Box.createHorizontalGlue());
+ newPropName = new JTextField(15);
+ newPropBox.add(newPropName);
+ newPropType = new JComboBox(typeOptions);
+ newPropBox.add(newPropType);
+ newPropBox.add(Box.createHorizontalStrut(1));
+ addPropButton = new JButton("Add");
+ addPropButton.setMargin(new Insets(0, 0, 0, 0));
+ delPropButton = new JButton("Del");
+ delPropButton.setMargin(new Insets(0, 0, 0, 0));
+ addPropButton.addActionListener(this);
+ delPropButton.addActionListener(this);
+ newPropBox.add(addPropButton);
+ newPropBox.add(delPropButton);
+
+ c.gridy++;
+ c.weighty=0;
+ c.fill= GridBagConstraints.HORIZONTAL;
+ gridbag.setConstraints(newPropBox, c);
+ add(newPropBox);
+
+ if (selPanel != null) {
+ c.gridy++;
+ mSelPanel = selPanel;
+ gridbag.setConstraints(mSelPanel, c);
+ add(mSelPanel);
+ }
+ }
+
+ @Override
+ public void actionPerformed(ActionEvent e) {
+ if (e.getSource() == addPropButton) {
+ if (newPropName.getText().length() < 1) {
+ JOptionPane.showMessageDialog(this, "Enter a name for the new property", "Cannot add property", JOptionPane.ERROR_MESSAGE);
+ return;
+ }
+ if (mPropertyModel.sourceMap.containsKey(newPropName.getText())) {
+ JOptionPane.showMessageDialog(this, "Property '"+newPropName.getText()+"' already exists.", "Cannot add property", JOptionPane.ERROR_MESSAGE);
+ return;
+ }
+ if (mPropertyTable.getCellEditor() != null)
+ mPropertyTable.getCellEditor().stopCellEditing();
+
+ try {
+ Class<?> newPropClass = Class.forName("java.lang."+typeOptions[newPropType.getSelectedIndex()]);
+ Class<?>[] params = {String.class};
+ Constructor<?> init = newPropClass.getConstructor(params);
+ Object[] initParams = { typeInitVal[newPropType.getSelectedIndex()] };
+ mPropertyModel.addProperty(newPropName.getText(), init.newInstance(initParams));
+ } catch (Exception ex) {
+ Logger.exceptionDialog(ex);
+ }
+ }
+ else if (e.getSource() == delPropButton) {
+ int selrow = mPropertyTable.getSelectedRow();
+ if (selrow == -1) {
+ JOptionPane.showMessageDialog(this, "Select a property to remove", "Cannot delete property", JOptionPane.ERROR_MESSAGE);
+ return;
+ }
+ mPropertyModel.delProperty(mPropertyModel.sortedNameList.get(selrow));
+ }
+ }
+}
diff --git a/src/main/java/com/c2kernel/graph/view/VertexRenderer.java b/src/main/java/com/c2kernel/graph/view/VertexRenderer.java
new file mode 100644
index 0000000..1a8d263
--- /dev/null
+++ b/src/main/java/com/c2kernel/graph/view/VertexRenderer.java
@@ -0,0 +1,11 @@
+package com.c2kernel.graph.view;
+
+import java.awt.Graphics2D;
+
+import com.c2kernel.graph.model.Vertex;
+
+
+public interface VertexRenderer
+{
+ public void draw(Graphics2D g2d, Vertex vertex);
+}