package com.horstmann.violet.workspace.editorpart.behavior;
import java.awt.Cursor;
import java.awt.event.MouseEvent;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import java.util.Iterator;
import java.util.List;
import com.horstmann.violet.product.diagram.abstracts.IGraph;
import com.horstmann.violet.product.diagram.abstracts.IGridSticker;
import com.horstmann.violet.product.diagram.abstracts.edge.IEdge;
import com.horstmann.violet.product.diagram.abstracts.node.INode;
import com.horstmann.violet.workspace.editorpart.IEditorPart;
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 DragSelectedBehavior extends AbstractEditorPartBehavior {
public DragSelectedBehavior(IEditorPart editorPart, IGraphToolsBar graphToolsBar) {
this.editorPart = editorPart;
this.graph = editorPart.getGraph();
this.selectionHandler = editorPart.getSelectionHandler();
this.graphToolsBar = graphToolsBar;
}
@Override
public void onMousePressed(MouseEvent event) {
if (event.getClickCount() > 1) {
return;
}
if (event.getButton() != MouseEvent.BUTTON1) {
return;
}
GraphTool selectedTool = this.selectionHandler.getSelectedTool();
if (IEdge.class.isInstance(selectedTool.getNodeOrEdge())) {
return;
}
double zoom = editorPart.getZoomFactor();
final Point2D mousePoint = new Point2D.Double(event.getX() / zoom, event.getY() / zoom);
if (isMouseOnNode(mousePoint)) {
changeSelectedElementIfNeeded(mousePoint);
this.isReadyForDragging = true;
this.lastMousePoint = mousePoint;
this.initialCursor = this.editorPart.getSwingComponent().getCursor();
this.editorPart.getSwingComponent().setCursor(this.dragCursor);
}
}
private boolean isMouseOnNode(Point2D mouseLocation) {
if (isLocked) {
return false;
}
INode node = this.graph.findNode(mouseLocation);
if (node == null) {
return false;
}
return true;
}
@Override
public void onMouseDragged(MouseEvent event) {
if (!isReadyForDragging) {
return;
}
double zoom = editorPart.getZoomFactor();
Point2D mousePoint = new Point2D.Double(event.getX() / zoom, event.getY() / zoom);
// TODO :
// behaviorManager.fireOnElementsDragged(selectionHandler.getSelectedNodes(),
// selectionHandler.getSelectedEdges());
INode lastNode = selectionHandler.getLastSelectedNode();
if (lastNode == null) {
return;
}
Rectangle2D bounds = lastNode.getBounds();
double dx = mousePoint.getX() - lastMousePoint.getX();
double dy = mousePoint.getY() - lastMousePoint.getY();
// we don't want to drag node into negative coordinates
// particularly with multiple selection, we might never be
// able to get them back.
List<INode> selectedNodes = selectionHandler.getSelectedNodes();
for (INode n : selectedNodes)
bounds.add(n.getBounds());
dx = Math.max(dx, -bounds.getX());
dy = Math.max(dy, -bounds.getY());
boolean isAtLeastOneNodeMoved = false;
IGridSticker gridSticker = graph.getGridSticker();
for (INode n : selectedNodes) {
if (selectedNodes.contains(n.getParent())) continue; // parents are responsible for translating their
// children
Point2D currentNodeLocation = n.getLocation();
Point2D futureNodeLocation = new Point2D.Double(currentNodeLocation.getX() + dx, currentNodeLocation.getY() + dy);
Point2D fixedFutureNodeLocation = gridSticker.snap(futureNodeLocation);
if (!currentNodeLocation.equals(fixedFutureNodeLocation)) {
n.setLocation(fixedFutureNodeLocation);
isAtLeastOneNodeMoved = true;
}
}
// Drag transition points on edges
Iterator<IEdge> iterOnEdges = graph.getAllEdges().iterator();
while (iterOnEdges.hasNext()) {
IEdge e = (IEdge) iterOnEdges.next();
INode startingNode = e.getStartNode();
INode endinNode = e.getEndNode();
if (selectedNodes.contains(startingNode) && selectedNodes.contains(endinNode)) {
Point2D[] transitionPoints = e.getTransitionPoints();
for (Point2D aTransitionPoint : transitionPoints) {
double newTransitionPointLocationX = aTransitionPoint.getX() + dx;
double newTransitionPointLocationY = aTransitionPoint.getY() + dy;
aTransitionPoint.setLocation(newTransitionPointLocationX, newTransitionPointLocationY);
aTransitionPoint = gridSticker.snap(aTransitionPoint);
}
e.setTransitionPoints(transitionPoints);
}
}
// Save mouse location for next dragging sequence
if (isAtLeastOneNodeMoved) {
Point2D snappedMousePoint = gridSticker.snap(mousePoint);
if (!snappedMousePoint.equals(lastMousePoint)) {
editorPart.getSwingComponent().invalidate();
editorPart.getSwingComponent().repaint();
}
lastMousePoint = snappedMousePoint;
}
}
@Override
public void onMouseReleased(MouseEvent event) {
this.editorPart.getSwingComponent().setCursor(this.initialCursor);
this.lastMousePoint = null;
this.isReadyForDragging = false;
this.initialCursor = null;
}
private void changeSelectedElementIfNeeded(Point2D mouseLocation) {
IEdge edge = this.graph.findEdge(mouseLocation);
if (edge != null) {
// We don't want to drag edges
return;
}
INode node = this.graph.findNode(mouseLocation);
if (node == null) {
return;
}
List<INode> selectedNodes = this.selectionHandler.getSelectedNodes();
if (!selectedNodes.contains(node)) {
this.selectionHandler.clearSelection();
this.selectionHandler.addSelectedElement(node);
}
}
public static void lock() {
isLocked = true;
}
public static void unlock() {
isLocked = false;
}
private IGraph graph;
private Point2D lastMousePoint = null;
private IEditorPartSelectionHandler selectionHandler;
private IEditorPart editorPart;
private IGraphToolsBar graphToolsBar;
private boolean isReadyForDragging = false;
private Cursor initialCursor = null;
private Cursor dragCursor = new Cursor(Cursor.HAND_CURSOR);
private static volatile boolean isLocked = false;
}