package com.horstmann.violet.workspace.editorpart.behavior;
import java.awt.Graphics2D;
import java.awt.event.MouseEvent;
import java.awt.geom.Line2D;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import java.util.List;
import com.horstmann.violet.framework.util.GrabberUtils;
import com.horstmann.violet.framework.util.KeyModifierUtil;
import com.horstmann.violet.product.diagram.abstracts.IGraph;
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.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 SelectByClickBehavior extends AbstractEditorPartBehavior
{
public SelectByClickBehavior(IEditorPart editorPart, IGraphToolsBar graphToolsBar)
{
this.editorPart = editorPart;
this.graph = editorPart.getGraph();
this.selectionHandler = editorPart.getSelectionHandler();
this.behaviorManager = editorPart.getBehaviorManager();
this.graphToolsBar = graphToolsBar;
}
@Override
public void onMousePressed(MouseEvent event)
{
resetEventAttributes();
if (event.getClickCount() > 1) {
return;
}
if (event.getButton() != MouseEvent.BUTTON1) {
return;
}
if (!GraphTool.SELECTION_TOOL.equals(this.graphToolsBar.getSelectedTool())) {
return;
}
double zoom = editorPart.getZoomFactor();
Point2D mousePoint = new Point2D.Double(event.getX() / zoom, event.getY() / zoom);
boolean isCtrl = KeyModifierUtil.isCtrl(event);
boolean isOnNodeOrEdge = isMouseOnNodeOrEdge(mousePoint);
if (!isOnNodeOrEdge && !isCtrl)
{
resetSelectedElements();
return;
}
if (isOnNodeOrEdge && !isCtrl)
{
processSelection(mousePoint, true);
return;
}
if (isOnNodeOrEdge && isCtrl)
{
processSelection(mousePoint, false);
return;
}
}
@Override
public void onMouseDragged(MouseEvent event)
{
this.isDragGesture = true;
}
@Override
public void onMouseReleased(MouseEvent event)
{
if (event.getClickCount() > 1) {
return;
}
if (event.getButton() != MouseEvent.BUTTON1) {
return;
}
if (this.isDragGesture) {
return;
}
if (KeyModifierUtil.isCtrl(event)) {
processSelectionInConflictWithDraggingEvents(false);
} else {
processSelectionInConflictWithDraggingEvents(true);
}
this.editorPart.getSwingComponent().invalidate();
}
private void resetEventAttributes()
{
this.isDragGesture = false;
this.unprocessedNode = null;
this.unprocessedEdge = null;
}
private boolean isMouseOnNodeOrEdge(Point2D mouseLocation)
{
INode node = this.graph.findNode(mouseLocation);
IEdge edge = this.graph.findEdge(mouseLocation);
if (node == null && edge == null)
{
return false;
}
return true;
}
private void resetSelectedElements()
{
this.selectionHandler.clearSelection();
}
/**
* Here, we add or remove the selected node_old or edge to the global selection. Under the wood, we can't remove anything.
* This can only made on 'mouse released' to avoid conflict to any dragging event.
*
* @param mouseLocation
* @param isResetSelectionFirst
*/
private void processSelection(Point2D mouseLocation, boolean isResetSelectionFirst)
{
INode node = this.graph.findNode(mouseLocation);
IEdge edge = this.graph.findEdge(mouseLocation);
if (edge != null)
{
if (this.selectionHandler.isElementAlreadySelected(edge))
{
// This edge will be removed only on mouse button released
// to avoid conflicts with dragging events
this.unprocessedEdge = edge;
}
else
{
if (isResetSelectionFirst) {
resetSelectedElements();
}
this.selectionHandler.addSelectedElement(edge);
if (this.selectionHandler.getSelectedEdges().size() == 1) {
this.behaviorManager.fireOnEdgeSelected(edge);
}
}
return;
}
if (node != null)
{
if (this.selectionHandler.isElementAlreadySelected(node))
{
// This node_old will be removed only on mouse button released
// to avoid conflicts with dragging events
this.unprocessedNode = node;
}
else
{
if (isResetSelectionFirst) {
resetSelectedElements();
}
this.selectionHandler.addSelectedElement(node);
if (this.selectionHandler.getSelectedNodes().size() == 1) {
this.behaviorManager.fireOnNodeSelected(node);
}
}
return;
}
}
/**
* We process node or edges on 'mouse released' event because it's not possible to remove node or edges
* from selection on 'mouse pressed' because it can be part of a dragging intention from the user. So,
* unprocessed elements are removed from selection only on 'mouse released' if the user is pressing CTRL.
* They are set as unique selection if the user isn't pressing CTRL.
*
* @param isResetSelectionFirst
*/
private void processSelectionInConflictWithDraggingEvents(boolean isResetSelectionFirst) {
if (this.unprocessedNode == null && this.unprocessedEdge == null) {
return;
}
if (isResetSelectionFirst) {
resetSelectedElements();
if (this.unprocessedNode != null) {
this.selectionHandler.addSelectedElement(this.unprocessedNode);
}
if (this.unprocessedEdge != null) {
this.selectionHandler.addSelectedElement(this.unprocessedEdge);
}
}
if (!isResetSelectionFirst) {
if (this.unprocessedNode != null) {
this.selectionHandler.removeElementFromSelection(this.unprocessedNode);
}
if (this.unprocessedEdge != null) {
this.selectionHandler.removeElementFromSelection(this.unprocessedEdge);
}
}
}
@Override
public void onPaint(Graphics2D g2)
{
List<INode> nodes = selectionHandler.getSelectedNodes();
for (INode n : nodes)
{
if (graph.getAllNodes().contains(n))
{
Point2D nodeLocationOnGraph = n.getLocationOnGraph();
Rectangle2D nodeBounds = n.getBounds();
GrabberUtils.drawPurpleGrabber(g2, nodeLocationOnGraph.getX(), nodeLocationOnGraph.getY());
GrabberUtils.drawPurpleGrabber(g2, nodeLocationOnGraph.getX(), nodeLocationOnGraph.getY() + nodeBounds.getHeight());
GrabberUtils.drawPurpleGrabber(g2, nodeLocationOnGraph.getX() + nodeBounds.getWidth(), nodeLocationOnGraph.getY());
GrabberUtils.drawPurpleGrabber(g2, nodeLocationOnGraph.getX() + nodeBounds.getWidth(), nodeLocationOnGraph.getY() + nodeBounds.getHeight());
}
}
List<IEdge> edges = selectionHandler.getSelectedEdges();
for (IEdge e : edges)
{
if (graph.getAllEdges().contains(e))
{
Line2D line = e.getConnectionPoints();
GrabberUtils.drawPurpleGrabber(g2, line.getX1(), line.getY1());
GrabberUtils.drawPurpleGrabber(g2, line.getX2(), line.getY2());
for (Point2D aTransitionPoint : e.getTransitionPoints()) {
GrabberUtils.drawGrayGrabber(g2, aTransitionPoint.getX(), aTransitionPoint.getY());
}
}
}
}
private IEditorPart editorPart;
private IGraph graph;
private IEditorPartSelectionHandler selectionHandler;
private IEditorPartBehaviorManager behaviorManager;
private IGraphToolsBar graphToolsBar;
private boolean isDragGesture = false;
private INode unprocessedNode = null;
private IEdge unprocessedEdge = null;
}