package com.horstmann.violet.workspace.editorpart.behavior; import java.awt.Cursor; import java.awt.event.MouseEvent; import java.awt.geom.Line2D; import java.awt.geom.Point2D; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import com.horstmann.violet.product.diagram.abstracts.IGridSticker; import com.horstmann.violet.product.diagram.abstracts.edge.IEdge; import com.horstmann.violet.workspace.editorpart.IEditorPart; import com.horstmann.violet.workspace.editorpart.IEditorPartBehaviorManager; import com.horstmann.violet.workspace.editorpart.IEditorPartSelectionHandler; import com.horstmann.violet.workspace.sidebar.graphtools.GraphTool; import com.horstmann.violet.workspace.sidebar.graphtools.IGraphToolsBar; public class AddTransitionPointBehavior extends AbstractEditorPartBehavior { public AddTransitionPointBehavior(IEditorPart editorPart, IGraphToolsBar graphToolsBar) { this.editorPart = editorPart; this.selectionHandler = editorPart.getSelectionHandler(); this.graphToolsBar = graphToolsBar; this.behaviorManager = editorPart.getBehaviorManager(); } @Override public void onMouseMoved(MouseEvent event) { if (!isPrerequisitesOK()) { return; } boolean isMouseOnEdgePath = isMouseOnEdgePath(event); if (isMouseOnEdgePath) { if (this.initialCursor == null) { this.initialCursor = this.editorPart.getSwingComponent().getCursor(); } this.editorPart.getSwingComponent().setCursor(this.transitionCursor); } if (!isMouseOnEdgePath) { if (this.initialCursor != null) { this.editorPart.getSwingComponent().setCursor(this.initialCursor); this.initialCursor = null; } } } @Override public void onMousePressed(MouseEvent event) { if (event.getClickCount() > 1) { return; } if (event.getButton() != MouseEvent.BUTTON1) { return; } if (!isPrerequisitesOK()) { return; } if (!isMouseOnEdgePath(event)) { return; } if (isMouseOnTransitionPoint(event)) { return; } this.isReadyToAddTransitionPoint = true; double zoom = editorPart.getZoomFactor(); IGridSticker gridSticker = editorPart.getGraph().getGridSticker(); final Point2D mousePoint = new Point2D.Double(event.getX() / zoom, event.getY() / zoom); this.newTransitionPointLocation = mousePoint; this.newTransitionPointLocation = gridSticker.snap(this.newTransitionPointLocation); this.selectedEdge = this.selectionHandler.getSelectedEdges().get(0); } @Override public void onMouseDragged(MouseEvent event) { if (this.isReadyToAddTransitionPoint && !this.isTransitionPointAdded) { // We add transition point only if a dragging action is detected. // If we added it on mouse pressed, it will produce a conflict with // other click-based actions such as EditSeletedBehavior startUndoRedoCapture(); addNewTransitionPoint(event); stopUndoRedoCapture(); this.editorPart.getSwingComponent().invalidate(); this.isTransitionPointAdded = true; } } @Override public void onMouseReleased(MouseEvent event) { this.newTransitionPointLocation = null; this.isReadyToAddTransitionPoint = false; this.isTransitionPointAdded = false; this.selectedEdge = null; } private IEdge getSelectedEdge() { if (this.selectedEdge == null) { if (this.selectionHandler.getSelectedEdges().size() == 1) { this.selectedEdge = this.selectionHandler.getSelectedEdges().get(0); } } return this.selectedEdge; } private boolean isPrerequisitesOK() { if (this.selectionHandler.getSelectedEdges().size() != 1) { return false; } if (getSelectedEdge().isTransitionPointsSupported()) { return true; } return false; } private boolean isSelectedToolOK() { if (getSelectedEdge() == null) { return false; } GraphTool selectedTool = this.graphToolsBar.getSelectedTool(); if (GraphTool.SELECTION_TOOL.equals(selectedTool)) { return true; } if (selectedTool.getNodeOrEdge().getClass().isInstance(getSelectedEdge())) { return true; } return false; } private boolean isMouseOnTransitionPoint(MouseEvent event) { if (getSelectedEdge() == null) { return false; } double zoom = this.editorPart.getZoomFactor(); final Point2D mousePoint = new Point2D.Double(event.getX() / zoom, event.getY() / zoom); final double MAX_DIST = 5; for (Point2D aTransitionPoint : getSelectedEdge().getTransitionPoints()) { if (aTransitionPoint.distance(mousePoint) <= MAX_DIST) { return true; } } return false; } private void addNewTransitionPoint(MouseEvent event) { if (getSelectedEdge() == null) { return; } Point2D[] transitionPoints = getSelectedEdge().getTransitionPoints(); if (transitionPoints.length == 0) { List<Point2D> newTransitionPointList = new ArrayList<Point2D>(); newTransitionPointList.add(this.newTransitionPointLocation); getSelectedEdge().setTransitionPoints(newTransitionPointList.toArray(new Point2D[newTransitionPointList.size()])); return; } if (transitionPoints.length > 0) { List<Point2D> pointsToTest = new ArrayList<Point2D>(); Line2D connectionPoints = getSelectedEdge().getConnectionPoints(); pointsToTest.add(connectionPoints.getP1()); pointsToTest.addAll(Arrays.asList(transitionPoints)); pointsToTest.add(connectionPoints.getP2()); Point2D lineToTestStartingPoint = pointsToTest.get(0); final double MAX_DIST = 5; for (int i = 1; i < pointsToTest.size(); i++) { Point2D lineToTestEndingPoint = pointsToTest.get(i); Line2D lineToTest = new Line2D.Double(lineToTestStartingPoint, lineToTestEndingPoint); if (lineToTest.ptSegDist(this.newTransitionPointLocation) <= MAX_DIST) { List<Point2D> newTransitionPointList = new ArrayList<Point2D>(); newTransitionPointList.addAll(Arrays.asList(transitionPoints)); newTransitionPointList.add(i - 1, this.newTransitionPointLocation); getSelectedEdge().setTransitionPoints( newTransitionPointList.toArray(new Point2D[newTransitionPointList.size()])); return; } lineToTestStartingPoint = lineToTestEndingPoint; } return; } } private boolean isMouseOnEdgePath(MouseEvent event) { if (getSelectedEdge() == null) { return false; } double zoom = this.editorPart.getZoomFactor(); final Point2D mousePoint = new Point2D.Double(event.getX() / zoom, event.getY() / zoom); return getSelectedEdge().contains(mousePoint); } private void startUndoRedoCapture() { if (getSelectedEdge() == null) { return; } this.behaviorManager.fireBeforeChangingTransitionPointsOnEdge(getSelectedEdge()); } private void stopUndoRedoCapture() { if (getSelectedEdge() == null) { return; } this.behaviorManager.fireAfterChangingTransitionPointsOnEdge(getSelectedEdge()); } private IEditorPartBehaviorManager behaviorManager; private IEditorPartSelectionHandler selectionHandler; private IEditorPart editorPart; private IGraphToolsBar graphToolsBar; private boolean isReadyToAddTransitionPoint = false; private boolean isTransitionPointAdded = false; private Point2D newTransitionPointLocation = null; private IEdge selectedEdge = null; private Cursor initialCursor = null; private Cursor transitionCursor = new Cursor(Cursor.CROSSHAIR_CURSOR); }