/*******************************************************************************
* Copyright (c) 2006-2012
* Software Technology Group, Dresden University of Technology
* DevBoost GmbH, Berlin, Amtsgericht Charlottenburg, HRB 140026
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Software Technology Group - TU Dresden, Germany;
* DevBoost GmbH - Berlin, Germany
* - initial API and implementation
******************************************************************************/
/*
* @(#)ConnectorHandle.java 2.0.1 2009-05-09
*
* Copyright (c) 1996-2009 by the original authors of JHotDraw
* and all its contributors.
* All rights reserved.
*
* The copyright of this software is owned by the authors and
* contributors of the JHotDraw project ("the copyright holders").
* You may not use, copy or modify this software, except in
* accordance with the license agreement you entered into with
* the copyright holders. For details see accompanying license terms.
*/
package org.jhotdraw.draw;
import java.util.*;
import javax.swing.undo.*;
import org.jhotdraw.util.*;
import java.awt.*;
import java.awt.geom.*;
/**
* A ConnectorHandle allows to create a ConnectionFigure by dragging the
* connector handle to a connector.
*
* @author Werner Randelshofer.
* @version 2.0.1 2009-05-09 The drawing area was not entirely repainted, when
* the handle was released without connecting the figure.
* <br>2.0 2007-05-15 Renamed from ConnectionHandle to ConnectorHandle.
* Uses a Connector instead of a Locator now.
* <br>1.0 20. Juni 2006 Created.
*/
public class ConnectorHandle extends AbstractHandle {
/**
* Holds the ConnectionFigure which is currently being created.
*/
private ConnectionFigure createdConnection;
/**
* The prototype for the ConnectionFigure to be created
*/
private ConnectionFigure prototype;
/**
* The Connector.
*/
private Connector connector;
/**
* The current connectable Figure.
*/
private Figure connectableFigure;
/**
* The current connectable Connector.
*/
private Connector connectableConnector;
/**
* All connectors of the connectable Figure.
*/
protected Collection<Connector> connectors = Collections.emptyList();
/** Creates a new instance. */
public ConnectorHandle(Connector connector, ConnectionFigure prototype) {
super(connector.getOwner());
this.connector = connector;
this.prototype = prototype;
}
public Point2D.Double getLocationOnDrawing() {
return connector.getAnchor();
}
public Point getLocation() {
return view.drawingToView(connector.getAnchor());
}
@Override
public void draw(Graphics2D g) {
Graphics2D gg = (Graphics2D) g.create();
gg.transform(view.getDrawingToViewTransform());
for (Connector c : connectors) {
c.draw(gg);
}
if (createdConnection == null) {
drawCircle(g,
getEditor().getHandleAttribute(HandleAttributeKeys.DISCONNECTED_CONNECTOR_HANDLE_FILL_COLOR),
getEditor().getHandleAttribute(HandleAttributeKeys.DISCONNECTED_CONNECTOR_HANDLE_STROKE_COLOR));
} else {
drawCircle(g,
getEditor().getHandleAttribute(HandleAttributeKeys.CONNECTED_CONNECTOR_HANDLE_FILL_COLOR),
getEditor().getHandleAttribute(HandleAttributeKeys.CONNECTED_CONNECTOR_HANDLE_STROKE_COLOR));
Point p = view.drawingToView(createdConnection.getEndPoint());
g.setColor((Color) getEditor().getHandleAttribute(HandleAttributeKeys.CONNECTED_CONNECTOR_HANDLE_FILL_COLOR));
int width = getHandlesize();
g.fillOval(p.x - width / 2, p.y - width / 2, width, width);
g.setColor((Color) getEditor().getHandleAttribute(HandleAttributeKeys.CONNECTED_CONNECTOR_HANDLE_STROKE_COLOR));
g.drawOval(p.x - width / 2, p.y - width / 2, width, width);
}
}
public void trackStart(Point anchor, int modifiersEx) {
setConnection(createConnection());
ResourceBundleUtil labels = ResourceBundleUtil.getBundle("org.jhotdraw.draw.Labels");
Point2D.Double p = getLocationOnDrawing();
getConnection().setStartPoint(p);
getConnection().setEndPoint(p);
view.getDrawing().add(getConnection());
}
public void trackStep(Point anchor, Point lead, int modifiersEx) {
//updateConnectors(lead);
Point2D.Double p = view.viewToDrawing(lead);
fireAreaInvalidated(getDrawingArea());
Figure figure = findConnectableFigure(p, view.getDrawing());
if (figure != connectableFigure) {
connectableFigure = figure;
repaintConnectors();
}
connectableConnector = findConnectableConnector(figure, p);
if (connectableConnector != null) {
p = connectableConnector.getAnchor();
}
getConnection().willChange();
getConnection().setEndPoint(p);
getConnection().changed();
fireAreaInvalidated(getDrawingArea());
}
@Override
public Rectangle getDrawingArea() {
if (getConnection() != null) {
Rectangle r = new Rectangle(
view.drawingToView(getConnection().getEndPoint()));
r.grow(getHandlesize(), getHandlesize());
return r;
} else {
return new Rectangle(); // empty rectangle
}
}
public void trackEnd(Point anchor, Point lead, int modifiersEx) {
Point2D.Double p = view.viewToDrawing(lead);
view.getConstrainer().constrainPoint(p);
Figure f = findConnectableFigure(p, view.getDrawing());
connectableConnector = findConnectableConnector(f, p);
if (connectableConnector != null) {
final Drawing drawing = view.getDrawing();
final ConnectionFigure c = getConnection();
getConnection().setStartConnector(connector);
getConnection().setEndConnector(connectableConnector);
getConnection().updateConnection();
view.clearSelection();
view.addToSelection(c);
view.getDrawing().fireUndoableEditHappened(new AbstractUndoableEdit() {
@Override
public String getPresentationName() {
ResourceBundleUtil labels = ResourceBundleUtil.getBundle("org.jhotdraw.draw.Labels");
return labels.getString("edit.createConnectionFigure.text");
}
@Override
public void undo() throws CannotUndoException {
super.undo();
drawing.remove(c);
}
@Override
public void redo() throws CannotRedoException {
super.redo();
drawing.add(c);
view.clearSelection();
view.addToSelection(c);
}
});
} else {
view.getDrawing().remove(getConnection());
fireAreaInvalidated(getDrawingArea());
}
connectableConnector = null;
connectors = Collections.emptyList();
setConnection(null);
setTargetFigure(null);
}
/**
* Creates the ConnectionFigure. By default the figure prototype is
* cloned.
*/
protected ConnectionFigure createConnection() {
return (ConnectionFigure) prototype.clone();
}
protected void setConnection(ConnectionFigure newConnection) {
createdConnection = newConnection;
}
protected ConnectionFigure getConnection() {
return createdConnection;
}
protected Figure getTargetFigure() {
return connectableFigure;
}
protected void setTargetFigure(Figure newTargetFigure) {
connectableFigure = newTargetFigure;
}
private Figure findConnectableFigure(Point2D.Double p, Drawing drawing) {
for (Figure figure : drawing.getFiguresFrontToBack()) {
if (!figure.includes(getConnection()) &&
figure.canConnect() &&
figure.contains(p)) {
return figure;
}
}
return null;
}
/**
* Finds a connection end figure.
*/
protected Connector findConnectableConnector(Figure connectableFigure, Point2D.Double p) {
Connector target = (connectableFigure == null) ? null : connectableFigure.findConnector(p, getConnection());
if ((connectableFigure != null) && connectableFigure.canConnect() && !connectableFigure.includes(getOwner()) && getConnection().canConnect(connector, target)) {
return target;
}
return null;
}
protected Rectangle basicGetBounds() {
Rectangle r = new Rectangle(getLocation());
int h = getHandlesize();
r.x -= h / 2;
r.y -= h / 2;
r.width = r.height = h;
return r;
}
@Override
public boolean isCombinableWith(Handle handle) {
return false;
}
/**
* Updates the list of connectors that we draw when the user
* moves or drags the mouse over a figure to which can connect.
*/
public void repaintConnectors() {
Rectangle2D.Double invalidArea = null;
for (Connector c : connectors) {
if (invalidArea == null) {
invalidArea = c.getDrawingArea();
} else {
invalidArea.add(c.getDrawingArea());
}
}
connectors = (connectableFigure == null) ? new java.util.LinkedList<Connector>() : connectableFigure.getConnectors(prototype);
for (Connector c : connectors) {
if (invalidArea == null) {
invalidArea = c.getDrawingArea();
} else {
invalidArea.add(c.getDrawingArea());
}
}
if (invalidArea != null) {
view.getComponent().repaint(
view.drawingToView(invalidArea));
}
}
}