/* * org.openmicroscopy.shoola.util.ui.drawingtools.creationtools.DrawingObjectCreationTool * *------------------------------------------------------------------------------ * Copyright (C) 2006-2007 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; import java.awt.Cursor; import java.awt.Dimension; import java.awt.Point; import java.awt.event.MouseEvent; import java.awt.event.MouseListener; import java.awt.event.MouseMotionListener; import java.awt.geom.Point2D; import java.awt.geom.Rectangle2D; import java.util.Map; import javax.swing.undo.AbstractUndoableEdit; import javax.swing.undo.CannotRedoException; import javax.swing.undo.CannotUndoException; import org.jhotdraw.draw.AbstractTool; import org.jhotdraw.draw.AttributeKey; import org.jhotdraw.draw.CompositeFigure; import org.jhotdraw.draw.Drawing; import org.jhotdraw.draw.DrawingEditor; import org.jhotdraw.draw.Figure; import org.jhotdraw.util.ResourceBundleUtil; import org.openmicroscopy.shoola.util.roi.model.annotation.MeasurementAttributes; /** * A tool to create new drawing figures. * * @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 * @since OME3.0 */ public class DrawingObjectCreationTool extends AbstractTool implements DrawingCreationTool { /** Reset the tool to the select tool. */ private boolean resetToSelect; /** * Attributes to be applied to the created ConnectionFigure. * These attributes override the default attributes of the * DrawingEditor. */ private Map<AttributeKey, Object> prototypeAttributes; /** * A localized name for this tool. The presentationName is displayed by the * UndoableEdit. */ private String presentationName; /** * Threshold for which we create a larger shape of a minimal size. */ private Dimension minimalSizeTreshold = new Dimension(2, 2); /** * We set the figure to this minimal size, if it is smaller than the * minimal size threshold. */ private Dimension minimalSize = new Dimension(10, 10); /** The prototype for new figures. */ private Figure prototype; /** The created figure. */ protected Figure createdFigure; /** * Creates a new instance. * * @param prototypeClassName The type of prototype to create. */ public DrawingObjectCreationTool(String prototypeClassName) { this(prototypeClassName, null, null); } /** * Creates a new instance. * * @param prototypeClassName The type of prototype to create. * @param attributes The attributes to add. */ public DrawingObjectCreationTool(String prototypeClassName, Map<AttributeKey, Object> attributes) { this(prototypeClassName, attributes, null); } /** * Creates a new instance. * * @param prototypeClassName The type of prototype to create. * @param attributes The attributes to add. * @param name The name to display. */ public DrawingObjectCreationTool(String prototypeClassName, Map<AttributeKey, Object> attributes, String name) { try { this.prototype = (Figure) Class.forName(prototypeClassName).newInstance(); } catch (Exception e) { InternalError error = new InternalError( "Unable to create Figure from "+prototypeClassName); error.initCause(e); throw error; } this.prototypeAttributes = attributes; if (name == null) { ResourceBundleUtil labels = ResourceBundleUtil.getLAFBundle( "org.jhotdraw.draw.Labels"); name = labels.getString("createFigure"); } this.presentationName = name; } /** * Creates a new instance with the specified prototype but without an * attribute set. The CreationTool clones this prototype each time a new * Figure needs to be created. When a new Figure is created, the * CreationTool applies the default attributes from the DrawingEditor to it. * * @param prototype The prototype used to create a new Figure. */ public DrawingObjectCreationTool(Figure prototype) { this(prototype, null, null); } /** Creates a new instance with the specified prototype but without an * attribute set. The CreationTool clones this prototype each time a new * Figure needs to be created. When a new Figure is created, the * CreationTool applies the default attributes from the DrawingEditor to it, * and then it applies the attributes to it, that have been supplied in * this constructor. * * @param prototype The prototype used to create a new Figure. * @param attributes The CreationTool applies these attributes to the * prototype after having applied the default attributes from the DrawingEditor. */ public DrawingObjectCreationTool(Figure prototype, Map<AttributeKey, Object> attributes) { this(prototype, attributes, null); } /** * Creates a new instance with the specified prototype and attribute set. * * @param prototype The prototype used to create a new Figure. * @param attributes The CreationTool applies these attributes to the * prototype after having applied the default attributes from the DrawingEditor. * @param name The presentationName parameter is currently not used. */ public DrawingObjectCreationTool(Figure prototype, Map<AttributeKey, Object> attributes, String name) { this.prototype = prototype; this.prototypeAttributes = attributes; if (name == null) { ResourceBundleUtil labels = ResourceBundleUtil.getLAFBundle("org.jhotdraw.draw.Labels"); name = labels.getString("createFigure"); } this.presentationName = name; } /** * Sets the attributes. * * @param attributes The CreationTool applies these attributes to the * prototype after having applied the default attributes from the DrawingEditor. */ public void setAttributes(Map<AttributeKey, Object> attributes) { prototypeAttributes = attributes; } /** * Returns the prototype. * * @return See above. */ public Figure getPrototype() { return prototype; } /** * Overridden to set the cursor and reset the figure. * @see AbstractTool#activate(DrawingEditor) */ public void activate(DrawingEditor editor) { super.activate(editor); //getView().clearSelection(); //getView().setCursor(Cursor.getPredefinedCursor(Cursor.CROSSHAIR_CURSOR)); } /** * Overridden to set the cursor and reset the figure. * @see AbstractTool#deactivate(DrawingEditor) */ public void deactivate(DrawingEditor editor) { super.deactivate(editor); if (getView() != null) { getView().setCursor(Cursor.getDefaultCursor()); } if (createdFigure != null) { if (createdFigure instanceof CompositeFigure) { ((CompositeFigure) createdFigure).layout(); } createdFigure = null; } } /** * Handles the figure is not <code>null</code>. * @see MouseListener#mousePressed(MouseEvent) */ public void mousePressed(MouseEvent evt) { super.mousePressed(evt); getView().clearSelection(); createdFigure = createFigure(); Point2D.Double p = constrainPoint(viewToDrawing(anchor)); anchor.x = evt.getX(); anchor.y = evt.getY(); createdFigure.setBounds(p, p); //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); } /** * Handles the figure is not <code>null</code>. * @see MouseMotionListener#mouseDragged(MouseEvent) */ public void mouseDragged(MouseEvent evt) { if (createdFigure != null) { Point2D.Double p = constrainPoint(new Point(evt.getX(), evt.getY())); createdFigure.willChange(); createdFigure.setBounds( constrainPoint(new Point(anchor.x, anchor.y)), p ); createdFigure.changed(); } } /** * Handles the figure is not <code>null</code>. * @see MouseListener#mouseReleased(MouseEvent) */ public void mouseReleased(MouseEvent evt) { if (createdFigure != null) { Rectangle2D.Double bounds = createdFigure.getBounds(); if (bounds.width == 0 && bounds.height == 0) { getDrawing().remove(createdFigure); fireToolDone(); } else { if (Math.abs(anchor.x - evt.getX()) < minimalSizeTreshold.width && Math.abs(anchor.y - evt.getY()) < minimalSizeTreshold.height) { createdFigure.willChange(); createdFigure.setBounds( constrainPoint(new Point(anchor.x, anchor.y)), constrainPoint(new Point( anchor.x + (int) Math.max(bounds.width, minimalSize.width), anchor.y + (int) Math.max(bounds.height, minimalSize.height) )) ); createdFigure.changed(); } getView().addToSelection(createdFigure); if (createdFigure instanceof CompositeFigure) { ((CompositeFigure) createdFigure).layout(); } final Figure addedFigure = createdFigure; final Drawing addedDrawing = getDrawing(); 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(); addedDrawing.add(addedFigure); } }); creationFinished(createdFigure); } } else { fireToolDone(); } } /** * Creates a figure. * * @return See above. */ protected Figure createFigure() { Figure f = (Figure) prototype.clone(); getEditor().applyDefaultAttributesTo(f); if (prototypeAttributes != null) { for (Map.Entry<AttributeKey, Object> entry : prototypeAttributes.entrySet()) { f.setAttribute(entry.getKey(), entry.getValue()); } } return f; } /** * Returns the created figure. * * @return See above. */ protected Figure getCreatedFigure() { return createdFigure; } /** * Returns the added figure. * * @return See above. */ protected Figure getAddedFigure() { return createdFigure; } /** * This method allows subclasses to do perform additional user interactions * after the new figure has been created. * The implementation of this class just invokes fireToolDone. * * @param createdFigure The newly created figure. */ protected void creationFinished(Figure createdFigure) { if (resetToSelect) fireToolDone(); } /** * Implemented as specified by the {@link DrawingCreationTool} I/F. * @see DrawingCreationTool#isResetToSelect() */ public boolean isResetToSelect() { return resetToSelect; } /** * Implemented as specified by the {@link DrawingCreationTool} I/F. * @see DrawingCreationTool#setResetToSelect(boolean) */ public void setResetToSelect(boolean create) { resetToSelect = create; } }