/*
* org.openmicroscopy.shoola.util.ui.drawingtools.creationtools.BezierTool
*
*------------------------------------------------------------------------------
* Copyright (C) 2006-2009 University of Dundee. All rights reserved.
*
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
*------------------------------------------------------------------------------
*/
package org.openmicroscopy.shoola.util.ui.drawingtools.creationtools;
//Java imports
import java.awt.Cursor;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.event.MouseEvent;
import java.awt.geom.Point2D;
import java.util.Map;
import javax.swing.undo.AbstractUndoableEdit;
import javax.swing.undo.CannotRedoException;
import javax.swing.undo.CannotUndoException;
//Third-party libraries
import org.jhotdraw.draw.AbstractTool;
import org.jhotdraw.draw.AttributeKey;
import org.jhotdraw.draw.Drawing;
import org.jhotdraw.draw.DrawingEditor;
import org.jhotdraw.draw.DrawingView;
import org.jhotdraw.draw.Figure;
import org.jhotdraw.geom.Bezier;
import org.jhotdraw.geom.BezierPath;
import org.jhotdraw.geom.Geom;
import org.jhotdraw.util.ResourceBundleUtil;
import org.openmicroscopy.shoola.util.roi.model.annotation.MeasurementAttributes;
//Application-internal dependencies
import org.openmicroscopy.shoola.util.ui.drawingtools.figures.BezierTextFigure;
/**
*
*
* @author Jean-Marie Burel
* <a href="mailto:j.burel@dundee.ac.uk">j.burel@dundee.ac.uk</a>
* @author Donald MacDonald
* <a href="mailto:donald@lifesci.dundee.ac.uk">donald@lifesci.dundee.ac.uk</a>
* @version 3.0
* <small>
* (<b>Internal version:</b> $Revision: $Date: $)
* </small>
* @since 3.0-Beta4
*/
public class BezierTool
extends AbstractTool
{
/**
* Set this to true to turn on debugging output on System.out.
*/
private final static boolean DEBUG = false;
private final boolean clickOnly = true;
private final double error = 1;
private Boolean finishWhenMouseReleased;
protected Map<AttributeKey, Object> attributes;
/**
* The prototype for new figures.
*/
private BezierTextFigure prototype;
/**
* The created figure.
*/
protected BezierTextFigure createdFigure;
private int nodeCountBeforeDrag;
/**
* A localized name for this tool. The presentationName is displayed by the
* UndoableEdit.
*/
private String presentationName;
/** Creates a new instance. */
public BezierTool(BezierTextFigure prototype) {
this(prototype, null);
}
/** Creates a new instance. */
public BezierTool(BezierTextFigure prototype, Map attributes) {
this(prototype, attributes, null);
}
public BezierTool(BezierTextFigure prototype, Map attributes, String name) {
this.prototype = prototype;
this.attributes = attributes;
if (name == null) {
ResourceBundleUtil labels = ResourceBundleUtil.getLAFBundle("org.jhotdraw.draw.Labels");
name = labels.getString("createFigure");
}
this.presentationName = name;
}
public String getPresentationName() {
return presentationName;
}
public void activate(DrawingEditor editor) {
super.activate(editor);
getView().clearSelection();
getView().setCursor(Cursor.getPredefinedCursor(Cursor.CROSSHAIR_CURSOR));
}
public void deactivate(DrawingEditor editor) {
super.deactivate(editor);
getView().setCursor(Cursor.getDefaultCursor());
if (createdFigure != null) {
finishCreation(createdFigure);
createdFigure = null;
}
}
public void mousePressed(MouseEvent evt) {
if (DEBUG) System.out.println("BezierTool.mousePressed "+evt);
super.mousePressed(evt);
if (createdFigure == null) {
finishWhenMouseReleased = null;
createdFigure = createFigure();
createdFigure.addNode(new BezierPath.Node(
getView().getConstrainer().constrainPoint(
getView().viewToDrawing(anchor)
)));
//work around since the font size is reset when the figure is added.
Object s = createdFigure.getAttribute(MeasurementAttributes.FONT_SIZE);
getDrawing().add(createdFigure);
createdFigure.setAttribute(MeasurementAttributes.FONT_SIZE, s);
nodeCountBeforeDrag = createdFigure.getNodeCount();
} else {
if (evt.getClickCount() == 1) {
addPointToFigure(getView().getConstrainer().constrainPoint(
getView().viewToDrawing(anchor)));
}
nodeCountBeforeDrag = createdFigure.getNodeCount();
}
}
protected BezierTextFigure createFigure() {
BezierTextFigure f = (BezierTextFigure) prototype.clone();
getEditor().applyDefaultAttributesTo(f);
if (attributes != null) {
for (Map.Entry<AttributeKey, Object> entry : attributes.entrySet()) {
f.setAttribute(entry.getKey(), entry.getValue());
}
}
return f;
}
protected Figure getCreatedFigure() {
return createdFigure;
}
protected Figure getAddedFigure() {
return createdFigure;
}
protected void addPointToFigure(Point2D.Double newPoint) {
int pointCount = createdFigure.getNodeCount();
createdFigure.willChange();
if (pointCount < 2) {
createdFigure.addNode(new BezierPath.Node(newPoint));
} else {
Point2D.Double endPoint = createdFigure.getEndPoint();
Point2D.Double secondLastPoint = (pointCount <= 1) ?
endPoint :
createdFigure.getPoint(pointCount - 2, 0);
if (newPoint.equals(endPoint)) {
// nothing to do
} else if (pointCount > 1 && Geom.lineContainsPoint(newPoint.x, newPoint.y, secondLastPoint.x, secondLastPoint.y, endPoint.x, endPoint.y, 0.9f / getView().getScaleFactor())) {
createdFigure.setPoint(pointCount - 1, 0, newPoint);
} else {
createdFigure.addNode(new BezierPath.Node(newPoint));
}
}
createdFigure.changed();
}
public void mouseClicked(MouseEvent evt) {
if (createdFigure != null) {
switch (evt.getClickCount()) {
case 1 :
if (createdFigure.getNodeCount() > 2) {
Rectangle r = new Rectangle(getView().drawingToView(createdFigure.getStartPoint()));
r.grow(2,2);
if (r.contains(evt.getX(), evt.getY())) {
createdFigure.setClosed(true);
finishCreation(createdFigure);
createdFigure = null;
fireToolDone();
}
}
break;
case 2 :
finishWhenMouseReleased = null;
finishCreation(createdFigure);
/*
getView().addToSelection(createdFigure);
*/
createdFigure = null;
fireToolDone();
break;
}
}
}
protected void fireUndoEvent(Figure createdFigure) {
final Figure addedFigure = createdFigure;
final Drawing addedDrawing = getDrawing();
final DrawingView addedView = getView();
getDrawing().fireUndoableEditHappened(new AbstractUndoableEdit() {
public String getPresentationName() {
return presentationName;
}
public void undo() throws CannotUndoException {
super.undo();
addedDrawing.remove(addedFigure);
}
public void redo() throws CannotRedoException {
super.redo();
addedView.clearSelection();
addedDrawing.add(addedFigure);
addedView.addToSelection(addedFigure);
}
});
}
public void mouseReleased(MouseEvent evt) {
if (!clickOnly)
{
if (DEBUG) System.out.println("BezierTool.mouseReleased "+evt);
if (finishWhenMouseReleased == Boolean.TRUE) {
if (createdFigure.getNodeCount() > 2) {
BezierPath fittedPath = Bezier.fitBezierCurve(createdFigure.getBezierPath(), error);
createdFigure.willChange();
createdFigure.setBezierPath(fittedPath);
createdFigure.changed();
finishCreation(createdFigure);
createdFigure = null;
finishWhenMouseReleased = null;
fireToolDone();
return;
}
} else if (finishWhenMouseReleased == null) {
finishWhenMouseReleased = Boolean.FALSE;
}
if (createdFigure.getNodeCount() > nodeCountBeforeDrag + 1) {
createdFigure.willChange();
BezierPath fittedPath = new BezierPath();
for (int i=nodeCountBeforeDrag, n = createdFigure.getNodeCount(); i < n; i++) {
fittedPath.add(createdFigure.getNode(nodeCountBeforeDrag));
createdFigure.removeNode(nodeCountBeforeDrag);
}
fittedPath = Bezier.fitBezierCurve(fittedPath, error);
for (BezierPath.Node node : fittedPath) {
createdFigure.addNode(node);
}
nodeCountBeforeDrag = createdFigure.getNodeCount();
createdFigure.changed();
}
}
}
protected void finishCreation(BezierTextFigure createdFigure) {
getView().addToSelection(createdFigure);
fireUndoEvent(createdFigure);
}
public void mouseDragged(MouseEvent evt) {
if (createdFigure != null) {
if (finishWhenMouseReleased == null) {
finishWhenMouseReleased = Boolean.TRUE;
}
if(!clickOnly)
{
int x = evt.getX();
int y = evt.getY();
addPointToFigure(getView().viewToDrawing(new Point(x, y)));
}}
}
public void mouseMoved(MouseEvent evt) {
/*
if (createdFigure != null) {
}*/
}
}