views;
private DrawingView activeView;
private boolean isEnabled = true;
@@ -114,16 +111,16 @@ public DefaultDrawingEditor() {
}
@Override
- public void setTool(Tool newValue) {
- Tool oldValue = tool;
+ public void setTool(BaseTool newValue) {
+ BaseTool oldValue = tool;
if (newValue == tool) {
return;
}
if (tool != null) {
for (DrawingView v : views) {
- v.removeMouseListener(tool);
- v.removeMouseMotionListener(tool);
- v.removeKeyListener(tool);
+ if (tool instanceof MouseListener) v.removeMouseListener((MouseListener) tool);
+ if (tool instanceof MouseMotionListener) v.removeMouseMotionListener((MouseMotionListener) tool);
+ if (tool instanceof KeyListener) v.removeKeyListener((KeyListener) tool);
if (tool instanceof MouseWheelListener) {
v.removeMouseWheelListener((MouseWheelListener) tool);
}
@@ -135,9 +132,9 @@ public void setTool(Tool newValue) {
if (tool != null) {
tool.activate(this);
for (DrawingView v : views) {
- v.addMouseListener(tool);
- v.addMouseMotionListener(tool);
- v.addKeyListener(tool);
+ if (tool instanceof MouseListener) v.addMouseListener((MouseListener) tool);
+ if (tool instanceof MouseMotionListener) v.addMouseMotionListener((MouseMotionListener) tool);
+ if (tool instanceof KeyListener) v.addKeyListener((KeyListener) tool);
if (tool instanceof MouseWheelListener) {
v.addMouseWheelListener((MouseWheelListener) tool);
}
@@ -155,7 +152,7 @@ public void setActiveView(DrawingView newValue) {
}
@Override
- public Tool getTool() {
+ public BaseTool getTool() {
return tool;
}
@@ -204,9 +201,9 @@ public void remove(DrawingView view) {
view.getComponent().removeFocusListener(focusHandler);
views.remove(view);
if (tool != null) {
- view.removeMouseListener(tool);
- view.removeMouseMotionListener(tool);
- view.removeKeyListener(tool);
+ if (tool instanceof MouseListener) view.removeMouseListener((MouseListener) tool);
+ if (tool instanceof MouseMotionListener) view.removeMouseMotionListener((MouseMotionListener) tool);
+ if (tool instanceof KeyListener) view.removeKeyListener((KeyListener) tool);
}
view.removeNotify(this);
if (activeView == view) {
@@ -221,9 +218,9 @@ public void add(DrawingView view) {
view.addNotify(this);
view.getComponent().addFocusListener(focusHandler);
if (tool != null) {
- view.addMouseListener(tool);
- view.addMouseMotionListener(tool);
- view.addKeyListener(tool);
+ if (tool instanceof MouseListener) view.addMouseListener((MouseListener) tool);
+ if (tool instanceof MouseMotionListener) view.addMouseMotionListener((MouseMotionListener) tool);
+ if (tool instanceof KeyListener) view.addKeyListener((KeyListener) tool);
}
updateActiveView();
}
diff --git a/jhotdraw-core/src/main/java/org/jhotdraw/draw/DefaultDrawingView.java b/jhotdraw-core/src/main/java/org/jhotdraw/draw/DefaultDrawingView.java
index de7e77022..64ee1f246 100644
--- a/jhotdraw-core/src/main/java/org/jhotdraw/draw/DefaultDrawingView.java
+++ b/jhotdraw-core/src/main/java/org/jhotdraw/draw/DefaultDrawingView.java
@@ -305,6 +305,7 @@ public DefaultDrawingView() {
setTransferHandler(new DefaultDrawingViewTransferHandler());
setBackground(new Color(0xb0b0b0));
setOpaque(true);
+ setName("drawingCanvas"); // For BDD Testing
}
protected EventHandler createEventHandler() {
diff --git a/jhotdraw-core/src/main/java/org/jhotdraw/draw/DrawingEditor.java b/jhotdraw-core/src/main/java/org/jhotdraw/draw/DrawingEditor.java
index 2776955cd..9b5b7c588 100644
--- a/jhotdraw-core/src/main/java/org/jhotdraw/draw/DrawingEditor.java
+++ b/jhotdraw-core/src/main/java/org/jhotdraw/draw/DrawingEditor.java
@@ -13,6 +13,8 @@
import java.util.*;
import javax.swing.ActionMap;
import javax.swing.InputMap;
+
+import org.jhotdraw.draw.tool.BaseTool;
import org.jhotdraw.draw.tool.Tool;
/**
@@ -157,14 +159,14 @@ public interface DrawingEditor {
*
* This is a bound property.
*/
- void setTool(Tool t);
+ void setTool(BaseTool t);
/**
* Gets the current tool.
*
* This is a bound property.
*/
- Tool getTool();
+ BaseTool getTool();
/**
* Sets the cursor on the view(s) of the drawing editor.
diff --git a/jhotdraw-core/src/main/java/org/jhotdraw/draw/DrawingEditorProxy.java b/jhotdraw-core/src/main/java/org/jhotdraw/draw/DrawingEditorProxy.java
index b7d65bafc..8d47d62e9 100644
--- a/jhotdraw-core/src/main/java/org/jhotdraw/draw/DrawingEditorProxy.java
+++ b/jhotdraw-core/src/main/java/org/jhotdraw/draw/DrawingEditorProxy.java
@@ -17,6 +17,7 @@
import javax.swing.ActionMap;
import javax.swing.InputMap;
import org.jhotdraw.beans.AbstractBean;
+import org.jhotdraw.draw.tool.BaseTool;
import org.jhotdraw.draw.tool.Tool;
/**
@@ -105,12 +106,12 @@ public DrawingView getFocusedView() {
}
@Override
- public void setTool(Tool t) {
+ public void setTool(BaseTool t) {
target.setTool(t);
}
@Override
- public Tool getTool() {
+ public BaseTool getTool() {
return target.getTool();
}
diff --git a/jhotdraw-core/src/main/java/org/jhotdraw/draw/action/AbstractSelectedAction.java b/jhotdraw-core/src/main/java/org/jhotdraw/draw/action/AbstractSelectedAction.java
index c6f23dc34..c4b8820b7 100644
--- a/jhotdraw-core/src/main/java/org/jhotdraw/draw/action/AbstractSelectedAction.java
+++ b/jhotdraw-core/src/main/java/org/jhotdraw/draw/action/AbstractSelectedAction.java
@@ -164,6 +164,8 @@ public void setUpdateEnabledState(boolean newValue) {
* Returns true, if this action automatically updates its enabled
* state to reflect the enabled state of the active {@code DrawingView}.
*/
+
+ //FIXME: Typo
public boolean isUpdatEnabledState() {
return eventHandler != null;
}
diff --git a/jhotdraw-core/src/main/java/org/jhotdraw/draw/event/FigureListener.java b/jhotdraw-core/src/main/java/org/jhotdraw/draw/event/FigureListener.java
index 235f1157a..486ede776 100644
--- a/jhotdraw-core/src/main/java/org/jhotdraw/draw/event/FigureListener.java
+++ b/jhotdraw-core/src/main/java/org/jhotdraw/draw/event/FigureListener.java
@@ -36,12 +36,12 @@ public interface FigureListener extends EventListener {
/**
* Sent when the drawing area used by the figure needs to be repainted.
*/
- public void areaInvalidated(FigureEvent e);
+ default void areaInvalidated(FigureEvent e) {}
/**
* Sent when an attribute of the figure has changed.
*/
- public void attributeChanged(FigureEvent e);
+ default void attributeChanged(FigureEvent e) {}
/**
* Sent when handles of a Figure have been added, removed or replaced.
@@ -51,25 +51,25 @@ public interface FigureListener extends EventListener {
* A Figure should not fire this event, if just the state or the location
* of Handle has changed.
*/
- public void figureHandlesChanged(FigureEvent e);
+ default void figureHandlesChanged(FigureEvent e) {}
/**
* Sent when the geometry (for example the bounds) of the figure has changed.
*/
- public void figureChanged(FigureEvent e);
+ default void figureChanged(FigureEvent e) {}
/**
* Sent when a figure was added to a drawing.
*/
- public void figureAdded(FigureEvent e);
+ default void figureAdded(FigureEvent e) {}
/**
* Sent when a figure was removed from a drawing.
*/
- public void figureRemoved(FigureEvent e);
+ void figureRemoved(FigureEvent e);
/**
* Sent when the figure requests to be removed from a drawing.
*/
- public void figureRequestRemove(FigureEvent e);
+ default void figureRequestRemove(FigureEvent e) {}
}
diff --git a/jhotdraw-core/src/main/java/org/jhotdraw/draw/event/ToolEvent.java b/jhotdraw-core/src/main/java/org/jhotdraw/draw/event/ToolEvent.java
index 7ac75849d..b2c060af6 100644
--- a/jhotdraw-core/src/main/java/org/jhotdraw/draw/event/ToolEvent.java
+++ b/jhotdraw-core/src/main/java/org/jhotdraw/draw/event/ToolEvent.java
@@ -10,6 +10,7 @@
import java.awt.*;
import java.util.*;
import org.jhotdraw.draw.*;
+import org.jhotdraw.draw.tool.BaseTool;
import org.jhotdraw.draw.tool.Tool;
/**
@@ -38,7 +39,7 @@ public class ToolEvent extends EventObject {
/**
* Creates a new instance.
*/
- public ToolEvent(Tool src, DrawingView view, Rectangle invalidatedArea) {
+ public ToolEvent(BaseTool src, DrawingView view, Rectangle invalidatedArea) {
super(src);
this.view = view;
this.invalidatedArea = invalidatedArea;
@@ -47,8 +48,8 @@ public ToolEvent(Tool src, DrawingView view, Rectangle invalidatedArea) {
/**
* Gets the tool which is the source of the event.
*/
- public Tool getTool() {
- return (Tool) getSource();
+ public BaseTool getTool() {
+ return (BaseTool) getSource();
}
/**
diff --git a/jhotdraw-core/src/main/java/org/jhotdraw/draw/figure/AbstractFigure.java b/jhotdraw-core/src/main/java/org/jhotdraw/draw/figure/AbstractFigure.java
index 7602ca32f..ee74a0067 100644
--- a/jhotdraw-core/src/main/java/org/jhotdraw/draw/figure/AbstractFigure.java
+++ b/jhotdraw-core/src/main/java/org/jhotdraw/draw/figure/AbstractFigure.java
@@ -27,6 +27,7 @@
import org.jhotdraw.draw.handle.BoundsOutlineHandle;
import org.jhotdraw.draw.handle.Handle;
import org.jhotdraw.draw.handle.ResizeHandleKit;
+import org.jhotdraw.draw.tool.BaseTool;
import org.jhotdraw.draw.tool.Tool;
import org.jhotdraw.geom.Dimension2DDouble;
@@ -460,7 +461,7 @@ public Collection getActions(Point2D.Double p) {
* Returns null, if no specialized tool is available.
*/
@Override
- public Tool getTool(Point2D.Double p) {
+ public BaseTool getTool(Point2D.Double p) {
return null;
}
diff --git a/jhotdraw-core/src/main/java/org/jhotdraw/draw/figure/Figure.java b/jhotdraw-core/src/main/java/org/jhotdraw/draw/figure/Figure.java
index 2e9b9ab11..12e6c8aa5 100644
--- a/jhotdraw-core/src/main/java/org/jhotdraw/draw/figure/Figure.java
+++ b/jhotdraw-core/src/main/java/org/jhotdraw/draw/figure/Figure.java
@@ -20,6 +20,7 @@
import org.jhotdraw.draw.connector.Connector;
import org.jhotdraw.draw.event.FigureListener;
import org.jhotdraw.draw.handle.Handle;
+import org.jhotdraw.draw.tool.BaseTool;
import org.jhotdraw.draw.tool.Tool;
import org.jhotdraw.geom.Dimension2DDouble;
@@ -411,7 +412,7 @@ public interface Figure extends Cloneable, Serializable {
*
* Returns null, if no specialized tool is available.
*/
- public Tool getTool(Point2D.Double p);
+ public BaseTool getTool(Point2D.Double p);
/**
* Returns a tooltip for the specified location on the figure.
diff --git a/jhotdraw-core/src/main/java/org/jhotdraw/draw/figure/LabelFigure.java b/jhotdraw-core/src/main/java/org/jhotdraw/draw/figure/LabelFigure.java
index 76b13bbab..f2235e9fa 100644
--- a/jhotdraw-core/src/main/java/org/jhotdraw/draw/figure/LabelFigure.java
+++ b/jhotdraw-core/src/main/java/org/jhotdraw/draw/figure/LabelFigure.java
@@ -11,22 +11,35 @@
import java.util.*;
import org.jhotdraw.draw.event.FigureEvent;
import org.jhotdraw.draw.event.FigureListener;
+import org.jhotdraw.draw.tool.BaseTool;
import org.jhotdraw.draw.tool.TextEditingTool;
-import org.jhotdraw.draw.tool.Tool;
+
/**
* A LabelFigure can be used to provide more double clickable area for a
* TextHolderFigure.
*
- * FIXME - Move FigureListener into inner class.
*
* @author Werner Randelshofer
* @version $Id$
*/
-public class LabelFigure extends TextFigure implements FigureListener {
+public class LabelFigure extends TextFigure {
private static final long serialVersionUID = 1L;
private TextHolderFigure target;
+ private final transient EventHandler eventHandler = new EventHandler();
+
+
+ private class EventHandler implements FigureListener {
+ @Override
+ public void figureRemoved(FigureEvent e) {
+ if (e.getFigure() == target) {
+ target.removeFigureListener(this);
+ target = null;
+ }
+ }
+ }
+
/**
* Creates a new instance.
@@ -40,16 +53,19 @@ public LabelFigure(String text) {
setEditable(false);
}
+
public void setLabelFor(TextHolderFigure target) {
if (this.target != null) {
- this.target.removeFigureListener(this);
+ this.target.removeFigureListener(eventHandler);
}
this.target = target;
if (this.target != null) {
- this.target.addFigureListener(this);
+ this.target.addFigureListener(eventHandler);
}
}
+
+
@Override
public TextHolderFigure getLabelFor() {
return (target == null) ? this : target;
@@ -61,37 +77,15 @@ public TextHolderFigure getLabelFor() {
* Returns null, if no specialized tool is available.
*/
@Override
- public Tool getTool(Point2D.Double p) {
- return (target != null && contains(p)) ? new TextEditingTool(target) : null;
+ public BaseTool getTool(Point2D.Double coordinate) {
+ return (target != null && contains(coordinate)) ? new TextEditingTool(target) : null;
}
- @Override
- public void areaInvalidated(FigureEvent e) {
- }
- @Override
- public void attributeChanged(FigureEvent e) {
- }
- @Override
- public void figureAdded(FigureEvent e) {
- }
- @Override
- public void figureChanged(FigureEvent e) {
- }
- @Override
- public void figureRemoved(FigureEvent e) {
- if (e.getFigure() == target) {
- target.removeFigureListener(this);
- target = null;
- }
- }
- @Override
- public void figureRequestRemove(FigureEvent e) {
- }
@Override
public void remap(Map oldToNew, boolean disconnectIfNotInMap) {
@@ -99,14 +93,12 @@ public void remap(Map oldToNew, boolean disconnectIfNotInMap) {
if (target != null) {
Figure newTarget = oldToNew.get(target);
if (newTarget != null) {
- target.removeFigureListener(this);
+ target.removeFigureListener(eventHandler);
target = (TextHolderFigure) newTarget;
- newTarget.addFigureListener(this);
+ newTarget.addFigureListener(eventHandler);
}
}
}
- @Override
- public void figureHandlesChanged(FigureEvent e) {
- }
+
}
diff --git a/jhotdraw-core/src/main/java/org/jhotdraw/draw/figure/TextFigure.java b/jhotdraw-core/src/main/java/org/jhotdraw/draw/figure/TextFigure.java
index 43be4010e..9318aa64f 100644
--- a/jhotdraw-core/src/main/java/org/jhotdraw/draw/figure/TextFigure.java
+++ b/jhotdraw-core/src/main/java/org/jhotdraw/draw/figure/TextFigure.java
@@ -12,6 +12,7 @@
import java.awt.geom.*;
import java.io.*;
import java.util.*;
+
import org.jhotdraw.draw.AttributeKeys;
import static org.jhotdraw.draw.AttributeKeys.*;
import org.jhotdraw.draw.handle.BoundsOutlineHandle;
@@ -19,8 +20,8 @@
import org.jhotdraw.draw.handle.Handle;
import org.jhotdraw.draw.handle.MoveHandle;
import org.jhotdraw.draw.locator.RelativeLocator;
+import org.jhotdraw.draw.tool.BaseTool;
import org.jhotdraw.draw.tool.TextEditingTool;
-import org.jhotdraw.draw.tool.Tool;
import org.jhotdraw.geom.Dimension2DDouble;
import org.jhotdraw.geom.Geom;
import org.jhotdraw.geom.Insets2D;
@@ -40,11 +41,12 @@
public class TextFigure extends AbstractAttributedDecoratedFigure
implements TextHolderFigure {
+private static final int MIN_COLUMN_COUNT = 4;
private static final long serialVersionUID = 1L;
protected Point2D.Double origin = new Point2D.Double();
protected boolean editable = true;
// cache of the TextFigure's layout
- transient protected TextLayout textLayout;
+ protected transient TextLayout textLayout;
/**
* Creates a new instance.
@@ -60,39 +62,41 @@ public TextFigure(String text) {
// DRAWING
@Override
- protected void drawStroke(java.awt.Graphics2D g) {
+ protected void drawStroke(java.awt.Graphics2D graphics2D) {
+ // Text Figures are treated as primitives, they do not support adding strokes.
}
@Override
- protected void drawFill(java.awt.Graphics2D g) {
+ protected void drawFill(java.awt.Graphics2D graphics2D) {
+ // Text Figures do not have a fill area to draw.
}
@Override
- protected void drawText(java.awt.Graphics2D g) {
+ protected void drawText(java.awt.Graphics2D canvas) {
if (getText() != null || isEditable()) {
TextLayout layout = getTextLayout();
- Graphics2D g2 = (Graphics2D) g.create();
+ Graphics2D localGraphics = (Graphics2D) canvas.create();
try {
//Test if world to screen transformation mirrors the text. If so it tries to
//unmirror it.
- if (g2.getTransform().getScaleY() * g2.getTransform().getScaleX() < 0) {
+ if (localGraphics.getTransform().getScaleY() * localGraphics.getTransform().getScaleX() < 0) {
AffineTransform at = new AffineTransform();
at.translate(0, origin.y + layout.getAscent() / 2);
at.scale(1, -1);
at.translate(0, -origin.y - layout.getAscent() / 2);
- g2.transform(at);
+ localGraphics.transform(at);
}
- layout.draw(g2, (float) origin.x, (float) (origin.y + layout.getAscent()));
+ layout.draw(localGraphics, (float) origin.x, (float) (origin.y + layout.getAscent()));
} finally {
- g2.dispose();
+ localGraphics.dispose();
}
}
}
// SHAPE AND BOUNDS
@Override
- public void transform(AffineTransform tx) {
- tx.transform(origin, origin);
+ public void transform(AffineTransform affineTransform) {
+ affineTransform.transform(origin, origin);
}
@Override
@@ -102,25 +106,22 @@ public void setBounds(Point2D.Double anchor, Point2D.Double lead) {
@Override
public boolean figureContains(Point2D.Double p) {
- if (getBounds().contains(p)) {
- return true;
- }
- return false;
+ return getBounds().contains(p);
}
protected TextLayout getTextLayout() {
if (textLayout == null) {
String text = getText();
- if (text == null || text.length() == 0) {
+ if (text == null || text.isEmpty()) {
text = " ";
}
- FontRenderContext frc = getFontRenderContext();
+ FontRenderContext fontRenderContext = getFontRenderContext();
HashMap textAttributes = new HashMap<>();
textAttributes.put(TextAttribute.FONT, getFont());
- if (get(FONT_UNDERLINE)) {
+ if (get(FONT_UNDERLINE) != null && get(FONT_UNDERLINE)) {
textAttributes.put(TextAttribute.UNDERLINE, TextAttribute.UNDERLINE_LOW_ONE_PIXEL);
}
- textLayout = new TextLayout(text, textAttributes, frc);
+ textLayout = new TextLayout(text, textAttributes, fontRenderContext);
}
return textLayout;
}
@@ -128,15 +129,17 @@ protected TextLayout getTextLayout() {
@Override
public Rectangle2D.Double getBounds() {
TextLayout layout = getTextLayout();
- Rectangle2D.Double r = new Rectangle2D.Double(origin.x, origin.y, layout.getAdvance(),
- layout.getAscent() + layout.getDescent());
- return r;
+ return new Rectangle2D.Double(
+ origin.x, origin.y,
+ layout.getAdvance(),
+ layout.getAscent() + layout.getDescent()
+ );
}
@Override
public Dimension2DDouble getPreferredSize() {
- Rectangle2D.Double b = getBounds();
- return new Dimension2DDouble(b.width, b.height);
+ Rectangle2D.Double bounds = getBounds();
+ return new Dimension2DDouble(bounds.width, bounds.height);
}
@Override
@@ -154,23 +157,34 @@ protected Rectangle2D.Double getFigureDrawingArea() {
return getBounds();
} else {
TextLayout layout = getTextLayout();
- Rectangle2D.Double r = new Rectangle2D.Double(
+ Rectangle2D.Double rectangle = new Rectangle2D.Double(
origin.x, origin.y, layout.getAdvance(), layout.getAscent());
Rectangle2D lBounds = layout.getBounds();
if (!lBounds.isEmpty() && !Double.isNaN(lBounds.getX())) {
- r.add(new Rectangle2D.Double(
+ rectangle.add(new Rectangle2D.Double(
lBounds.getX() + origin.x,
(lBounds.getY() + origin.y + layout.getAscent()),
lBounds.getWidth(),
lBounds.getHeight()));
}
// grow by two pixels to take antialiasing into account
- Geom.grow(r, 2d, 2d);
- return r;
+ Geom.grow(rectangle, 2d, 2d);
+ return rectangle;
}
}
+ public void restoreTransformTo(Point2D.Double geometry) {
+ origin.x = geometry.x;
+ origin.y = geometry.y;
+ }
+
+ /**
+ * @deprecated
+ * Old implementation is not typesafe.
+ * Use {@link #restoreTransformTo(Point2D.Double)} instead.
+ */
@Override
+ @Deprecated
public void restoreTransformTo(Object geometry) {
Point2D.Double p = (Point2D.Double) geometry;
origin.x = p.x;
@@ -202,8 +216,7 @@ public void setText(String newText) {
@Override
public int getTextColumns() {
- //return (getText() == null) ? 4 : Math.max(getText().length(), 4);
- return 4;
+ return MIN_COLUMN_COUNT;
}
/**
@@ -241,7 +254,7 @@ public Color getFillColor() {
@Override
public void setFontSize(float size) {
- set(FONT_SIZE, new Double(size));
+ set(FONT_SIZE, (double) size);
}
@Override
@@ -255,25 +268,22 @@ public boolean isEditable() {
return editable;
}
- public void setEditable(boolean b) {
- this.editable = b;
+ public void setEditable(boolean editable) {
+ this.editable = editable;
}
@Override
public Collection createHandles(int detailLevel) {
LinkedList handles = new LinkedList<>();
- switch (detailLevel) {
- case -1:
- handles.add(new BoundsOutlineHandle(this, false, true));
- break;
- case 0:
- handles.add(new BoundsOutlineHandle(this));
- handles.add(new MoveHandle(this, RelativeLocator.northWest()));
- handles.add(new MoveHandle(this, RelativeLocator.northEast()));
- handles.add(new MoveHandle(this, RelativeLocator.southWest()));
- handles.add(new MoveHandle(this, RelativeLocator.southEast()));
- handles.add(new FontSizeHandle(this));
- break;
+
+ if (detailLevel == -1) handles.add(new BoundsOutlineHandle(this, false, true));
+ else if (detailLevel == 0) {
+ handles.add(new BoundsOutlineHandle(this));
+ handles.add(new MoveHandle(this, RelativeLocator.northWest()));
+ handles.add(new MoveHandle(this, RelativeLocator.northEast()));
+ handles.add(new MoveHandle(this, RelativeLocator.southWest()));
+ handles.add(new MoveHandle(this, RelativeLocator.southEast()));
+ handles.add(new FontSizeHandle(this));
}
return handles;
}
@@ -284,10 +294,9 @@ public Collection createHandles(int detailLevel) {
* Returns null, if no specialized tool is available.
*/
@Override
- public Tool getTool(Point2D.Double p) {
+ public BaseTool getTool(Point2D.Double p) {
if (isEditable() && contains(p)) {
- TextEditingTool t = new TextEditingTool(this);
- return t;
+ return new TextEditingTool(this);
}
return null;
}
@@ -309,25 +318,44 @@ protected void validate() {
}
@Override
- public void read(DOMInput in) throws IOException {
+ public void read(DOMInput input) throws IOException {
setBounds(
- new Point2D.Double(in.getAttribute("x", 0d), in.getAttribute("y", 0d)),
+ new Point2D.Double(input.getAttribute("x", 0d), input.getAttribute("y", 0d)),
new Point2D.Double(0, 0));
- readAttributes(in);
- readDecorator(in);
+ readAttributes(input);
+ readDecorator(input);
invalidate();
}
@Override
public void write(DOMOutput out) throws IOException {
- Rectangle2D.Double b = getBounds();
- out.addAttribute("x", b.x);
- out.addAttribute("y", b.y);
+ Rectangle2D.Double bounds = getBounds();
+ out.addAttribute("x", bounds.x);
+ out.addAttribute("y", bounds.y);
writeAttributes(out);
writeDecorator(out);
}
- @Override
+
+ public static TextFigure createFrom(TextFigure figureToDuplicate) {
+ TextFigure duplicate = new TextFigure();
+ duplicate.setText(figureToDuplicate.getText());
+ duplicate.origin = (figureToDuplicate.origin == null) ? null : (Point2D.Double) figureToDuplicate.origin;
+ duplicate.setAttributes(figureToDuplicate.getAttributes());
+ duplicate.textLayout = figureToDuplicate.textLayout;
+ return duplicate;
+ }
+
+
+ /**
+ * @deprecated Use {@link #createFrom(TextFigure)} instead.
+ * This method is kept around for framework compatibility.
+ * */
+ // Using .clone is inherently flawed but unfortunately legacy concerns keep it around.
+ // I've deprecated it with reference to the copy factory above.
+ @Deprecated
+ @Override
+ @SuppressWarnings("java:S2975")
public TextFigure clone() {
TextFigure that = (TextFigure) super.clone();
that.origin = (Point2D.Double) this.origin.clone();
diff --git a/jhotdraw-core/src/main/java/org/jhotdraw/draw/text/AbstractEditableFloatingText.java b/jhotdraw-core/src/main/java/org/jhotdraw/draw/text/AbstractEditableFloatingText.java
new file mode 100644
index 000000000..a245cb3d5
--- /dev/null
+++ b/jhotdraw-core/src/main/java/org/jhotdraw/draw/text/AbstractEditableFloatingText.java
@@ -0,0 +1,49 @@
+package org.jhotdraw.draw.text;
+
+import org.jhotdraw.draw.DrawingView;
+import org.jhotdraw.draw.event.FigureAdapter;
+import org.jhotdraw.draw.event.FigureEvent;
+import org.jhotdraw.draw.event.FigureListener;
+import org.jhotdraw.draw.figure.TextHolderFigure;
+
+import javax.swing.*;
+import java.awt.*;
+
+public abstract class AbstractEditableFloatingText {
+ private DrawingView view;
+ private TextHolderFigure editedFigure;
+
+ public abstract JComponent getEditorComponent();
+ protected abstract void updateWidget();
+ protected abstract DrawingView getDrawingView();
+
+
+
+ private FigureListener figureHandler = new FigureAdapter() {
+ @Override
+ public void attributeChanged(FigureEvent e) {
+ updateWidget();
+ }
+ };
+
+
+ /**
+ * Removes the overlay.
+ */
+ public void endOverlay() {
+ view = getDrawingView();
+ view.getComponent().requestFocus();
+ JComponent component = getEditorComponent();
+ if (component != null) {
+ component.setVisible(false);
+ view.getComponent().remove(component);
+ Rectangle bounds = component.getBounds();
+ view.getComponent().repaint(bounds.x, bounds.y, bounds.width, bounds.height);
+ }
+ if (editedFigure != null) {
+ editedFigure.removeFigureListener(figureHandler);
+ editedFigure = null;
+ }
+ }
+
+}
diff --git a/jhotdraw-core/src/main/java/org/jhotdraw/draw/text/FloatingTextArea.java b/jhotdraw-core/src/main/java/org/jhotdraw/draw/text/FloatingTextArea.java
index 57d3ac765..e596e083c 100644
--- a/jhotdraw-core/src/main/java/org/jhotdraw/draw/text/FloatingTextArea.java
+++ b/jhotdraw-core/src/main/java/org/jhotdraw/draw/text/FloatingTextArea.java
@@ -10,9 +10,8 @@
import org.jhotdraw.draw.figure.TextHolderFigure;
import java.awt.*;
import java.awt.geom.*;
-import javax.swing.BorderFactory;
-import javax.swing.JScrollPane;
-import javax.swing.JTextArea;
+import javax.swing.*;
+
import org.jhotdraw.draw.*;
import org.jhotdraw.draw.event.FigureAdapter;
import org.jhotdraw.draw.event.FigureEvent;
@@ -39,7 +38,7 @@
* @author Werner Randelshofer
* @version $Id: FloatingTextArea.java -1 $
*/
-public class FloatingTextArea {
+public class FloatingTextArea extends AbstractEditableFloatingText {
/**
* A scroll pane to allow for vertical scrolling while editing
@@ -88,6 +87,17 @@ public void requestFocus() {
textArea.requestFocus();
}
+ @Override
+ public JComponent getEditorComponent() {
+ return editScrollContainer;
+ }
+
+ @Override
+ protected DrawingView getDrawingView() {
+ return view;
+ }
+
+
/**
* Creates the overlay for the given Container using a
* specific font.
@@ -105,6 +115,8 @@ public void createOverlay(DrawingView view, TextHolderFigure figure) {
}
}
+
+
protected void updateWidget() {
Font f = editedFigure.getFont();
// FIXME - Should scale with fractional value!
@@ -148,20 +160,4 @@ public Dimension getPreferredSize(int cols) {
return new Dimension(textArea.getWidth(), textArea.getHeight());
}
- /**
- * Removes the overlay.
- */
- public void endOverlay() {
- view.getComponent().requestFocus();
- if (editScrollContainer != null) {
- editScrollContainer.setVisible(false);
- view.getComponent().remove(editScrollContainer);
- Rectangle bounds = editScrollContainer.getBounds();
- view.getComponent().repaint(bounds.x, bounds.y, bounds.width, bounds.height);
- }
- if (editedFigure != null) {
- editedFigure.removeFigureListener(figureHandler);
- editedFigure = null;
- }
- }
}
diff --git a/jhotdraw-core/src/main/java/org/jhotdraw/draw/text/FloatingTextField.java b/jhotdraw-core/src/main/java/org/jhotdraw/draw/text/FloatingTextField.java
index e2c423d94..d84815ddd 100644
--- a/jhotdraw-core/src/main/java/org/jhotdraw/draw/text/FloatingTextField.java
+++ b/jhotdraw-core/src/main/java/org/jhotdraw/draw/text/FloatingTextField.java
@@ -43,7 +43,7 @@
* @author Werner Randelshofer
* @version $Id: FloatingTextField.java -1 $
*/
-public class FloatingTextField {
+public class FloatingTextField extends AbstractEditableFloatingText {
private TextHolderFigure editedFigure;
private JTextField textField;
@@ -63,6 +63,16 @@ public void requestFocus() {
textField.requestFocus();
}
+ @Override
+ public JComponent getEditorComponent() {
+ return textField;
+ }
+
+ @Override
+ protected DrawingView getDrawingView() {
+ return view;
+ }
+
/**
* Creates the overlay for the given Container using a
* specific font.
@@ -79,30 +89,33 @@ public void createOverlay(DrawingView view, TextHolderFigure figure) {
updateWidget();
}
+
protected void updateWidget() {
- Font font = editedFigure.getFont();
- font = font.deriveFont(font.getStyle(), (float) (editedFigure.getFontSize() * view.getScaleFactor()));
- textField.setFont(font);
+ if (editedFigure == null) return;
+ Font fontOnFigure = editedFigure.getFont();
+ fontOnFigure = fontOnFigure.deriveFont(fontOnFigure.getStyle(), (float) (editedFigure.getFontSize() * view.getScaleFactor()));
+ textField.setFont(fontOnFigure);
textField.setForeground(editedFigure.getTextColor());
textField.setBackground(editedFigure.getFillColor());
- Rectangle2D.Double fDrawBounds = editedFigure.getBounds();
- Point2D.Double fDrawLoc = new Point2D.Double(fDrawBounds.getX(), fDrawBounds.getY());
+ Rectangle2D.Double fieldDrawBounds = editedFigure.getBounds();
+ Point2D.Double fieldDrawLocation = new Point2D.Double(fieldDrawBounds.getX(), fieldDrawBounds.getY());
if (editedFigure.get(TRANSFORM) != null) {
- editedFigure.get(TRANSFORM).transform(fDrawLoc, fDrawLoc);
+ editedFigure.get(TRANSFORM).transform(fieldDrawLocation, fieldDrawLocation);
}
- Point fViewLoc = view.drawingToView(fDrawLoc);
- Rectangle fViewBounds = view.drawingToView(fDrawBounds);
- fViewBounds.x = fViewLoc.x;
- fViewBounds.y = fViewLoc.y;
- Dimension tfDim = textField.getPreferredSize();
- Insets tfInsets = textField.getInsets();
- float fontBaseline = textField.getGraphics().getFontMetrics(font).getMaxAscent();
- double fBaseline = editedFigure.getBaseline() * view.getScaleFactor();
+ Point fieldViewLocation = view.drawingToView(fieldDrawLocation);
+ Rectangle fieldViewBounds = view.drawingToView(fieldDrawBounds);
+ fieldViewBounds.x = fieldViewLocation.x;
+ fieldViewBounds.y = fieldViewLocation.y;
+ Dimension textFieldDimensions = textField.getPreferredSize();
+ Insets textFieldInsets = textField.getInsets();
+ if (textField.getGraphics() == null) return;
+ float fontBaseline = textField.getGraphics().getFontMetrics(fontOnFigure).getMaxAscent();
+ double fieldBaseline = editedFigure.getBaseline() * view.getScaleFactor();
textField.setBounds(
- fViewBounds.x - tfInsets.left,
- fViewBounds.y - tfInsets.top - (int) (fontBaseline - fBaseline),
- Math.max(fViewBounds.width + tfInsets.left + tfInsets.right, tfDim.width),
- Math.max(fViewBounds.height + tfInsets.top + tfInsets.bottom, tfDim.height)
+ fieldViewBounds.x - textFieldInsets.left,
+ fieldViewBounds.y - textFieldInsets.top - (int) (fontBaseline - fieldBaseline),
+ Math.max(fieldViewBounds.width + textFieldInsets.left + textFieldInsets.right, textFieldDimensions.width),
+ Math.max(fieldViewBounds.height + textFieldInsets.top + textFieldInsets.bottom, textFieldDimensions.height)
);
}
@@ -139,20 +152,5 @@ public Dimension getPreferredSize(int cols) {
return textField.getPreferredSize();
}
- /**
- * Removes the overlay.
- */
- public void endOverlay() {
- view.getComponent().requestFocus();
- if (textField != null) {
- textField.setVisible(false);
- view.getComponent().remove(textField);
- Rectangle bounds = textField.getBounds();
- view.getComponent().repaint(bounds.x, bounds.y, bounds.width, bounds.height);
- }
- if (editedFigure != null) {
- editedFigure.removeFigureListener(figureHandler);
- editedFigure = null;
- }
- }
+
}
diff --git a/jhotdraw-core/src/main/java/org/jhotdraw/draw/tool/AbstractCreationTool.java b/jhotdraw-core/src/main/java/org/jhotdraw/draw/tool/AbstractCreationTool.java
new file mode 100644
index 000000000..821e736c3
--- /dev/null
+++ b/jhotdraw-core/src/main/java/org/jhotdraw/draw/tool/AbstractCreationTool.java
@@ -0,0 +1,170 @@
+package org.jhotdraw.draw.tool;
+
+import org.jhotdraw.draw.AttributeKey;
+import org.jhotdraw.draw.DrawingEditor;
+import org.jhotdraw.draw.DrawingView;
+import org.jhotdraw.draw.figure.CompositeFigure;
+import org.jhotdraw.draw.figure.Figure;
+import org.jhotdraw.util.ResourceBundleUtil;
+
+import java.awt.*;
+import java.awt.event.MouseEvent;
+import java.awt.geom.Point2D;
+import java.util.Map;
+
+
+
+public abstract class AbstractCreationTool extends BaseToolImpl implements ClickListeningTool {
+
+ protected boolean isWorking;
+ protected Point anchor = new Point();
+ protected String presentationName;
+
+
+ /**
+ * Attributes to be applied to the created ConnectionFigure. These attributes override the
+ * default attributes of the DrawingEditor.
+ */
+ protected Map, Object> prototypeAttributes;
+ /**
+ * The prototype for new figures.
+ */
+ protected Figure prototype;
+ /**
+ * The created figure.
+ */
+ protected Figure createdFigure;
+ /**
+ * If this is set to false, the CreationTool does not fire toolDone after a new Figure has been
+ * created. This allows to create multiple figures consecutively.
+ */
+ private boolean isToolDoneAfterCreation = true;
+
+ public AbstractCreationTool(Figure prototype, Map, Object> prototypeAttributes, String name) {
+ super();
+ this.prototype = prototype;
+ this.prototypeAttributes = prototypeAttributes;
+
+ if (name == null) {
+ ResourceBundleUtil labels = ResourceBundleUtil.getBundle("org.jhotdraw.draw.Labels");
+ name = labels.getString("edit.createFigure.text");
+ }
+ }
+
+ public AbstractCreationTool(Figure prototype) {
+ this(prototype, null, null);
+ }
+
+
+ public AbstractCreationTool(String prototypeClassName, Map, 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.getBundle("org.jhotdraw.draw.Labels");
+ name = labels.getString("edit.createFigure.text");
+ }
+ this.presentationName = name;
+ }
+
+ public AbstractCreationTool(Figure prototype, Map, Object> attributes) {
+ this(prototype, attributes, null);
+ }
+
+ public Figure getPrototype() {
+ return prototype;
+ }
+
+ @Override
+ public void activate(DrawingEditor editor) {
+ super.activate(editor);
+ if (getView() != null) {
+ getView().setCursor(Cursor.getPredefinedCursor(Cursor.CROSSHAIR_CURSOR));
+ }
+ }
+
+ @Override
+ 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;
+ }
+ }
+
+
+ @Override
+ public void mouseReleased(MouseEvent e) {
+ isWorking = false;
+ }
+
+
+
+ @SuppressWarnings("unchecked")
+ protected Figure createFigure() {
+ Figure f = prototype.clone();
+ getEditor().applyDefaultAttributesTo(f);
+ if (prototypeAttributes != null) {
+ for (Map.Entry, Object> entry : prototypeAttributes.entrySet()) {
+ f.set((AttributeKey) entry.getKey(), entry.getValue());
+ }
+ }
+ return f;
+ }
+
+ protected Figure getCreatedFigure() {
+ return createdFigure;
+ }
+
+ protected Figure getAddedFigure() {
+ return createdFigure;
+ }
+
+ /**
+ * This method allows subclasses to do perform additonal user interactions after the new figure
+ * has been created. The implementation of this class just invokes fireToolDone.
+ */
+ protected void creationFinished(Figure createdFigure) {
+ if (createdFigure.isSelectable()) {
+ getView().addToSelection(createdFigure);
+ }
+ if (isToolDoneAfterCreation()) {
+ fireToolDone();
+ }
+ }
+
+ /**
+ * If this is set to false, the CreationTool does not fire toolDone after a new Figure has been
+ * created. This allows to create multiple figures consecutively.
+ */
+ public void setToolDoneAfterCreation(boolean newValue) {
+ boolean oldValue = isToolDoneAfterCreation;
+ isToolDoneAfterCreation = newValue;
+ }
+
+ /**
+ * Returns true, if this tool fires toolDone immediately after a new figure has been created.
+ */
+ public boolean isToolDoneAfterCreation() {
+ return isToolDoneAfterCreation;
+ }
+
+ @Override
+ public void updateCursor(DrawingView view, Point p) {
+ if (view.isEnabled()) {
+ view.setCursor(Cursor.getPredefinedCursor(Cursor.CROSSHAIR_CURSOR));
+ } else {
+ view.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
+ }
+ }
+}
diff --git a/jhotdraw-core/src/main/java/org/jhotdraw/draw/tool/AbstractTool.java b/jhotdraw-core/src/main/java/org/jhotdraw/draw/tool/AbstractTool.java
index a9599de68..1e3fe67eb 100644
--- a/jhotdraw-core/src/main/java/org/jhotdraw/draw/tool/AbstractTool.java
+++ b/jhotdraw-core/src/main/java/org/jhotdraw/draw/tool/AbstractTool.java
@@ -36,175 +36,29 @@
* @author Werner Randelshofer
* @version $Id$
*/
-public abstract class AbstractTool extends AbstractBean implements Tool {
+public abstract class AbstractTool extends BaseToolImpl implements Tool {
private static final long serialVersionUID = 1L;
- /**
- * This is set to true, if this is the active tool of the editor.
- */
- private boolean isActive;
/**
* This is set to true, while the tool is doing some work. This prevents the currentView from
* being changed when a mouseEnter event is received.
*/
protected boolean isWorking;
- protected DrawingEditor editor;
protected Point anchor = new Point();
- protected EventListenerList listenerList = new EventListenerList();
- private DrawingEditorProxy editorProxy;
/*
private PropertyChangeListener editorHandler;
private PropertyChangeListener viewHandler;
*/
- /**
- * The input map of the tool.
- */
- private InputMap inputMap;
- /**
- * The action map of the tool.
- */
- private ActionMap actionMap;
/**
* Creates a new instance.
*/
public AbstractTool() {
- editorProxy = new DrawingEditorProxy();
+ super();
setInputMap(createInputMap());
setActionMap(createActionMap());
}
- public void addUndoableEditListener(UndoableEditListener l) {
- listenerList.add(UndoableEditListener.class, l);
- }
-
- public void removeUndoableEditListener(UndoableEditListener l) {
- listenerList.remove(UndoableEditListener.class, l);
- }
-
- @Override
- public void activate(DrawingEditor editor) {
- this.editor = editor;
- editorProxy.setTarget(editor);
- isActive = true;
- // Repaint all handles
- for (DrawingView v : editor.getDrawingViews()) {
- v.repaintHandles();
- }
- }
-
- @Override
- public void deactivate(DrawingEditor editor) {
- this.editor = editor;
- editorProxy.setTarget(null);
- isActive = false;
- }
-
- public boolean isActive() {
- return isActive;
- }
-
- protected DrawingView getView() {
- return editor.getActiveView();
- }
-
- protected DrawingEditor getEditor() {
- return editor;
- }
-
- protected Drawing getDrawing() {
- return getView().getDrawing();
- }
-
- protected Point2D.Double viewToDrawing(Point p) {
- return constrainPoint(getView().viewToDrawing(p));
- }
-
- protected Point2D.Double constrainPoint(Point p, Figure... figure) {
- return constrainPoint(getView().viewToDrawing(p), figure);
- }
-
- protected Point2D.Double constrainPoint(Point2D.Double p, Figure... figure) {
- if (getView() == null) {
- return p;
- }
- return getView().getConstrainer() == null ? p : getView().getConstrainer().constrainPoint(p, figure);
- }
-
- /**
- * Sets the InputMap for the Tool.
- *
- * @see #keyPressed
- * @see #setActionMap
- */
- public void setInputMap(InputMap newValue) {
- inputMap = newValue;
- }
-
- /**
- * Gets the input map of the Tool
- */
- public InputMap getInputMap() {
- return inputMap;
- }
-
- /**
- * Sets the ActionMap for the Tool.
- *
- * @see #keyPressed
- */
- public void setActionMap(ActionMap newValue) {
- actionMap = newValue;
- }
-
- /**
- * Gets the action map of the Tool
- */
- public ActionMap getActionMap() {
- return actionMap;
- }
-
- /**
- * Deletes the selection. Depending on the tool, this could be selected figures, selected points
- * or selected text.
- */
- @Override
- public void editDelete() {
- getView().getDrawing().removeAll(getView().getSelectedFigures());
- }
-
- /**
- * Cuts the selection into the clipboard. Depending on the tool, this could be selected figures,
- * selected points or selected text.
- */
- @Override
- public void editCut() {
- }
-
- /**
- * Copies the selection into the clipboard. Depending on the tool, this could be selected
- * figures, selected points or selected text.
- */
- @Override
- public void editCopy() {
- }
-
- /**
- * Duplicates the selection. Depending on the tool, this could be selected figures, selected
- * points or selected text.
- */
- @Override
- public void editDuplicate() {
- }
-
- /**
- * Pastes the contents of the clipboard. Depending on the tool, this could be selected figures,
- * selected points or selected text.
- */
- @Override
- public void editPaste() {
- }
-
@Override
public void keyReleased(KeyEvent evt) {
fireToolDone();
@@ -259,26 +113,6 @@ public void keyPressed(KeyEvent evt) {
}
}
- /**
- * Override this method to create a tool-specific input map, which overrides the input map of
- * the drawing edtior.
- *
- * The implementation of this class returns null.
- */
- protected InputMap createInputMap() {
- return null;
- }
-
- /**
- * Override this method to create a tool-specific action map, which overrides the action map of
- * the drawing edtior.
- *
- * The implementation of this class returns null.
- */
- protected ActionMap createActionMap() {
- return null;
- }
-
@Override
public void mouseClicked(MouseEvent evt) {
}
@@ -312,171 +146,4 @@ public void mouseReleased(MouseEvent evt) {
isWorking = false;
}
- @Override
- public void addToolListener(ToolListener l) {
- listenerList.add(ToolListener.class, l);
- }
-
- @Override
- public void removeToolListener(ToolListener l) {
- listenerList.remove(ToolListener.class, l);
- }
-
- /**
- * Notify all listenerList that have registered interest for notification on this event type.
- */
- protected void fireToolStarted(DrawingView view) {
- ToolEvent event = null;
- // Notify all listeners that have registered interest for
- // Guaranteed to return a non-null array
- Object[] listeners = listenerList.getListenerList();
- // Process the listeners last to first, notifying
- // those that are interested in this event
- for (int i = listeners.length - 2; i >= 0; i -= 2) {
- if (listeners[i] == ToolListener.class) {
- // Lazily create the event:
- if (event == null) {
- event = new ToolEvent(this, view, new Rectangle(0, 0, -1, -1));
- }
- ((ToolListener) listeners[i + 1]).toolStarted(event);
- }
- }
- }
-
- /**
- * Notify all listenerList that have registered interest for notification on this event type.
- */
- protected void fireToolDone() {
- ToolEvent event = null;
- // Notify all listeners that have registered interest for
- // Guaranteed to return a non-null array
- Object[] listeners = listenerList.getListenerList();
- // Process the listeners last to first, notifying
- // those that are interested in this event
- for (int i = listeners.length - 2; i >= 0; i -= 2) {
- if (listeners[i] == ToolListener.class) {
- // Lazily create the event:
- if (event == null) {
- event = new ToolEvent(this, getView(), new Rectangle(0, 0, -1, -1));
- }
- ((ToolListener) listeners[i + 1]).toolDone(event);
- }
- }
- }
-
- /**
- * Notify all listenerList that have registered interest for notification on this event type.
- */
- protected void fireAreaInvalidated(Rectangle2D.Double r) {
- Point p1 = getView().drawingToView(new Point2D.Double(r.x, r.y));
- Point p2 = getView().drawingToView(new Point2D.Double(r.x + r.width, r.y + r.height));
- fireAreaInvalidated(
- new Rectangle(p1.x, p1.y, p2.x - p1.x, p2.y - p1.y));
- }
-
- /**
- * Notify all listenerList that have registered interest for notification on this event type.
- */
- protected void fireAreaInvalidated(Rectangle invalidatedArea) {
- ToolEvent event = null;
- // Notify all listeners that have registered interest for
- // Guaranteed to return a non-null array
- Object[] listeners = listenerList.getListenerList();
- // Process the listeners last to first, notifying
- // those that are interested in this event
- for (int i = listeners.length - 2; i >= 0; i -= 2) {
- if (listeners[i] == ToolListener.class) {
- // Lazily create the event:
- if (event == null) {
- event = new ToolEvent(this, getView(), invalidatedArea);
- }
- ((ToolListener) listeners[i + 1]).areaInvalidated(event);
- }
- }
- }
-
- /**
- * Notify all listenerList that have registered interest for notification on this event type.
- *
- * Note: This method only fires an event, if the invalidated area is outside of the canvas
- * bounds.
- */
- protected void maybeFireBoundsInvalidated(Rectangle invalidatedArea) {
- Drawing d = getDrawing();
- Rectangle2D.Double canvasBounds = new Rectangle2D.Double(0, 0, 0, 0);
- if (d.get(CANVAS_WIDTH) != null) {
- canvasBounds.width += d.get(CANVAS_WIDTH);
- }
- if (d.get(CANVAS_HEIGHT) != null) {
- canvasBounds.height += d.get(CANVAS_HEIGHT);
- }
- if (!canvasBounds.contains(invalidatedArea)) {
- fireBoundsInvalidated(invalidatedArea);
- }
- }
-
- /**
- * Notify all listenerList that have registered interest for notification on this event type.
- */
- protected void fireBoundsInvalidated(Rectangle invalidatedArea) {
- ToolEvent event = null;
- // Notify all listeners that have registered interest for
- // Guaranteed to return a non-null array
- Object[] listeners = listenerList.getListenerList();
- // Process the listeners last to first, notifying
- // those that are interested in this event
- for (int i = listeners.length - 2; i >= 0; i -= 2) {
- if (listeners[i] == ToolListener.class) {
- // Lazily create the event:
- if (event == null) {
- event = new ToolEvent(this, getView(), invalidatedArea);
- }
- ((ToolListener) listeners[i + 1]).boundsInvalidated(event);
- }
- }
- }
-
- @Override
- public void draw(Graphics2D g) {
- }
-
- public void updateCursor(DrawingView view, Point p) {
- if (view.isEnabled()) {
- Handle handle = view.findHandle(p);
- if (handle != null) {
- view.setCursor(handle.getCursor());
- } else {
- Figure figure = view.findFigure(p);
- Point2D.Double point = view.viewToDrawing(p);
- Drawing drawing = view.getDrawing();
- while (figure != null && !figure.isSelectable()) {
- figure = drawing.findFigureBehind(point, figure);
- }
- if (figure != null) {
- view.setCursor(figure.getCursor(view.viewToDrawing(p)));
- } else {
- view.setCursor(Cursor.getDefaultCursor());
- }
- }
- } else {
- view.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
- }
- }
-
- @Override
- public String getToolTipText(DrawingView view, MouseEvent evt) {
- return null;
- }
-
- /**
- * Returns true, if this tool lets the user interact with handles.
- *
- * Handles may draw differently, if interaction is not possible.
- *
- * @return True, if this tool supports interaction with the handles.
- */
- @Override
- public boolean supportsHandleInteraction() {
- return false;
- }
}
diff --git a/jhotdraw-core/src/main/java/org/jhotdraw/draw/tool/BaseTool.java b/jhotdraw-core/src/main/java/org/jhotdraw/draw/tool/BaseTool.java
new file mode 100644
index 000000000..a481dca04
--- /dev/null
+++ b/jhotdraw-core/src/main/java/org/jhotdraw/draw/tool/BaseTool.java
@@ -0,0 +1,90 @@
+package org.jhotdraw.draw.tool;
+
+import org.jhotdraw.draw.DrawingEditor;
+import org.jhotdraw.draw.DrawingView;
+import org.jhotdraw.draw.event.ToolListener;
+
+import java.awt.*;
+import java.awt.event.MouseEvent;
+
+public interface BaseTool {
+ /**
+ * Activates the tool for the given editor. This method is called
+ * whenever the user switches to this tool.
+ */
+ void activate(DrawingEditor editor);
+
+ /**
+ * Deactivates the tool. This method is called whenever the user
+ * switches to another tool.
+ */
+ void deactivate(DrawingEditor editor);
+
+ /**
+ * Adds a listener for this tool.
+ */
+ void addToolListener(ToolListener l);
+
+ /**
+ * Removes a listener for this tool.
+ */
+ void removeToolListener(ToolListener l);
+
+ /**
+ * Draws the tool.
+ */
+ void draw(Graphics2D g);
+
+ /**
+ * Deletes the selection.
+ * Depending on the tool, this could be selected figures, selected points
+ * or selected text.
+ */
+ void editDelete();
+
+ /**
+ * Cuts the selection into the clipboard.
+ * Depending on the tool, this could be selected figures, selected points
+ * or selected text.
+ */
+ void editCut();
+
+ /**
+ * Copies the selection into the clipboard.
+ * Depending on the tool, this could be selected figures, selected points
+ * or selected text.
+ */
+ void editCopy();
+
+ /**
+ * Duplicates the selection.
+ * Depending on the tool, this could be selected figures, selected points
+ * or selected text.
+ */
+ void editDuplicate();
+
+ /**
+ * Pastes the contents of the clipboard.
+ * Depending on the tool, this could be selected figures, selected points
+ * or selected text.
+ */
+ void editPaste();
+
+ /**
+ * Returns the tooltip text for a mouse event on a drawing view.
+ *
+ * @param view A drawing view.
+ * @param evt A mouse event.
+ * @return A tooltip text or null.
+ */
+ String getToolTipText(DrawingView view, MouseEvent evt);
+
+ /**
+ * Returns true, if this tool lets the user interact with handles.
+ *
+ * Handles may draw differently, if interaction is not possible.
+ *
+ * @return True, if this tool supports interaction with the handles.
+ */
+ boolean supportsHandleInteraction();
+}
diff --git a/jhotdraw-core/src/main/java/org/jhotdraw/draw/tool/BaseToolImpl.java b/jhotdraw-core/src/main/java/org/jhotdraw/draw/tool/BaseToolImpl.java
new file mode 100644
index 000000000..fd8a2c9a3
--- /dev/null
+++ b/jhotdraw-core/src/main/java/org/jhotdraw/draw/tool/BaseToolImpl.java
@@ -0,0 +1,361 @@
+package org.jhotdraw.draw.tool;
+
+import org.jhotdraw.beans.AbstractBean;
+import org.jhotdraw.draw.Drawing;
+import org.jhotdraw.draw.DrawingEditor;
+import org.jhotdraw.draw.DrawingEditorProxy;
+import org.jhotdraw.draw.DrawingView;
+import org.jhotdraw.draw.event.ToolEvent;
+import org.jhotdraw.draw.event.ToolListener;
+import org.jhotdraw.draw.figure.Figure;
+import org.jhotdraw.draw.handle.Handle;
+
+import javax.swing.*;
+import javax.swing.event.EventListenerList;
+import javax.swing.event.UndoableEditListener;
+import java.awt.*;
+import java.awt.event.MouseEvent;
+import java.awt.geom.Point2D;
+import java.awt.geom.Rectangle2D;
+
+import static org.jhotdraw.draw.AttributeKeys.CANVAS_HEIGHT;
+import static org.jhotdraw.draw.AttributeKeys.CANVAS_WIDTH;
+
+public class BaseToolImpl extends AbstractBean implements BaseTool {
+ protected DrawingEditor editor;
+ protected EventListenerList listenerList = new EventListenerList();
+ protected DrawingEditorProxy editorProxy;
+ /**
+ * The input map of the tool.
+ */
+ protected InputMap inputMap;
+ /**
+ * The action map of the tool.
+ */
+ protected ActionMap actionMap;
+ /**
+ * This is set to true, if this is the active tool of the editor.
+ */
+ private boolean isActive;
+
+ public BaseToolImpl() {
+ editorProxy = new DrawingEditorProxy();
+ }
+
+ public void addUndoableEditListener(UndoableEditListener l) {
+ listenerList.add(UndoableEditListener.class, l);
+ }
+
+ public void removeUndoableEditListener(UndoableEditListener l) {
+ listenerList.remove(UndoableEditListener.class, l);
+ }
+
+ public void activate(DrawingEditor editor) {
+ this.editor = editor;
+ editorProxy.setTarget(editor);
+ isActive = true;
+ // Repaint all handles
+ for (DrawingView v : editor.getDrawingViews()) {
+ v.repaintHandles();
+ }
+ }
+
+ public void deactivate(DrawingEditor editor) {
+ this.editor = editor;
+ editorProxy.setTarget(null);
+ isActive = false;
+ }
+
+ public boolean isActive() {
+ return isActive;
+ }
+
+ protected DrawingView getView() {
+ return editor.getActiveView();
+ }
+
+ protected DrawingEditor getEditor() {
+ return editor;
+ }
+
+ protected Drawing getDrawing() {
+ return getView().getDrawing();
+ }
+
+ protected Point2D.Double viewToDrawing(Point p) {
+ return constrainPoint(getView().viewToDrawing(p));
+ }
+
+ protected Point2D.Double constrainPoint(Point p, Figure... figure) {
+ return constrainPoint(getView().viewToDrawing(p), figure);
+ }
+
+ protected Point2D.Double constrainPoint(Point2D.Double p, Figure... figure) {
+ if (getView() == null) {
+ return p;
+ }
+ return getView().getConstrainer() == null ? p : getView().getConstrainer().constrainPoint(p, figure);
+ }
+
+ /**
+ * Sets the InputMap for the Tool.
+ *
+ * @see #keyPressed
+ * @see #setActionMap
+ */
+ public void setInputMap(InputMap newValue) {
+ inputMap = newValue;
+ }
+
+ /**
+ * Gets the input map of the Tool
+ */
+ public InputMap getInputMap() {
+ return inputMap;
+ }
+
+ /**
+ * Sets the ActionMap for the Tool.
+ *
+ * @see #keyPressed
+ */
+ public void setActionMap(ActionMap newValue) {
+ actionMap = newValue;
+ }
+
+ /**
+ * Gets the action map of the Tool
+ */
+ public ActionMap getActionMap() {
+ return actionMap;
+ }
+
+ /**
+ * Deletes the selection. Depending on the tool, this could be selected figures, selected points
+ * or selected text.
+ */
+ public void editDelete() {
+ getView().getDrawing().removeAll(getView().getSelectedFigures());
+ }
+
+ /**
+ * Cuts the selection into the clipboard. Depending on the tool, this could be selected figures,
+ * selected points or selected text.
+ */
+ public void editCut() {
+ }
+
+
+ protected DrawingView prepareView(MouseEvent event) {
+ DrawingView view = editor.findView((Container) event.getSource());
+ if (view != null) {
+ view.requestFocus();
+ fireToolStarted(view);
+ }
+ return view;
+ }
+
+ /**
+ * Copies the selection into the clipboard. Depending on the tool, this could be selected
+ * figures, selected points or selected text.
+ */
+ public void editCopy() {
+ }
+
+ /**
+ * Duplicates the selection. Depending on the tool, this could be selected figures, selected
+ * points or selected text.
+ */
+ public void editDuplicate() {
+ }
+
+ /**
+ * Pastes the contents of the clipboard. Depending on the tool, this could be selected figures,
+ * selected points or selected text.
+ */
+ public void editPaste() {
+ }
+
+ /**
+ * Override this method to create a tool-specific input map, which overrides the input map of
+ * the drawing edtior.
+ *
+ * The implementation of this class returns null.
+ */
+ protected InputMap createInputMap() {
+ return null;
+ }
+
+ /**
+ * Override this method to create a tool-specific action map, which overrides the action map of
+ * the drawing edtior.
+ *
+ * The implementation of this class returns null.
+ */
+ protected ActionMap createActionMap() {
+ return null;
+ }
+
+ public void addToolListener(ToolListener l) {
+ listenerList.add(ToolListener.class, l);
+ }
+
+ public void removeToolListener(ToolListener l) {
+ listenerList.remove(ToolListener.class, l);
+ }
+
+ /**
+ * Notify all listenerList that have registered interest for notification on this event type.
+ */
+ protected void fireToolStarted(DrawingView view) {
+ ToolEvent event = null;
+ // Notify all listeners that have registered interest for
+ // Guaranteed to return a non-null array
+ Object[] listeners = listenerList.getListenerList();
+ // Process the listeners last to first, notifying
+ // those that are interested in this event
+ for (int i = listeners.length - 2; i >= 0; i -= 2) {
+ if (listeners[i] == ToolListener.class) {
+ // Lazily create the event:
+ if (event == null) {
+ event = new ToolEvent(this, view, new Rectangle(0, 0, -1, -1));
+ }
+ ((ToolListener) listeners[i + 1]).toolStarted(event);
+ }
+ }
+ }
+
+ /**
+ * Notify all listenerList that have registered interest for notification on this event type.
+ */
+ protected void fireToolDone() {
+ ToolEvent event = null;
+ // Notify all listeners that have registered interest for
+ // Guaranteed to return a non-null array
+ Object[] listeners = listenerList.getListenerList();
+ // Process the listeners last to first, notifying
+ // those that are interested in this event
+ for (int i = listeners.length - 2; i >= 0; i -= 2) {
+ if (listeners[i] == ToolListener.class) {
+ // Lazily create the event:
+ if (event == null) {
+ event = new ToolEvent(this, getView(), new Rectangle(0, 0, -1, -1));
+ }
+ ((ToolListener) listeners[i + 1]).toolDone(event);
+ }
+ }
+ }
+
+ /**
+ * Notify all listenerList that have registered interest for notification on this event type.
+ */
+ protected void fireAreaInvalidated(Rectangle2D.Double r) {
+ Point p1 = getView().drawingToView(new Point2D.Double(r.x, r.y));
+ Point p2 = getView().drawingToView(new Point2D.Double(r.x + r.width, r.y + r.height));
+ fireAreaInvalidated(
+ new Rectangle(p1.x, p1.y, p2.x - p1.x, p2.y - p1.y));
+ }
+
+ /**
+ * Notify all listenerList that have registered interest for notification on this event type.
+ */
+ protected void fireAreaInvalidated(Rectangle invalidatedArea) {
+ ToolEvent event = null;
+ // Notify all listeners that have registered interest for
+ // Guaranteed to return a non-null array
+ Object[] listeners = listenerList.getListenerList();
+ // Process the listeners last to first, notifying
+ // those that are interested in this event
+ for (int i = listeners.length - 2; i >= 0; i -= 2) {
+ if (listeners[i] == ToolListener.class) {
+ // Lazily create the event:
+ if (event == null) {
+ event = new ToolEvent(this, getView(), invalidatedArea);
+ }
+ ((ToolListener) listeners[i + 1]).areaInvalidated(event);
+ }
+ }
+ }
+
+ /**
+ * Notify all listenerList that have registered interest for notification on this event type.
+ *
+ * Note: This method only fires an event, if the invalidated area is outside of the canvas
+ * bounds.
+ */
+ protected void maybeFireBoundsInvalidated(Rectangle invalidatedArea) {
+ Drawing d = getDrawing();
+ Rectangle2D.Double canvasBounds = new Rectangle2D.Double(0, 0, 0, 0);
+ if (d.get(CANVAS_WIDTH) != null) {
+ canvasBounds.width += d.get(CANVAS_WIDTH);
+ }
+ if (d.get(CANVAS_HEIGHT) != null) {
+ canvasBounds.height += d.get(CANVAS_HEIGHT);
+ }
+ if (!canvasBounds.contains(invalidatedArea)) {
+ fireBoundsInvalidated(invalidatedArea);
+ }
+ }
+
+ /**
+ * Notify all listenerList that have registered interest for notification on this event type.
+ */
+ protected void fireBoundsInvalidated(Rectangle invalidatedArea) {
+ ToolEvent event = null;
+ // Notify all listeners that have registered interest for
+ // Guaranteed to return a non-null array
+ Object[] listeners = listenerList.getListenerList();
+ // Process the listeners last to first, notifying
+ // those that are interested in this event
+ for (int i = listeners.length - 2; i >= 0; i -= 2) {
+ if (listeners[i] == ToolListener.class) {
+ // Lazily create the event:
+ if (event == null) {
+ event = new ToolEvent(this, getView(), invalidatedArea);
+ }
+ ((ToolListener) listeners[i + 1]).boundsInvalidated(event);
+ }
+ }
+ }
+
+ public void draw(Graphics2D g) {
+ }
+
+ public void updateCursor(DrawingView view, Point p) {
+ if (view.isEnabled()) {
+ Handle handle = view.findHandle(p);
+ if (handle != null) {
+ view.setCursor(handle.getCursor());
+ } else {
+ Figure figure = view.findFigure(p);
+ Point2D.Double point = view.viewToDrawing(p);
+ Drawing drawing = view.getDrawing();
+ while (figure != null && !figure.isSelectable()) {
+ figure = drawing.findFigureBehind(point, figure);
+ }
+ if (figure != null) {
+ view.setCursor(figure.getCursor(view.viewToDrawing(p)));
+ } else {
+ view.setCursor(Cursor.getDefaultCursor());
+ }
+ }
+ } else {
+ view.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
+ }
+ }
+
+ public String getToolTipText(DrawingView view, MouseEvent evt) {
+ return null;
+ }
+
+ /**
+ * Returns true, if this tool lets the user interact with handles.
+ *
+ * Handles may draw differently, if interaction is not possible.
+ *
+ * @return True, if this tool supports interaction with the handles.
+ */
+ public boolean supportsHandleInteraction() {
+ return false;
+ }
+}
diff --git a/jhotdraw-core/src/main/java/org/jhotdraw/draw/tool/ClickListeningTool.java b/jhotdraw-core/src/main/java/org/jhotdraw/draw/tool/ClickListeningTool.java
new file mode 100644
index 000000000..b617e0354
--- /dev/null
+++ b/jhotdraw-core/src/main/java/org/jhotdraw/draw/tool/ClickListeningTool.java
@@ -0,0 +1,12 @@
+package org.jhotdraw.draw.tool;
+
+import java.awt.event.MouseEvent;
+import java.awt.event.MouseListener;
+
+public interface ClickListeningTool extends MouseListener, BaseTool {
+ @Override default void mousePressed(MouseEvent e) {}
+ @Override default void mouseReleased(MouseEvent e) {}
+ @Override default void mouseClicked(MouseEvent e) {}
+ @Override default void mouseEntered(MouseEvent e) {}
+ @Override default void mouseExited(MouseEvent e) {}
+}
diff --git a/jhotdraw-core/src/main/java/org/jhotdraw/draw/tool/CreationTool.java b/jhotdraw-core/src/main/java/org/jhotdraw/draw/tool/CreationTool.java
index c7e07706f..cde8b5d1f 100644
--- a/jhotdraw-core/src/main/java/org/jhotdraw/draw/tool/CreationTool.java
+++ b/jhotdraw-core/src/main/java/org/jhotdraw/draw/tool/CreationTool.java
@@ -12,12 +12,15 @@
import java.awt.*;
import java.awt.event.*;
import java.awt.geom.*;
+import java.lang.reflect.InvocationTargetException;
import java.util.*;
import javax.swing.undo.*;
import org.jhotdraw.draw.*;
+import org.jhotdraw.draw.figure.ImageHolderFigure;
import org.jhotdraw.util.*;
/**
+ * @deprecated
* A {@link Tool} to create a new figure by drawing its bounds. The figure to be created is
* specified by a prototype.
*
@@ -53,14 +56,11 @@
* @author Werner Randelshofer
* @version $Id$
*/
-public class CreationTool extends AbstractTool {
+
+@Deprecated()
+public class CreationTool extends ExtendedMouseCreationTool implements DragableTool {
private static final long serialVersionUID = 1L;
- /**
- * Attributes to be applied to the created ConnectionFigure. These attributes override the
- * default attributes of the DrawingEditor.
- */
- protected Map, Object> prototypeAttributes;
/**
* A localized name for this tool. The presentationName is displayed by the UndoableEdit.
*/
@@ -73,19 +73,6 @@ public class CreationTool extends AbstractTool {
* We set the figure to this minimal size, if it is smaller than the minimal size treshold.
*/
protected Dimension minimalSize = new Dimension(40, 40);
- /**
- * The prototype for new figures.
- */
- protected Figure prototype;
- /**
- * The created figure.
- */
- protected Figure createdFigure;
- /**
- * If this is set to false, the CreationTool does not fire toolDone after a new Figure has been
- * created. This allows to create multiple figures consecutively.
- */
- private boolean isToolDoneAfterCreation = true;
/**
* Creates a new instance.
@@ -98,20 +85,38 @@ public CreationTool(String prototypeClassName, Map, Object> attr
this(prototypeClassName, attributes, null);
}
+
public CreationTool(String prototypeClassName, Map, Object> attributes, String name) {
+ super(createInstance(prototypeClassName),attributes, name);
+ }
+
+ public CreationTool(Figure prototype, Map, Object> attributes) {
+ super(prototype, attributes);
+ }
+
+ private static Figure createInstance(String className) {
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.getBundle("org.jhotdraw.draw.Labels");
- name = labels.getString("edit.createFigure.text");
+ return (Figure) Class.forName(className).getDeclaredConstructor().newInstance();
+ } catch (ClassNotFoundException e) {
+ throw new IllegalArgumentException("Class " + className + " not found");
+ } catch (InstantiationException | IllegalAccessException e) {
+ throw new IllegalStateException("Failed to instantiate figure: " + className, e);
+ } catch (ClassCastException e) {
+ throw new IllegalArgumentException("Class " + className + " is not a figure");
+ } catch (NoSuchMethodException e) {
+ throw new IllegalArgumentException("No such constructor: " + className, e);
+ } catch (InvocationTargetException e) {
+
+ Throwable cause = e.getCause();
+
+ if (cause instanceof RuntimeException)
+ throw (RuntimeException) cause;
+ if (cause instanceof Error)
+ throw (Error) cause;
+
+ // TODO: Make Tool Exception class
+ throw new RuntimeException("Failed to instantiate figure: " + className, e);
}
- this.presentationName = name;
}
/**
@@ -123,7 +128,7 @@ public CreationTool(String prototypeClassName, Map, Object> attr
* @param prototype The prototype used to create a new Figure.
*/
public CreationTool(Figure prototype) {
- this(prototype, null, null);
+ super(prototype, null, null);
}
/**
@@ -136,70 +141,9 @@ public CreationTool(Figure prototype) {
* @param attributes The CreationTool applies these attributes to the prototype after having
* applied the default attributes from the DrawingEditor.
*/
- public CreationTool(Figure prototype, Map, 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 name parameter is currently not used.
- * @deprecated This constructor might go away, because the name parameter is not used.
- */
- @Deprecated
- public CreationTool(Figure prototype, Map, Object> attributes, String name) {
- this.prototype = prototype;
- this.prototypeAttributes = attributes;
- if (name == null) {
- ResourceBundleUtil labels = ResourceBundleUtil.getBundle("org.jhotdraw.draw.Labels");
- name = labels.getString("edit.createFigure.text");
- }
- this.presentationName = name;
- }
- public Figure getPrototype() {
- return prototype;
- }
-
- @Override
- public void activate(DrawingEditor editor) {
- super.activate(editor);
- if (getView() != null) {
- getView().setCursor(Cursor.getPredefinedCursor(Cursor.CROSSHAIR_CURSOR));
- }
- }
-
- @Override
- 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;
- }
- }
- @Override
- public void mousePressed(MouseEvent evt) {
- super.mousePressed(evt);
- if (getView() == null) {
- return;
- }
- getView().clearSelection();
- createdFigure = createFigure();
- Point2D.Double p = constrainPoint(viewToDrawing(anchor), createdFigure);
- anchor.x = evt.getX();
- anchor.y = evt.getY();
- createdFigure.setBounds(p, p);
- getDrawing().add(createdFigure);
- }
@Override
public void mouseDragged(MouseEvent evt) {
@@ -213,6 +157,11 @@ public void mouseDragged(MouseEvent evt) {
}
}
+ @Override
+ public void mouseMoved(MouseEvent e) {
+ // Intentional No-Op: Legacy Code. Legacy parent implemented this, new parent does not.
+ }
+
@Override
public void mouseReleased(MouseEvent evt) {
if (createdFigure != null) {
@@ -272,61 +221,4 @@ public void redo() throws CannotRedoException {
}
}
- @SuppressWarnings("unchecked")
- protected Figure createFigure() {
- Figure f = prototype.clone();
- getEditor().applyDefaultAttributesTo(f);
- if (prototypeAttributes != null) {
- for (Map.Entry, Object> entry : prototypeAttributes.entrySet()) {
- f.set((AttributeKey) entry.getKey(), entry.getValue());
- }
- }
- return f;
- }
-
- protected Figure getCreatedFigure() {
- return createdFigure;
- }
-
- protected Figure getAddedFigure() {
- return createdFigure;
- }
-
- /**
- * This method allows subclasses to do perform additonal user interactions after the new figure
- * has been created. The implementation of this class just invokes fireToolDone.
- */
- protected void creationFinished(Figure createdFigure) {
- if (createdFigure.isSelectable()) {
- getView().addToSelection(createdFigure);
- }
- if (isToolDoneAfterCreation()) {
- fireToolDone();
- }
- }
-
- /**
- * If this is set to false, the CreationTool does not fire toolDone after a new Figure has been
- * created. This allows to create multiple figures consecutively.
- */
- public void setToolDoneAfterCreation(boolean newValue) {
- boolean oldValue = isToolDoneAfterCreation;
- isToolDoneAfterCreation = newValue;
- }
-
- /**
- * Returns true, if this tool fires toolDone immediately after a new figure has been created.
- */
- public boolean isToolDoneAfterCreation() {
- return isToolDoneAfterCreation;
- }
-
- @Override
- public void updateCursor(DrawingView view, Point p) {
- if (view.isEnabled()) {
- view.setCursor(Cursor.getPredefinedCursor(Cursor.CROSSHAIR_CURSOR));
- } else {
- view.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
- }
- }
}
diff --git a/jhotdraw-core/src/main/java/org/jhotdraw/draw/tool/DelegationSelectionTool.java b/jhotdraw-core/src/main/java/org/jhotdraw/draw/tool/DelegationSelectionTool.java
index 9490be884..32aee7808 100644
--- a/jhotdraw-core/src/main/java/org/jhotdraw/draw/tool/DelegationSelectionTool.java
+++ b/jhotdraw-core/src/main/java/org/jhotdraw/draw/tool/DelegationSelectionTool.java
@@ -298,7 +298,7 @@ protected void handleDoubleClick(MouseEvent evt) {
if (DEBUG) {
System.out.println("DelegationSelectionTool.handleDoubleClick by figure");
}
- Tool figureTool = figure.getTool(p);
+ BaseTool figureTool = figure.getTool(p);
if (figureTool == null) {
figure = getDrawing().findFigureInside(p);
if (figure != null) {
@@ -307,7 +307,8 @@ protected void handleDoubleClick(MouseEvent evt) {
}
if (figureTool != null) {
setTracker(figureTool);
- figureTool.mousePressed(evt);
+ if (figureTool instanceof ClickListeningTool)
+ ((ClickListeningTool) figureTool).mousePressed(evt);
} else {
if (outerFigure.handleMouseClick(p, evt, getView())) {
v.clearSelection();
diff --git a/jhotdraw-core/src/main/java/org/jhotdraw/draw/tool/DragableTool.java b/jhotdraw-core/src/main/java/org/jhotdraw/draw/tool/DragableTool.java
new file mode 100644
index 000000000..f9a34e3bd
--- /dev/null
+++ b/jhotdraw-core/src/main/java/org/jhotdraw/draw/tool/DragableTool.java
@@ -0,0 +1,6 @@
+package org.jhotdraw.draw.tool;
+
+import java.awt.event.MouseMotionListener;
+
+public interface DragableTool extends MouseMotionListener, BaseTool {
+}
diff --git a/jhotdraw-core/src/main/java/org/jhotdraw/draw/tool/ExtendedMouseCreationTool.java b/jhotdraw-core/src/main/java/org/jhotdraw/draw/tool/ExtendedMouseCreationTool.java
new file mode 100644
index 000000000..aed57816b
--- /dev/null
+++ b/jhotdraw-core/src/main/java/org/jhotdraw/draw/tool/ExtendedMouseCreationTool.java
@@ -0,0 +1,41 @@
+package org.jhotdraw.draw.tool;
+
+import org.jhotdraw.draw.AttributeKey;
+import org.jhotdraw.draw.DrawingView;
+import org.jhotdraw.draw.figure.Figure;
+
+import java.awt.*;
+import java.awt.event.MouseEvent;
+import java.awt.geom.Point2D;
+import java.util.Map;
+
+public abstract class ExtendedMouseCreationTool extends AbstractCreationTool {
+
+ @Override
+ public void mousePressed(MouseEvent evt) {
+ DrawingView view = prepareView(evt);
+ if (view == null) return;
+ if (getView() == null) {
+ return;
+ }
+
+ anchor = new Point(evt.getX(), evt.getY());
+ isWorking = true;
+
+ getView().clearSelection();
+ createdFigure = createFigure();
+ Point2D.Double p = constrainPoint(viewToDrawing(anchor), createdFigure);
+ anchor.x = evt.getX();
+ anchor.y = evt.getY();
+ createdFigure.setBounds(p, p);
+ getDrawing().add(createdFigure);
+ }
+
+ public ExtendedMouseCreationTool(Figure prototype, Map, Object> prototypeAttributes, String name) {
+ super(prototype, prototypeAttributes, name);
+ }
+
+ public ExtendedMouseCreationTool(Figure prototype, Map, Object> attributes) {
+ super(prototype, attributes);
+ }
+}
diff --git a/jhotdraw-core/src/main/java/org/jhotdraw/draw/tool/KeyListeningTool.java b/jhotdraw-core/src/main/java/org/jhotdraw/draw/tool/KeyListeningTool.java
new file mode 100644
index 000000000..5167251f2
--- /dev/null
+++ b/jhotdraw-core/src/main/java/org/jhotdraw/draw/tool/KeyListeningTool.java
@@ -0,0 +1,20 @@
+package org.jhotdraw.draw.tool;
+
+import java.awt.event.KeyEvent;
+import java.awt.event.KeyListener;
+import java.awt.event.MouseEvent;
+
+public interface KeyListeningTool extends KeyListener, BaseTool {
+ @Override
+ default void keyTyped(KeyEvent e) {
+ }
+
+ @Override
+ default void keyPressed(KeyEvent e) {
+ }
+
+ @Override
+ default void keyReleased(KeyEvent e) {
+ }
+
+}
\ No newline at end of file
diff --git a/jhotdraw-core/src/main/java/org/jhotdraw/draw/tool/SelectionTool.java b/jhotdraw-core/src/main/java/org/jhotdraw/draw/tool/SelectionTool.java
index 50f6c47e0..cbdfce4b7 100644
--- a/jhotdraw-core/src/main/java/org/jhotdraw/draw/tool/SelectionTool.java
+++ b/jhotdraw-core/src/main/java/org/jhotdraw/draw/tool/SelectionTool.java
@@ -56,7 +56,7 @@ public class SelectionTool extends AbstractTool {
/**
* The tracker encapsulates the current state of the SelectionTool.
*/
- private Tool tracker;
+ private BaseTool tracker;
/**
* The tracker encapsulates the current state of the SelectionTool.
*/
@@ -161,59 +161,68 @@ public void deactivate(DrawingEditor editor) {
@Override
public void keyPressed(KeyEvent e) {
if (getView() != null && getView().isEnabled()) {
- tracker.keyPressed(e);
+ if (tracker instanceof KeyListeningTool)
+ ((KeyListeningTool) tracker).keyPressed(e);
}
}
@Override
public void keyReleased(KeyEvent evt) {
if (getView() != null && getView().isEnabled()) {
- tracker.keyReleased(evt);
+ if (tracker instanceof KeyListeningTool)
+ ((KeyListeningTool) tracker).keyReleased(evt);
}
}
@Override
public void keyTyped(KeyEvent evt) {
if (getView() != null && getView().isEnabled()) {
- tracker.keyTyped(evt);
+ if (tracker instanceof KeyListeningTool)
+ ((KeyListeningTool) tracker).keyTyped(evt);
}
}
@Override
public void mouseClicked(MouseEvent evt) {
if (getView() != null && getView().isEnabled()) {
- tracker.mouseClicked(evt);
+ if (tracker instanceof ClickListeningTool)
+ ((ClickListeningTool) tracker).mouseClicked(evt);
}
}
@Override
public void mouseDragged(MouseEvent evt) {
if (getView() != null && getView().isEnabled()) {
- tracker.mouseDragged(evt);
+ if (tracker instanceof DragableTool)
+ ((DragableTool) tracker).mouseDragged(evt);
}
}
@Override
public void mouseEntered(MouseEvent evt) {
super.mouseEntered(evt);
- tracker.mouseEntered(evt);
+ if (tracker instanceof ClickListeningTool)
+ ((ClickListeningTool) tracker).mouseEntered(evt);
}
@Override
public void mouseExited(MouseEvent evt) {
super.mouseExited(evt);
- tracker.mouseExited(evt);
+ if (tracker instanceof ClickListeningTool)
+ ((ClickListeningTool) tracker).mouseExited(evt);
}
@Override
public void mouseMoved(MouseEvent evt) {
- tracker.mouseMoved(evt);
+ if (tracker instanceof DragableTool)
+ ((DragableTool) tracker).mouseMoved(evt);
}
@Override
public void mouseReleased(MouseEvent evt) {
if (getView() != null && getView().isEnabled()) {
- tracker.mouseReleased(evt);
+ if (tracker instanceof ClickListeningTool)
+ ((ClickListeningTool) tracker).mouseReleased(evt);
}
}
@@ -286,11 +295,12 @@ public void mousePressed(MouseEvent evt) {
if (newTracker != null) {
setTracker(newTracker);
}
- tracker.mousePressed(evt);
+ if (tracker instanceof ClickListeningTool)
+ ((ClickListeningTool) tracker).mousePressed(evt);
}
}
- protected void setTracker(Tool newTracker) {
+ protected void setTracker(BaseTool newTracker) {
if (tracker != null) {
tracker.deactivate(getEditor());
tracker.removeToolListener(trackerHandler);
diff --git a/jhotdraw-core/src/main/java/org/jhotdraw/draw/tool/SimpleCreationTool.java b/jhotdraw-core/src/main/java/org/jhotdraw/draw/tool/SimpleCreationTool.java
new file mode 100644
index 000000000..5c8175082
--- /dev/null
+++ b/jhotdraw-core/src/main/java/org/jhotdraw/draw/tool/SimpleCreationTool.java
@@ -0,0 +1,47 @@
+package org.jhotdraw.draw.tool;
+
+import org.jhotdraw.draw.AttributeKey;
+import org.jhotdraw.draw.DrawingView;
+import org.jhotdraw.draw.figure.Figure;
+
+import java.awt.*;
+import java.awt.event.MouseEvent;
+import java.awt.geom.Point2D;
+import java.util.Map;
+
+public class SimpleCreationTool extends AbstractCreationTool {
+
+ public SimpleCreationTool(Figure prototype) {
+ super(prototype);
+ }
+
+ public SimpleCreationTool(Figure prototype, Map, Object> attributes, String name) {
+ super(prototype, attributes, name);
+ }
+
+ public SimpleCreationTool(Figure prototype, Map, Object> attributes) {
+ super(prototype, attributes);
+ }
+
+ @Override
+ public void mouseClicked(MouseEvent event) {
+ DrawingView view = (getView() == null) ? null : prepareView(event);
+ if (view == null) return;
+
+ Point anchor = new Point(event.getX(), event.getY());
+ createdFigure = createFigure();
+
+ Point2D.Double p = constrainPoint(viewToDrawing(anchor), createdFigure);
+ createdFigure.setBounds(p,p);
+
+ getDrawing().add(createdFigure);
+ view.clearSelection();
+ view.addToSelection(createdFigure);
+ }
+
+
+ @Override
+ public void mouseReleased(MouseEvent event) {
+ super.mouseReleased(event);
+ }
+}
diff --git a/jhotdraw-core/src/main/java/org/jhotdraw/draw/tool/TextCreationTool.java b/jhotdraw-core/src/main/java/org/jhotdraw/draw/tool/TextCreationTool.java
index d6477493c..a4cb8b52d 100644
--- a/jhotdraw-core/src/main/java/org/jhotdraw/draw/tool/TextCreationTool.java
+++ b/jhotdraw-core/src/main/java/org/jhotdraw/draw/tool/TextCreationTool.java
@@ -12,11 +12,9 @@
import java.awt.*;
import java.awt.event.*;
import java.util.*;
-import javax.swing.undo.AbstractUndoableEdit;
-import javax.swing.undo.UndoableEdit;
import org.jhotdraw.draw.*;
import org.jhotdraw.draw.text.*;
-import org.jhotdraw.util.ResourceBundleUtil;
+import org.jhotdraw.draw.undo.TextEdit;
/**
* A tool to create figures which implement the {@code TextHolderFigure}
@@ -56,12 +54,14 @@
* @author Werner Randelshofer
* @version $Id$
*/
-public class TextCreationTool extends CreationTool implements ActionListener {
+public class TextCreationTool extends SimpleCreationTool implements ActionListener, ClickListeningTool, KeyListeningTool {
private static final long serialVersionUID = 1L;
- private FloatingTextField textField;
+ private transient FloatingTextField textField;
private TextHolderFigure typingTarget;
+
+
/**
* Creates a new instance.
*/
@@ -78,39 +78,39 @@ public TextCreationTool(TextHolderFigure prototype, Map, Object>
@Override
public void deactivate(DrawingEditor editor) {
- endEdit();
+ if (typingTarget != null) {
+ endEdit();
+ }
super.deactivate(editor);
}
/**
- * Creates a new figure at the location where the mouse was pressed.
+ * If the created figure is a TextHolderFigure it can be edited.
*/
+
@Override
- public void mousePressed(MouseEvent e) {
- // Note: The search sequence used here, must be
- // consistent with the search sequence used by the
- // HandleTracker, SelectAreaTracker, DelegationSelectionTool, SelectionTool.
+ public void mouseClicked(MouseEvent event) {
+
if (typingTarget != null) {
endEdit();
- if (isToolDoneAfterCreation()) {
- fireToolDone();
- }
- } else {
- super.mousePressed(e);
- // update view so the created figure is drawn before the floating text
- // figure is overlaid.
- TextHolderFigure textHolder = (TextHolderFigure) getCreatedFigure();
- getView().clearSelection();
- getView().addToSelection(textHolder);
- beginEdit(textHolder);
- updateCursor(getView(), e.getPoint());
+ fireToolDone();
+ return;
+ }
+
+ super.mouseClicked(event);
+
+ if (createdFigure instanceof TextHolderFigure) {
+ beginEdit((TextHolderFigure) createdFigure);
}
}
+
@Override
- public void mouseDragged(java.awt.event.MouseEvent e) {
+ protected void fireToolDone() {
+ super.fireToolDone();
}
+ @SuppressWarnings("Duplicates")
protected void beginEdit(TextHolderFigure textHolder) {
if (textField == null) {
textField = new FloatingTextField();
@@ -121,12 +121,10 @@ protected void beginEdit(TextHolderFigure textHolder) {
}
textField.createOverlay(getView(), textHolder);
textField.requestFocus();
+ textField.getEditorComponent().addKeyListener(this);
typingTarget = textHolder;
}
- @Override
- public void mouseReleased(MouseEvent evt) {
- }
protected void endEdit() {
if (typingTarget != null) {
@@ -134,59 +132,34 @@ protected void endEdit() {
final TextHolderFigure editedFigure = typingTarget;
final String oldText = typingTarget.getText();
final String newText = textField.getText();
- if (newText.length() > 0) {
+ if (!newText.isEmpty()) {
typingTarget.setText(newText);
} else {
- if (createdFigure != null) {
getDrawing().remove(getAddedFigure());
// XXX - Fire undoable edit here!!
- } else {
+ typingTarget.willChange();
typingTarget.setText("");
typingTarget.changed();
- }
}
- UndoableEdit edit = new AbstractUndoableEdit() {
- private static final long serialVersionUID = 1L;
-
- @Override
- public String getPresentationName() {
- ResourceBundleUtil labels = ResourceBundleUtil.getBundle("org.jhotdraw.draw.Labels");
- return labels.getString("attribute.text.text");
- }
-
- @Override
- public void undo() {
- super.undo();
- editedFigure.willChange();
- editedFigure.setText(oldText);
- editedFigure.changed();
- }
-
- @Override
- public void redo() {
- super.redo();
- editedFigure.willChange();
- editedFigure.setText(newText);
- editedFigure.changed();
- }
- };
- getDrawing().fireUndoableEditHappened(edit);
+
+ TextEdit.createAndFireEditHappened(getDrawing(), editedFigure, oldText, newText);
typingTarget.changed();
typingTarget = null;
textField.endOverlay();
}
- // view().checkDamage();
}
+
+
@Override
- public void keyReleased(KeyEvent evt) {
- if (evt.getKeyCode() == KeyEvent.VK_ESCAPE || isToolDoneAfterCreation()) {
+ public void keyReleased(KeyEvent keyEvent) {
+ if (keyEvent.getKeyCode() == KeyEvent.VK_ESCAPE) {
fireToolDone();
}
}
@Override
- public void actionPerformed(ActionEvent event) {
+ public void actionPerformed(ActionEvent actionEvent) {
endEdit();
if (isToolDoneAfterCreation()) {
fireToolDone();
@@ -204,11 +177,11 @@ public boolean isEditing() {
}
@Override
- public void updateCursor(DrawingView view, Point p) {
- if (view.isEnabled()) {
- view.setCursor(Cursor.getPredefinedCursor(isEditing() ? Cursor.DEFAULT_CURSOR : Cursor.CROSSHAIR_CURSOR));
+ public void updateCursor(DrawingView drawingView, Point point) {
+ if (drawingView.isEnabled()) {
+ drawingView.setCursor(Cursor.getPredefinedCursor(isEditing() ? Cursor.DEFAULT_CURSOR : Cursor.CROSSHAIR_CURSOR));
} else {
- view.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
+ drawingView.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
}
}
}
diff --git a/jhotdraw-core/src/main/java/org/jhotdraw/draw/tool/TextEditingTool.java b/jhotdraw-core/src/main/java/org/jhotdraw/draw/tool/TextEditingTool.java
index b9455715c..7976752ae 100644
--- a/jhotdraw-core/src/main/java/org/jhotdraw/draw/tool/TextEditingTool.java
+++ b/jhotdraw-core/src/main/java/org/jhotdraw/draw/tool/TextEditingTool.java
@@ -10,11 +10,9 @@
import org.jhotdraw.draw.figure.TextHolderFigure;
import java.awt.*;
import java.awt.event.*;
-import javax.swing.undo.AbstractUndoableEdit;
-import javax.swing.undo.UndoableEdit;
import org.jhotdraw.draw.*;
import org.jhotdraw.draw.text.*;
-import org.jhotdraw.util.ResourceBundleUtil;
+import org.jhotdraw.draw.undo.TextEdit;
/**
* A tool to edit figures which implement the {@code TextHolderFigure} interface,
@@ -44,10 +42,10 @@
* @author Werner Randelshofer
* @version $Id$
*/
-public class TextEditingTool extends AbstractTool implements ActionListener {
+public class TextEditingTool extends BaseToolImpl implements ActionListener, ClickListeningTool, KeyListeningTool {
private static final long serialVersionUID = 1L;
- private FloatingTextField textField;
+ transient FloatingTextField textField; // Visibility slightly relaxed for integration tests.
private TextHolderFigure typingTarget;
/**
@@ -74,6 +72,9 @@ public void mousePressed(MouseEvent e) {
}
}
+ @SuppressWarnings("Duplicates")
+ // "Duplication is far cheaper than the wrong abstraction." - Sandi Metz
+ // Both have different reasons to change, so we keep both.
protected void beginEdit(TextHolderFigure textHolder) {
if (textField == null) {
textField = new FloatingTextField();
@@ -84,12 +85,10 @@ protected void beginEdit(TextHolderFigure textHolder) {
}
textField.createOverlay(getView(), textHolder);
textField.requestFocus();
+ textField.getEditorComponent().addKeyListener(this);
typingTarget = textHolder;
}
- @Override
- public void mouseReleased(MouseEvent evt) {
- }
protected void endEdit() {
if (typingTarget != null) {
@@ -97,42 +96,16 @@ protected void endEdit() {
final TextHolderFigure editedFigure = typingTarget;
final String oldText = typingTarget.getText();
final String newText = textField.getText();
- if (newText.length() > 0) {
+ if (!newText.isEmpty()) {
typingTarget.willChange();
typingTarget.setText(newText);
typingTarget.changed();
}
- UndoableEdit edit = new AbstractUndoableEdit() {
- private static final long serialVersionUID = 1L;
-
- @Override
- public String getPresentationName() {
- ResourceBundleUtil labels = ResourceBundleUtil.getBundle("org.jhotdraw.draw.Labels");
- return labels.getString("attribute.text.text");
- }
-
- @Override
- public void undo() {
- super.undo();
- editedFigure.willChange();
- editedFigure.setText(oldText);
- editedFigure.changed();
- }
-
- @Override
- public void redo() {
- super.redo();
- editedFigure.willChange();
- editedFigure.setText(newText);
- editedFigure.changed();
- }
- };
- getDrawing().fireUndoableEditHappened(edit);
+ TextEdit.createAndFireEditHappened(getDrawing(), editedFigure, oldText, newText);
typingTarget.changed();
typingTarget = null;
textField.endOverlay();
}
- // view().checkDamage();
}
@Override
@@ -161,8 +134,5 @@ public void updateCursor(DrawingView view, Point p) {
}
}
- @Override
- public void mouseDragged(MouseEvent e) {
- throw new UnsupportedOperationException("Not supported yet.");
- }
+
}
diff --git a/jhotdraw-core/src/main/java/org/jhotdraw/draw/tool/Tool.java b/jhotdraw-core/src/main/java/org/jhotdraw/draw/tool/Tool.java
index 2fed1c394..a130f84b1 100644
--- a/jhotdraw-core/src/main/java/org/jhotdraw/draw/tool/Tool.java
+++ b/jhotdraw-core/src/main/java/org/jhotdraw/draw/tool/Tool.java
@@ -7,12 +7,11 @@
*/
package org.jhotdraw.draw.tool;
-import java.awt.*;
-import java.awt.event.*;
import org.jhotdraw.draw.*;
import org.jhotdraw.draw.event.ToolListener;
/**
+ * @deprecated
* A tool defines an editing mode of a {@link DrawingEditor}.
*
* Tools are used for user interaction. Unlike figures, a tool works with
@@ -73,85 +72,7 @@
* @author Werner Randelshofer
* @version $Id$
*/
-public interface Tool extends MouseListener, MouseMotionListener, KeyListener {
-
- /**
- * Activates the tool for the given editor. This method is called
- * whenever the user switches to this tool.
- */
- public void activate(DrawingEditor editor);
-
- /**
- * Deactivates the tool. This method is called whenever the user
- * switches to another tool.
- */
- public void deactivate(DrawingEditor editor);
-
- /**
- * Adds a listener for this tool.
- */
- void addToolListener(ToolListener l);
-
- /**
- * Removes a listener for this tool.
- */
- void removeToolListener(ToolListener l);
-
- /**
- * Draws the tool.
- */
- void draw(Graphics2D g);
-
- /**
- * Deletes the selection.
- * Depending on the tool, this could be selected figures, selected points
- * or selected text.
- */
- public void editDelete();
-
- /**
- * Cuts the selection into the clipboard.
- * Depending on the tool, this could be selected figures, selected points
- * or selected text.
- */
- public void editCut();
-
- /**
- * Copies the selection into the clipboard.
- * Depending on the tool, this could be selected figures, selected points
- * or selected text.
- */
- public void editCopy();
-
- /**
- * Duplicates the selection.
- * Depending on the tool, this could be selected figures, selected points
- * or selected text.
- */
- public void editDuplicate();
-
- /**
- * Pastes the contents of the clipboard.
- * Depending on the tool, this could be selected figures, selected points
- * or selected text.
- */
- public void editPaste();
-
- /**
- * Returns the tooltip text for a mouse event on a drawing view.
- *
- * @param view A drawing view.
- * @param evt A mouse event.
- * @return A tooltip text or null.
- */
- public String getToolTipText(DrawingView view, MouseEvent evt);
-
- /**
- * Returns true, if this tool lets the user interact with handles.
- *
- * Handles may draw differently, if interaction is not possible.
- *
- * @return True, if this tool supports interaction with the handles.
- */
- public boolean supportsHandleInteraction();
+@Deprecated
+public interface Tool extends BaseTool, ClickListeningTool, DragableTool, KeyListeningTool {
+ // Legacy God Tool to maintain compatibility
}
diff --git a/jhotdraw-core/src/main/java/org/jhotdraw/draw/undo/TextEdit.java b/jhotdraw-core/src/main/java/org/jhotdraw/draw/undo/TextEdit.java
new file mode 100644
index 000000000..2a5c8929f
--- /dev/null
+++ b/jhotdraw-core/src/main/java/org/jhotdraw/draw/undo/TextEdit.java
@@ -0,0 +1,49 @@
+package org.jhotdraw.draw.undo;
+
+import org.jhotdraw.draw.Drawing;
+import org.jhotdraw.draw.figure.TextHolderFigure;
+import org.jhotdraw.util.ResourceBundleUtil;
+
+import javax.swing.undo.AbstractUndoableEdit;
+
+public class TextEdit extends AbstractUndoableEdit {
+
+ private TextHolderFigure editedFigure;
+ private String oldText;
+ private String newText;
+
+ public TextEdit(TextHolderFigure figure, String oldText, String newText) {
+ this.editedFigure = figure;
+ this.oldText = oldText;
+ this.newText = newText;
+ }
+
+ private static final long serialVersionUID = 1L;
+
+ @Override
+ public String getPresentationName() {
+ ResourceBundleUtil labels = ResourceBundleUtil.getBundle("org.jhotdraw.draw.Labels");
+ return labels.getString("attribute.text.text");
+ }
+
+ public static void createAndFireEditHappened(Drawing drawing, TextHolderFigure figure, String oldText, String newText) {
+ TextEdit edit = new TextEdit(figure, oldText, newText);
+ drawing.fireUndoableEditHappened(edit);
+ }
+
+ @Override
+ public void undo() {
+ super.undo();
+ editedFigure.willChange();
+ editedFigure.setText(oldText);
+ editedFigure.changed();
+ }
+
+ @Override
+ public void redo() {
+ super.redo();
+ editedFigure.willChange();
+ editedFigure.setText(newText);
+ editedFigure.changed();
+ }
+}
diff --git a/jhotdraw-core/src/test/java/org/jhotdraw/draw/DefaultDrawingEditorTest.java b/jhotdraw-core/src/test/java/org/jhotdraw/draw/DefaultDrawingEditorTest.java
new file mode 100644
index 000000000..538f416ee
--- /dev/null
+++ b/jhotdraw-core/src/test/java/org/jhotdraw/draw/DefaultDrawingEditorTest.java
@@ -0,0 +1,30 @@
+package org.jhotdraw.draw;
+
+import org.junit.After;
+import org.junit.Before;
+
+import java.awt.event.KeyListener;
+import java.awt.event.MouseAdapter;
+import java.awt.event.MouseListener;
+import static org.junit.Assert.*;
+import static org.mockito.Mockito.*;
+
+public class DefaultDrawingEditorTest {
+ private MouseListener mouseListener;
+ private KeyListener keyListener;
+ private MouseListener combinedInterface;
+
+
+
+ @Before
+ public void setUp() throws Exception {
+ mouseListener = mock(MouseListener.class);
+
+ }
+
+
+
+ @After
+ public void tearDown() throws Exception {
+ }
+}
\ No newline at end of file
diff --git a/jhotdraw-core/src/test/java/org/jhotdraw/draw/figure/TextFigureTest.java b/jhotdraw-core/src/test/java/org/jhotdraw/draw/figure/TextFigureTest.java
new file mode 100644
index 000000000..2da085fac
--- /dev/null
+++ b/jhotdraw-core/src/test/java/org/jhotdraw/draw/figure/TextFigureTest.java
@@ -0,0 +1,54 @@
+package org.jhotdraw.draw.figure;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+import java.awt.font.TextLayout;
+import java.awt.geom.Point2D;
+
+import static org.junit.Assert.*;
+
+public class TextFigureTest {
+ private TextFigure textFigure;
+
+ @Before
+ public void setUp() throws Exception {
+ textFigure = new TextFigure();
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ }
+
+
+ @Test
+ public void testDuplicationFactory() {
+ TextFigure original = new TextFigure();
+ original.setText("Tell me. For whom do you fight?");
+
+ TextLayout layout = original.getTextLayout();
+
+ TextFigure duplicate = TextFigure.createFrom(original);
+
+ assertEquals("Text should be the same","Tell me. For whom do you fight?", duplicate.getText());
+ assertSame("Layout should be the same", duplicate.getTextLayout(), layout);
+ }
+
+
+ @Test
+ public void testTypesafeRestoreTransformTo() {
+
+ Point2D.Double point = new Point2D.Double(3760, 3760);
+
+ textFigure.restoreTransformTo(point);
+
+ assertEquals(3760, textFigure.origin.x, 0.00001);
+ assertEquals(3760, textFigure.origin.y, 0.00001);
+
+ }
+
+
+
+
+}
\ No newline at end of file
diff --git a/jhotdraw-core/src/test/java/org/jhotdraw/draw/stages/GivenDrawingCanvas.java b/jhotdraw-core/src/test/java/org/jhotdraw/draw/stages/GivenDrawingCanvas.java
new file mode 100644
index 000000000..e2612fcfc
--- /dev/null
+++ b/jhotdraw-core/src/test/java/org/jhotdraw/draw/stages/GivenDrawingCanvas.java
@@ -0,0 +1,43 @@
+package org.jhotdraw.draw.stages;
+
+import org.assertj.swing.core.GenericTypeMatcher;
+import org.assertj.swing.edt.GuiActionRunner;
+import org.jhotdraw.draw.figure.TextFigure;
+
+import javax.swing.*;
+import java.awt.geom.Point2D;
+
+public class GivenDrawingCanvas extends JHotDrawStage {
+
+ public GivenDrawingCanvas the_text_tool_is_selected() {
+
+ AbstractButton textButton = (AbstractButton) window.robot().finder().findByName("textToolButton",true);
+
+ window.robot().click(textButton);
+
+ return self();
+
+ }
+
+ public GivenDrawingCanvas the_selection_tool_is_selected() {
+
+ AbstractButton textButton = (AbstractButton) window.robot().finder().findByName("selectionToolButton",true);
+
+ window.robot().click(textButton);
+
+ return self();
+
+ }
+
+ public GivenDrawingCanvas a_text_figure_exists_on_the_canvas() {
+ TextFigure figure = new TextFigure("Text");
+
+ figure.setBounds(new Point2D.Double(100,100), new Point2D.Double(100,100));
+
+ GuiActionRunner.execute(() -> {
+ drawingView.getDrawing().add(figure);
+ });
+ return self();
+ }
+
+}
diff --git a/jhotdraw-core/src/test/java/org/jhotdraw/draw/stages/JHotDrawStage.java b/jhotdraw-core/src/test/java/org/jhotdraw/draw/stages/JHotDrawStage.java
new file mode 100644
index 000000000..32480c921
--- /dev/null
+++ b/jhotdraw-core/src/test/java/org/jhotdraw/draw/stages/JHotDrawStage.java
@@ -0,0 +1,23 @@
+package org.jhotdraw.draw.stages;
+
+import com.tngtech.jgiven.Stage;
+import org.assertj.swing.core.Robot;
+import org.assertj.swing.fixture.FrameFixture;
+import org.jhotdraw.draw.DrawingEditor;
+import org.jhotdraw.draw.DrawingView;
+
+public class JHotDrawStage> extends Stage {
+
+ protected static FrameFixture window;
+ protected static Robot robot;
+ protected static DrawingEditor drawingEditor;
+ protected static DrawingView drawingView;
+
+ public void setFixtures(FrameFixture fixture, Robot robotInstance, DrawingEditor drawingEditor, DrawingView drawingView) {
+ window = fixture;
+ robot = robotInstance;
+ drawingEditor = drawingEditor;
+ drawingView = drawingView;
+ }
+
+}
diff --git a/jhotdraw-core/src/test/java/org/jhotdraw/draw/stages/ThenDrawingState.java b/jhotdraw-core/src/test/java/org/jhotdraw/draw/stages/ThenDrawingState.java
new file mode 100644
index 000000000..811ceb238
--- /dev/null
+++ b/jhotdraw-core/src/test/java/org/jhotdraw/draw/stages/ThenDrawingState.java
@@ -0,0 +1,130 @@
+package org.jhotdraw.draw.stages;
+
+
+import com.tngtech.jgiven.annotation.ExpectedScenarioState;
+import com.tngtech.jgiven.annotation.ScenarioState;
+import org.assertj.swing.exception.ComponentLookupException;
+import org.jhotdraw.draw.Drawing;
+import org.jhotdraw.draw.DrawingView;
+import org.jhotdraw.draw.figure.Figure;
+import org.jhotdraw.draw.figure.TextFigure;
+import org.jhotdraw.draw.figure.TextHolderFigure;
+
+import javax.swing.text.JTextComponent;
+import java.awt.*;
+import java.awt.geom.Point2D;
+import java.awt.geom.Rectangle2D;
+import java.util.ArrayList;
+import java.util.List;
+
+import static org.assertj.core.api.Assertions.*;
+
+public class ThenDrawingState extends JHotDrawStage {
+
+ private DrawingView drawingView;
+
+ public ThenDrawingState setView(DrawingView view) {
+ this.drawingView = view;
+ return self();
+ }
+
+ public ThenDrawingState a_new_text_figure_should_exist() {
+ Drawing drawing = drawingView.getDrawing();
+ assertThat(drawing.getChildCount())
+ .as("Check that at least one figure exists on the canvas")
+ .isGreaterThan(0);
+ return self();
+ }
+
+ public ThenDrawingState the_figure_text_should_be(String expectedText) {
+ Figure f = drawingView.getSelectedFigures().iterator().next();
+ if (f instanceof TextHolderFigure)
+ assertThat(((TextHolderFigure) f).getText()).isEqualTo(expectedText);
+ else
+ fail("Selected figure does not hold text");
+ return self();
+ }
+
+ public ThenDrawingState the_figure_at_index_should_have_text(int index, String expectedText) {
+ TextFigure figure = (TextFigure) drawingView.getDrawing().getChild(index);
+
+ assertThat(figure.getText())
+ .as("Verify content of figure")
+ .isEqualTo(expectedText);
+ return self();
+ }
+
+ public Point2D.Double get_figure_anchor() {
+ Figure figure = drawingView.getDrawing().getChildren().get(0);
+ return figure.getStartPoint();
+ }
+
+ public ThenDrawingState the_figure_should_exist_at(int x, int y) {
+ List children = drawingView.getDrawing().getChildren();
+ Figure figure = children.get(children.size() - 1);
+
+ Point2D.Double currentPoint = figure.getStartPoint();
+
+ assertThat(currentPoint.x).isCloseTo(x, within(1.0));
+ assertThat(currentPoint.y).isCloseTo(y, within(1.0));
+
+ return self();
+ }
+
+ public ThenDrawingState the_canvas_should_be_empty() {
+ assertThat(drawingView.getDrawing().getChildCount())
+ .as("Check that no figures exist")
+ .isEqualTo(0);
+ return self();
+ }
+
+ public ThenDrawingState the_figure_should_be_selected() {
+ List figures = new ArrayList<>(drawingView.getDrawing().getChildren());
+ Figure newestFigure = figures.get(figures.size() - 1);
+
+ assertThat(drawingView.getSelectedFigures())
+ .as("Check that there's only a text figure selected")
+ .hasSize(1)
+ .allMatch(f -> f instanceof TextHolderFigure, "Should be a TextFigure");
+
+ return self();
+ }
+
+ public ThenDrawingState the_figure_should_be_in_edit_mode() {
+ Container viewContainer = (Container) drawingView.getComponent();
+
+
+ window.robot().waitForIdle();
+
+ Component canvas = window.robot().finder().findByName("drawingCanvas", true);
+
+ try {
+ window.robot().finder().find((Container) canvas, c ->
+ c instanceof JTextComponent && c.isShowing()
+ );
+ } catch (ComponentLookupException e) {
+ fail("There should be a floating text editor visible on the canvas");
+ }
+
+ return self();
+ }
+
+ public ThenDrawingState the_figure_should_not_be_in_edit_mode() {
+ window.robot().waitForIdle();
+ Container canvas = (Container) window.robot().finder().findByName("drawingCanvas", true);
+
+ // Verify NO JTextComponent is currently showing on the canvas
+ boolean found = false;
+ for (Component c : canvas.getComponents()) {
+ if (c instanceof javax.swing.text.JTextComponent && c.isShowing()) {
+ found = true;
+ break;
+ }
+ }
+
+ assertThat(found).as("The floating text editor should be closed").isFalse();
+ return self();
+ }
+
+
+}
diff --git a/jhotdraw-core/src/test/java/org/jhotdraw/draw/tool/BaseToolImplTest.java b/jhotdraw-core/src/test/java/org/jhotdraw/draw/tool/BaseToolImplTest.java
new file mode 100644
index 000000000..9b42c9994
--- /dev/null
+++ b/jhotdraw-core/src/test/java/org/jhotdraw/draw/tool/BaseToolImplTest.java
@@ -0,0 +1,61 @@
+package org.jhotdraw.draw.tool;
+
+import org.jhotdraw.draw.DefaultDrawingEditor;
+import org.jhotdraw.draw.DrawingEditor;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+import java.awt.event.KeyListener;
+import java.awt.event.MouseListener;
+import java.awt.event.MouseMotionListener;
+
+
+import static org.junit.Assert.*;
+import static org.mockito.Mockito.mock;
+
+public class BaseToolImplTest {
+ private BaseToolImpl tool;
+ private DrawingEditor editor;
+
+ @Before
+ public void setUp() throws Exception {
+ tool = new BaseToolImpl();
+ editor = mock(DrawingEditor.class);
+ }
+
+ @Test
+ public void testIsInitiallyInactive() {
+ assertFalse(tool.isActive());
+ }
+
+ @Test
+ public void testIsNotFatInterface() {
+
+
+ assertFalse("BaseTool should not be a MouseListener", tool instanceof MouseListener);
+ assertFalse("BaseTool should not be a MouseMotionListener", tool instanceof MouseMotionListener);
+ assertFalse("BaseTool should not be a KeyListener", tool instanceof KeyListener);
+ }
+
+ @Test
+ public void testActivationLifecycle() {
+
+ assertFalse("Tool should start inactive", tool.isActive());
+
+ tool.activate(editor);
+ assertTrue("Tool should be active after being activated", tool.isActive());
+
+ assertEquals("Tool should know its editor", editor, tool.getEditor());
+
+ tool.deactivate(editor);
+ assertFalse("Tool should be inactive after being deactivated", tool.isActive());
+
+
+ }
+
+
+ @After
+ public void tearDown() throws Exception {
+ }
+}
\ No newline at end of file
diff --git a/jhotdraw-core/src/test/java/org/jhotdraw/draw/tool/TextCreationToolTest.java b/jhotdraw-core/src/test/java/org/jhotdraw/draw/tool/TextCreationToolTest.java
new file mode 100644
index 000000000..f716f0587
--- /dev/null
+++ b/jhotdraw-core/src/test/java/org/jhotdraw/draw/tool/TextCreationToolTest.java
@@ -0,0 +1,117 @@
+package org.jhotdraw.draw.tool;
+
+import org.jhotdraw.draw.*;
+import org.jhotdraw.draw.figure.Figure;
+import org.jhotdraw.draw.figure.TextFigure;
+import org.jhotdraw.draw.figure.TextHolderFigure;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.ArgumentCaptor;
+import org.mockito.MockMakers;
+import org.mockito.MockitoAnnotations;
+
+import javax.swing.*;
+import java.awt.*;
+import java.awt.event.KeyListener;
+import java.awt.event.MouseEvent;
+import java.awt.event.MouseListener;
+import java.awt.event.MouseMotionListener;
+import java.awt.geom.Point2D;
+
+import static org.junit.Assert.*;
+import static org.mockito.Mockito.*;
+
+public class TextCreationToolTest {
+ private TextCreationTool tool;
+ private DrawingEditor editor;
+ private TextHolderFigure figure;
+ private Drawing drawing;
+ DrawingView view;
+
+ @Before
+ public void setUp() throws Exception {
+ // Mockito cannot mock this under JDK 25 for whatever reason without this.
+ figure = mock(TextFigure.class);
+ tool = new TextCreationTool(figure);
+ view = mock(DefaultDrawingView.class);
+ editor = mock(DrawingEditor.class);
+ drawing = mock(Drawing.class);
+ when(editor.getActiveView()).thenReturn(view);
+ when(view.getDrawing()).thenReturn(drawing);
+ when(view.viewToDrawing(any(Point.class))).thenReturn(new Point2D.Double(10,10));
+ }
+
+ @Test
+ public void testImplementsNecessaryContracts() {
+ // If this is not true, something has gone terribly wrong.
+ assertNotNull(tool);
+ assertTrue(tool instanceof MouseListener);
+ assertTrue(tool instanceof KeyListener);
+ assertFalse(tool instanceof MouseMotionListener);
+ }
+
+ @Test
+ public void testHandleMouseClicks() {
+ tool.activate(editor);
+
+ MouseEvent event = mock(MouseEvent.class);
+
+ tool.mouseClicked(event);
+
+ verify(editor, atLeastOnce()).getActiveView();
+ }
+
+
+ @Test
+ public void testToolUsesCorrectPrototype() {
+ TextFigure figure = mock(TextFigure.class);
+ when(figure.getText()).thenReturn("Test Text");
+ TextCreationTool tool = new TextCreationTool(figure);
+
+ Figure prototype = tool.getPrototype();
+
+ assertTrue(prototype instanceof TextHolderFigure);
+ assertEquals("Test Text", ((TextHolderFigure) prototype).getText());
+ }
+
+ @Test
+ public void testMouseClickedCreatesAndAddsFigure() {
+
+ // One could argue whether this would have been better with a real instance
+ // rather than mocking this much surface area, but it would also introduce involving Swing a lot more.
+ // The focus is on testing the text creation tool, not on accounting for Swing.
+ MouseEvent event = mock(MouseEvent.class);
+ when(event.getPoint()).thenReturn(new Point(10,10));
+ when(figure.clone()).thenReturn(mock(TextFigure.class));
+ when(event.getClickCount()).thenReturn(1);
+ when(event.getSource()).thenReturn(view);
+ when(view.getComponent()).thenReturn((JComponent) view);
+ when(view.viewToDrawing(any(Point.class))).thenReturn(new Point2D.Double(10,10));
+ when(view.isEnabled()).thenReturn(true);
+ when(editor.findView(any(Container.class))).thenReturn(view);
+
+ TextCreationTool spyTool = spy(tool);
+ // This integration test is about proving the figure is being created and added. Not whether it begins editing.
+ doNothing().when(spyTool).beginEdit(any(TextHolderFigure.class));
+
+
+
+ spyTool.activate(editor);
+
+ spyTool.mouseClicked(event);
+
+ verify(figure, atLeastOnce()).clone();
+ verify(drawing).add(any(TextHolderFigure.class));
+
+ spyTool.deactivate(editor);
+
+
+
+ }
+
+
+ @After
+ public void tearDown() throws Exception {
+ }
+}
\ No newline at end of file
diff --git a/jhotdraw-core/src/test/java/org/jhotdraw/draw/tool/TextEditingToolTest.java b/jhotdraw-core/src/test/java/org/jhotdraw/draw/tool/TextEditingToolTest.java
new file mode 100644
index 000000000..26f2c2cd2
--- /dev/null
+++ b/jhotdraw-core/src/test/java/org/jhotdraw/draw/tool/TextEditingToolTest.java
@@ -0,0 +1,88 @@
+package org.jhotdraw.draw.tool;
+
+import org.jhotdraw.draw.DefaultDrawingView;
+import org.jhotdraw.draw.Drawing;
+import org.jhotdraw.draw.DrawingEditor;
+import org.jhotdraw.draw.DrawingView;
+import org.jhotdraw.draw.figure.TextFigure;
+import org.jhotdraw.draw.figure.TextHolderFigure;
+import org.jhotdraw.draw.text.FloatingTextArea;
+import org.jhotdraw.draw.text.FloatingTextField;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+import javax.swing.*;
+import java.awt.*;
+import java.awt.event.MouseEvent;
+import java.awt.geom.Point2D;
+import java.awt.geom.Rectangle2D;
+
+import static org.junit.Assert.*;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.*;
+
+public class TextEditingToolTest {
+ private TextEditingTool textEditingTool;
+ private DrawingEditor editor;
+ private DrawingView view;
+ private Drawing drawing;
+ private TextHolderFigure textFigure;
+
+
+ @Before
+ public void setUp() throws Exception {
+ view = mock(DefaultDrawingView.class);
+ editor = mock(DrawingEditor.class);
+ drawing = mock(Drawing.class);
+
+ textFigure = new TextFigure("OG Text");
+
+ textEditingTool = new TextEditingTool(textFigure);
+
+ when(editor.getActiveView()).thenReturn(view);
+ when(editor.findView(any(Container.class))).thenReturn(view);
+ when(view.getDrawing()).thenReturn(drawing);
+ when(view.getComponent()).thenReturn((JComponent) view);
+
+ }
+
+ @Test
+ public void testMouseClickStartsEditing() {
+ Point2D.Double drawingPoint = new Point2D.Double(10, 10);
+ when(view.viewToDrawing(any(Point.class))).thenReturn(drawingPoint);
+ when(drawing.findFigureInside(drawingPoint)).thenReturn(textFigure);
+ when(view.getComponent()).thenReturn(new JPanel());
+
+
+ MouseEvent event = mock(MouseEvent.class);
+ when(event.getSource()).thenReturn(view);
+ when(event.getPoint()).thenReturn(new Point(10,10));
+ when(event.getClickCount()).thenReturn(1);
+ when(view.drawingToView(any(Point2D.Double.class))).thenReturn(new Point(10,10));
+ when(view.drawingToView(any(Rectangle2D.Double.class))).thenReturn(new Rectangle(10, 10, 100, 20));
+
+ FloatingTextArea mockEditor = mock(FloatingTextArea.class);
+ when(mockEditor.getText()).thenReturn("New Text");
+
+ textEditingTool.activate(editor);
+ textEditingTool.beginEdit(textFigure);
+
+ assertNotNull("Internal textfield should not be null", textEditingTool.textField);
+
+ FloatingTextField spyField = spy(textEditingTool.textField);
+
+ doReturn("New Text").when(spyField).getText();
+
+ assertEquals("New Text", textFigure.getText());
+
+
+
+
+
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ }
+}
\ No newline at end of file
diff --git a/jhotdraw-core/src/test/java/org/jhotdraw/draw/tool/stages/WhenUserActs.java b/jhotdraw-core/src/test/java/org/jhotdraw/draw/tool/stages/WhenUserActs.java
new file mode 100644
index 000000000..cb40ee2c6
--- /dev/null
+++ b/jhotdraw-core/src/test/java/org/jhotdraw/draw/tool/stages/WhenUserActs.java
@@ -0,0 +1,111 @@
+package org.jhotdraw.draw.tool.stages;
+
+import org.assertj.swing.core.MouseButton;
+import org.assertj.swing.core.MouseClickInfo;
+import org.assertj.swing.fixture.JTextComponentFixture;
+import org.jhotdraw.draw.DrawingView;
+import org.jhotdraw.draw.figure.Figure;
+import org.jhotdraw.draw.stages.JHotDrawStage;
+import org.jhotdraw.draw.stages.ThenDrawingState;
+
+import javax.swing.*;
+import javax.swing.text.JTextComponent;
+import java.awt.*;
+import java.awt.event.KeyEvent;
+import java.awt.geom.Point2D;
+import java.awt.geom.Rectangle2D;
+import java.util.List;
+
+import static org.assertj.swing.core.KeyPressInfo.keyCode;
+import static org.assertj.core.api.Assertions.fail;
+
+
+public class WhenUserActs extends JHotDrawStage {
+
+ private DrawingView drawingView;
+
+ public WhenUserActs the_user_clicks_on_the_canvas_at(int x, int y) {
+ Component canvas = window.robot().finder().findByName("drawingCanvas", true);
+ window.robot().click(canvas, new Point(x,y));
+ return self();
+ }
+
+ public WhenUserActs the_user_double_clicks_on_the_canvas_at(int x, int y) {
+ Component canvas = window.robot().finder().findByName("drawingCanvas", true);
+ window.robot().click(canvas, new Point(x,y), MouseButton.LEFT_BUTTON, 2);
+ return self();
+ }
+
+
+
+
+ public WhenUserActs the_user_double_clicks_the_figure_at(int x, int y) {
+ Figure figure = drawingView.getDrawing().findFigure(new Point2D.Double(x,y));
+
+
+ // As a fallback, choose the newest
+ if (figure == null) {
+ List children = drawingView.getDrawing().getChildren();
+ if (!children.isEmpty()) {
+ figure = children.get(children.size() - 1);
+ }
+ }
+
+ if (figure == null) {
+ fail("No figure found at " + x + " " + y + " and drawing is empty.");
+ }
+
+ Rectangle2D.Double bounds = figure.getBounds();
+
+ int centerX = (int) bounds.getCenterX();
+ int centerY = (int) bounds.getCenterY();
+
+ Component canvas = window.robot().finder().findByName("drawingCanvas", true);
+ window.robot().click(canvas, new Point(centerX,centerY), MouseButton.LEFT_BUTTON, 2);
+ return self();
+ }
+
+ public WhenUserActs the_user_types(String text) {
+ window.robot().enterText(text);
+ window.robot().waitForIdle();
+ return self();
+ }
+
+ public WhenUserActs the_user_presses_the_escape_key() {
+ window.robot().waitForIdle();
+
+
+ Component canvas = window.robot().finder().findByName("drawingCanvas", true);
+ JTextComponent editor = (JTextComponent) window.robot().finder().find((Container) canvas,
+ c -> c instanceof JTextComponent && c.isShowing());
+
+ window.robot().focusAndWaitForFocusGain(editor);
+
+ new JTextComponentFixture(window.robot(), editor).pressAndReleaseKey(keyCode(KeyEvent.VK_ESCAPE));
+
+ window.robot().waitForIdle();
+ return self();
+ }
+
+
+ public WhenUserActs the_user_clears_the_text_and_deselects() {
+ window.robot().pressAndReleaseKey(KeyEvent.VK_A, KeyEvent.CTRL_DOWN_MASK);
+ window.robot().pressAndReleaseKey(KeyEvent.VK_BACK_SPACE);
+ Component canvas = window.robot().finder().findByName("drawingCanvas", true);
+
+ return the_user_clicks_on_the_canvas_at(0,0);
+ }
+
+ public WhenUserActs the_user_finishes_editing() {
+ Component canvas = window.robot().finder().findByName("drawingCanvas", true);
+ window.robot().click(canvas, new Point(1,1));
+ return self();
+ }
+
+
+ public WhenUserActs setView(DrawingView view) {
+ this.drawingView = view;
+ return self();
+ }
+
+}
diff --git a/jhotdraw-gui/src/main/java/org/jhotdraw/gui/action/ButtonFactory.java b/jhotdraw-gui/src/main/java/org/jhotdraw/gui/action/ButtonFactory.java
index 1470a011b..b765ee6be 100644
--- a/jhotdraw-gui/src/main/java/org/jhotdraw/gui/action/ButtonFactory.java
+++ b/jhotdraw-gui/src/main/java/org/jhotdraw/gui/action/ButtonFactory.java
@@ -99,6 +99,7 @@
import org.jhotdraw.draw.event.ToolAdapter;
import org.jhotdraw.draw.event.ToolEvent;
import org.jhotdraw.draw.event.ToolListener;
+import org.jhotdraw.draw.tool.BaseTool;
import org.jhotdraw.draw.tool.DelegationSelectionTool;
import org.jhotdraw.draw.tool.Tool;
import org.jhotdraw.geom.DoubleStroke;
@@ -307,10 +308,10 @@ public class ButtonFactory {
private static class ToolButtonListener implements ItemListener {
- private Tool tool;
+ private BaseTool tool;
private DrawingEditor editor;
- public ToolButtonListener(Tool t, DrawingEditor editor) {
+ public ToolButtonListener(BaseTool t, DrawingEditor editor) {
this.tool = t;
this.editor = editor;
}
@@ -370,7 +371,7 @@ public static JToggleButton addSelectionToolTo(JToolBar tb, final DrawingEditor
public static JToggleButton addSelectionToolTo(JToolBar tb, final DrawingEditor editor, Tool selectionTool) {
ResourceBundleUtil labels = ResourceBundleUtil.getBundle("org.jhotdraw.draw.Labels");
JToggleButton t;
- Tool tool;
+ BaseTool tool;
HashMap attributes;
ButtonGroup group;
if (tb.getClientProperty("toolButtonGroup") instanceof ButtonGroup) {
@@ -409,7 +410,7 @@ public void toolDone(ToolEvent event) {
*
*/
public static JToggleButton addToolTo(JToolBar tb, DrawingEditor editor,
- Tool tool, String labelKey,
+ BaseTool tool, String labelKey,
ResourceBundleUtil labels) {
ButtonGroup group = (ButtonGroup) tb.getClientProperty("toolButtonGroup");
ToolListener toolHandler = (ToolListener) tb.getClientProperty("toolHandler");
diff --git a/jhotdraw-samples/jhotdraw-samples-misc/jgiven-reports/org.jhotdraw.samples.svg.TextToolScenarioTest.json b/jhotdraw-samples/jhotdraw-samples-misc/jgiven-reports/org.jhotdraw.samples.svg.TextToolScenarioTest.json
new file mode 100644
index 000000000..8df501b9e
--- /dev/null
+++ b/jhotdraw-samples/jhotdraw-samples-misc/jgiven-reports/org.jhotdraw.samples.svg.TextToolScenarioTest.json
@@ -0,0 +1,1340 @@
+{
+ "className": "org.jhotdraw.samples.svg.TextToolScenarioTest",
+ "name": "Text Tool Scenario",
+ "scenarios": [
+ {
+ "className": "org.jhotdraw.samples.svg.TextToolScenarioTest",
+ "testMethodName": "pressing_escape_exits_edit_mode",
+ "description": "pressing escape exits edit mode",
+ "tagIds": [],
+ "explicitParameters": [],
+ "derivedParameters": [],
+ "scenarioCases": [
+ {
+ "caseNr": 1,
+ "steps": [
+ {
+ "name": "set fixtures",
+ "words": [
+ {
+ "value": "Given",
+ "isIntroWord": true
+ },
+ {
+ "value": "set fixtures"
+ },
+ {
+ "value": "org.assertj.swing.fixture.FrameFixture@75a2673b",
+ "argumentInfo": {
+ "argumentName": "fixture",
+ "formattedValue": "org.assertj.swing.fixture.FrameFixture@75a2673b"
+ }
+ },
+ {
+ "value": "org.assertj.swing.core.BasicRobot@1e8823d2",
+ "argumentInfo": {
+ "argumentName": "robotInstance",
+ "formattedValue": "org.assertj.swing.core.BasicRobot@1e8823d2"
+ }
+ },
+ {
+ "value": "org.jhotdraw.draw.DefaultDrawingEditor@3b42d73b",
+ "argumentInfo": {
+ "argumentName": "drawingEditor",
+ "formattedValue": "org.jhotdraw.draw.DefaultDrawingEditor@3b42d73b"
+ }
+ },
+ {
+ "value": "org.jhotdraw.draw.DefaultDrawingView[drawingCanvas,0,0,1920x887,alignmentX\u003d0.0,alignmentY\u003d0.0,border\u003d,flags\u003d16777224,maximumSize\u003d,minimumSize\u003d,preferredSize\u003d]",
+ "argumentInfo": {
+ "argumentName": "drawingView",
+ "formattedValue": "org.jhotdraw.draw.DefaultDrawingView[drawingCanvas,0,0,1920x887,alignmentX\u003d0.0,alignmentY\u003d0.0,border\u003d,flags\u003d16777224,maximumSize\u003d,minimumSize\u003d,preferredSize\u003d]"
+ }
+ }
+ ],
+ "status": "PASSED",
+ "durationInNanos": 34309800,
+ "depth": 0,
+ "parentFailed": false
+ },
+ {
+ "name": "set fixtures",
+ "words": [
+ {
+ "value": "When",
+ "isIntroWord": true
+ },
+ {
+ "value": "set fixtures"
+ },
+ {
+ "value": "org.assertj.swing.fixture.FrameFixture@75a2673b",
+ "argumentInfo": {
+ "argumentName": "fixture",
+ "formattedValue": "org.assertj.swing.fixture.FrameFixture@75a2673b"
+ }
+ },
+ {
+ "value": "org.assertj.swing.core.BasicRobot@1e8823d2",
+ "argumentInfo": {
+ "argumentName": "robotInstance",
+ "formattedValue": "org.assertj.swing.core.BasicRobot@1e8823d2"
+ }
+ },
+ {
+ "value": "org.jhotdraw.draw.DefaultDrawingEditor@3b42d73b",
+ "argumentInfo": {
+ "argumentName": "drawingEditor",
+ "formattedValue": "org.jhotdraw.draw.DefaultDrawingEditor@3b42d73b"
+ }
+ },
+ {
+ "value": "org.jhotdraw.draw.DefaultDrawingView[drawingCanvas,0,0,1920x887,alignmentX\u003d0.0,alignmentY\u003d0.0,border\u003d,flags\u003d16777224,maximumSize\u003d,minimumSize\u003d,preferredSize\u003d]",
+ "argumentInfo": {
+ "argumentName": "drawingView",
+ "formattedValue": "org.jhotdraw.draw.DefaultDrawingView[drawingCanvas,0,0,1920x887,alignmentX\u003d0.0,alignmentY\u003d0.0,border\u003d,flags\u003d16777224,maximumSize\u003d,minimumSize\u003d,preferredSize\u003d]"
+ }
+ }
+ ],
+ "status": "PASSED",
+ "durationInNanos": 1414800,
+ "depth": 0,
+ "parentFailed": false
+ },
+ {
+ "name": "set view",
+ "words": [
+ {
+ "value": "When",
+ "isIntroWord": true
+ },
+ {
+ "value": "set view"
+ },
+ {
+ "value": "org.jhotdraw.draw.DefaultDrawingView[drawingCanvas,0,0,1920x887,alignmentX\u003d0.0,alignmentY\u003d0.0,border\u003d,flags\u003d16777224,maximumSize\u003d,minimumSize\u003d,preferredSize\u003d]",
+ "argumentInfo": {
+ "argumentName": "view",
+ "formattedValue": "org.jhotdraw.draw.DefaultDrawingView[drawingCanvas,0,0,1920x887,alignmentX\u003d0.0,alignmentY\u003d0.0,border\u003d,flags\u003d16777224,maximumSize\u003d,minimumSize\u003d,preferredSize\u003d]"
+ }
+ }
+ ],
+ "status": "PASSED",
+ "durationInNanos": 1119000,
+ "depth": 0,
+ "parentFailed": false
+ },
+ {
+ "name": "set view",
+ "words": [
+ {
+ "value": "Then",
+ "isIntroWord": true
+ },
+ {
+ "value": "set view"
+ },
+ {
+ "value": "org.jhotdraw.draw.DefaultDrawingView[drawingCanvas,0,0,1920x887,alignmentX\u003d0.0,alignmentY\u003d0.0,border\u003d,flags\u003d16777224,maximumSize\u003d,minimumSize\u003d,preferredSize\u003d]",
+ "argumentInfo": {
+ "argumentName": "view",
+ "formattedValue": "org.jhotdraw.draw.DefaultDrawingView[drawingCanvas,0,0,1920x887,alignmentX\u003d0.0,alignmentY\u003d0.0,border\u003d,flags\u003d16777224,maximumSize\u003d,minimumSize\u003d,preferredSize\u003d]"
+ }
+ }
+ ],
+ "status": "PASSED",
+ "durationInNanos": 1138200,
+ "depth": 0,
+ "parentFailed": false
+ },
+ {
+ "name": "the text tool is selected",
+ "words": [
+ {
+ "value": "Given",
+ "isIntroWord": true
+ },
+ {
+ "value": "the text tool is selected"
+ }
+ ],
+ "status": "PASSED",
+ "durationInNanos": 371494900,
+ "depth": 0,
+ "parentFailed": false
+ },
+ {
+ "name": "the user clicks on the canvas at",
+ "words": [
+ {
+ "value": "When",
+ "isIntroWord": true
+ },
+ {
+ "value": "the user clicks on the canvas at"
+ },
+ {
+ "value": "200",
+ "argumentInfo": {
+ "argumentName": "x",
+ "formattedValue": "200"
+ }
+ },
+ {
+ "value": "200",
+ "argumentInfo": {
+ "argumentName": "y",
+ "formattedValue": "200"
+ }
+ }
+ ],
+ "status": "PASSED",
+ "durationInNanos": 291831100,
+ "depth": 0,
+ "parentFailed": false
+ },
+ {
+ "name": "the user types",
+ "words": [
+ {
+ "value": "and",
+ "isIntroWord": true
+ },
+ {
+ "value": "the user types"
+ },
+ {
+ "value": "Pass Rot, Pop Green, Watch The Rots",
+ "argumentInfo": {
+ "argumentName": "text",
+ "formattedValue": "Pass Rot, Pop Green, Watch The Rots"
+ }
+ }
+ ],
+ "status": "PASSED",
+ "durationInNanos": 6250877400,
+ "depth": 0,
+ "parentFailed": false
+ },
+ {
+ "name": "the user presses the escape key",
+ "words": [
+ {
+ "value": "and",
+ "isIntroWord": true
+ },
+ {
+ "value": "the user presses the escape key"
+ }
+ ],
+ "status": "PASSED",
+ "durationInNanos": 339768500,
+ "depth": 0,
+ "parentFailed": false
+ },
+ {
+ "name": "the figure should not be in edit mode",
+ "words": [
+ {
+ "value": "Then",
+ "isIntroWord": true
+ },
+ {
+ "value": "the figure should not be in edit mode"
+ }
+ ],
+ "status": "PASSED",
+ "durationInNanos": 165131500,
+ "depth": 0,
+ "parentFailed": false
+ }
+ ],
+ "explicitArguments": [],
+ "derivedArguments": [],
+ "status": "SUCCESS",
+ "durationInNanos": 9556947500
+ }
+ ],
+ "casesAsTable": false,
+ "durationInNanos": 9556947500
+ },
+ {
+ "className": "org.jhotdraw.samples.svg.TextToolScenarioTest",
+ "testMethodName": "figure_stays_at_original_location",
+ "description": "figure stays at original location",
+ "tagIds": [],
+ "explicitParameters": [],
+ "derivedParameters": [],
+ "scenarioCases": [
+ {
+ "caseNr": 1,
+ "steps": [
+ {
+ "name": "set fixtures",
+ "words": [
+ {
+ "value": "Given",
+ "isIntroWord": true
+ },
+ {
+ "value": "set fixtures"
+ },
+ {
+ "value": "org.assertj.swing.fixture.FrameFixture@7a306bb2",
+ "argumentInfo": {
+ "argumentName": "fixture",
+ "formattedValue": "org.assertj.swing.fixture.FrameFixture@7a306bb2"
+ }
+ },
+ {
+ "value": "org.assertj.swing.core.BasicRobot@971e903",
+ "argumentInfo": {
+ "argumentName": "robotInstance",
+ "formattedValue": "org.assertj.swing.core.BasicRobot@971e903"
+ }
+ },
+ {
+ "value": "org.jhotdraw.draw.DefaultDrawingEditor@1e56c8e6",
+ "argumentInfo": {
+ "argumentName": "drawingEditor",
+ "formattedValue": "org.jhotdraw.draw.DefaultDrawingEditor@1e56c8e6"
+ }
+ },
+ {
+ "value": "org.jhotdraw.draw.DefaultDrawingView[drawingCanvas,0,0,1920x887,alignmentX\u003d0.0,alignmentY\u003d0.0,border\u003d,flags\u003d16777224,maximumSize\u003d,minimumSize\u003d,preferredSize\u003d]",
+ "argumentInfo": {
+ "argumentName": "drawingView",
+ "formattedValue": "org.jhotdraw.draw.DefaultDrawingView[drawingCanvas,0,0,1920x887,alignmentX\u003d0.0,alignmentY\u003d0.0,border\u003d,flags\u003d16777224,maximumSize\u003d,minimumSize\u003d,preferredSize\u003d]"
+ }
+ }
+ ],
+ "status": "PASSED",
+ "durationInNanos": 724800,
+ "depth": 0,
+ "parentFailed": false
+ },
+ {
+ "name": "set fixtures",
+ "words": [
+ {
+ "value": "When",
+ "isIntroWord": true
+ },
+ {
+ "value": "set fixtures"
+ },
+ {
+ "value": "org.assertj.swing.fixture.FrameFixture@7a306bb2",
+ "argumentInfo": {
+ "argumentName": "fixture",
+ "formattedValue": "org.assertj.swing.fixture.FrameFixture@7a306bb2"
+ }
+ },
+ {
+ "value": "org.assertj.swing.core.BasicRobot@971e903",
+ "argumentInfo": {
+ "argumentName": "robotInstance",
+ "formattedValue": "org.assertj.swing.core.BasicRobot@971e903"
+ }
+ },
+ {
+ "value": "org.jhotdraw.draw.DefaultDrawingEditor@1e56c8e6",
+ "argumentInfo": {
+ "argumentName": "drawingEditor",
+ "formattedValue": "org.jhotdraw.draw.DefaultDrawingEditor@1e56c8e6"
+ }
+ },
+ {
+ "value": "org.jhotdraw.draw.DefaultDrawingView[drawingCanvas,0,0,1920x887,alignmentX\u003d0.0,alignmentY\u003d0.0,border\u003d,flags\u003d16777224,maximumSize\u003d,minimumSize\u003d,preferredSize\u003d]",
+ "argumentInfo": {
+ "argumentName": "drawingView",
+ "formattedValue": "org.jhotdraw.draw.DefaultDrawingView[drawingCanvas,0,0,1920x887,alignmentX\u003d0.0,alignmentY\u003d0.0,border\u003d,flags\u003d16777224,maximumSize\u003d,minimumSize\u003d,preferredSize\u003d]"
+ }
+ }
+ ],
+ "status": "PASSED",
+ "durationInNanos": 428400,
+ "depth": 0,
+ "parentFailed": false
+ },
+ {
+ "name": "set view",
+ "words": [
+ {
+ "value": "When",
+ "isIntroWord": true
+ },
+ {
+ "value": "set view"
+ },
+ {
+ "value": "org.jhotdraw.draw.DefaultDrawingView[drawingCanvas,0,0,1920x887,alignmentX\u003d0.0,alignmentY\u003d0.0,border\u003d,flags\u003d16777224,maximumSize\u003d,minimumSize\u003d,preferredSize\u003d]",
+ "argumentInfo": {
+ "argumentName": "view",
+ "formattedValue": "org.jhotdraw.draw.DefaultDrawingView[drawingCanvas,0,0,1920x887,alignmentX\u003d0.0,alignmentY\u003d0.0,border\u003d,flags\u003d16777224,maximumSize\u003d,minimumSize\u003d,preferredSize\u003d]"
+ }
+ }
+ ],
+ "status": "PASSED",
+ "durationInNanos": 445100,
+ "depth": 0,
+ "parentFailed": false
+ },
+ {
+ "name": "set view",
+ "words": [
+ {
+ "value": "Then",
+ "isIntroWord": true
+ },
+ {
+ "value": "set view"
+ },
+ {
+ "value": "org.jhotdraw.draw.DefaultDrawingView[drawingCanvas,0,0,1920x887,alignmentX\u003d0.0,alignmentY\u003d0.0,border\u003d,flags\u003d16777224,maximumSize\u003d,minimumSize\u003d,preferredSize\u003d]",
+ "argumentInfo": {
+ "argumentName": "view",
+ "formattedValue": "org.jhotdraw.draw.DefaultDrawingView[drawingCanvas,0,0,1920x887,alignmentX\u003d0.0,alignmentY\u003d0.0,border\u003d,flags\u003d16777224,maximumSize\u003d,minimumSize\u003d,preferredSize\u003d]"
+ }
+ }
+ ],
+ "status": "PASSED",
+ "durationInNanos": 442800,
+ "depth": 0,
+ "parentFailed": false
+ },
+ {
+ "name": "the text tool is selected",
+ "words": [
+ {
+ "value": "Given",
+ "isIntroWord": true
+ },
+ {
+ "value": "the text tool is selected"
+ }
+ ],
+ "status": "PASSED",
+ "durationInNanos": 359124600,
+ "depth": 0,
+ "parentFailed": false
+ },
+ {
+ "name": "the user clicks on the canvas at",
+ "words": [
+ {
+ "value": "When",
+ "isIntroWord": true
+ },
+ {
+ "value": "the user clicks on the canvas at"
+ },
+ {
+ "value": "200",
+ "argumentInfo": {
+ "argumentName": "x",
+ "formattedValue": "200"
+ }
+ },
+ {
+ "value": "200",
+ "argumentInfo": {
+ "argumentName": "y",
+ "formattedValue": "200"
+ }
+ }
+ ],
+ "status": "PASSED",
+ "durationInNanos": 262065600,
+ "depth": 0,
+ "parentFailed": false
+ },
+ {
+ "name": "the user types",
+ "words": [
+ {
+ "value": "and",
+ "isIntroWord": true
+ },
+ {
+ "value": "the user types"
+ },
+ {
+ "value": "Red is defamation",
+ "argumentInfo": {
+ "argumentName": "text",
+ "formattedValue": "Red is defamation"
+ }
+ }
+ ],
+ "status": "PASSED",
+ "durationInNanos": 2447705400,
+ "depth": 0,
+ "parentFailed": false
+ },
+ {
+ "name": "get figure anchor",
+ "words": [
+ {
+ "value": "Then",
+ "isIntroWord": true
+ },
+ {
+ "value": "get figure anchor"
+ }
+ ],
+ "status": "PASSED",
+ "durationInNanos": 71800,
+ "depth": 0,
+ "parentFailed": false
+ },
+ {
+ "name": "the user finishes editing",
+ "words": [
+ {
+ "value": "When",
+ "isIntroWord": true
+ },
+ {
+ "value": "the user finishes editing"
+ }
+ ],
+ "status": "PASSED",
+ "durationInNanos": 247323400,
+ "depth": 0,
+ "parentFailed": false
+ },
+ {
+ "name": "the figure should exist at",
+ "words": [
+ {
+ "value": "Then",
+ "isIntroWord": true
+ },
+ {
+ "value": "the figure should exist at"
+ },
+ {
+ "value": "200",
+ "argumentInfo": {
+ "argumentName": "x",
+ "formattedValue": "200"
+ }
+ },
+ {
+ "value": "187",
+ "argumentInfo": {
+ "argumentName": "y",
+ "formattedValue": "187"
+ }
+ }
+ ],
+ "status": "PASSED",
+ "durationInNanos": 4357900,
+ "depth": 0,
+ "parentFailed": false
+ }
+ ],
+ "explicitArguments": [],
+ "derivedArguments": [],
+ "status": "SUCCESS",
+ "durationInNanos": 4308424000
+ }
+ ],
+ "casesAsTable": false,
+ "durationInNanos": 4308424000
+ },
+ {
+ "className": "org.jhotdraw.samples.svg.TextToolScenarioTest",
+ "testMethodName": "user_can_create_and_type_text",
+ "description": "user can create and type text",
+ "tagIds": [],
+ "explicitParameters": [],
+ "derivedParameters": [],
+ "scenarioCases": [
+ {
+ "caseNr": 1,
+ "steps": [
+ {
+ "name": "set fixtures",
+ "words": [
+ {
+ "value": "Given",
+ "isIntroWord": true
+ },
+ {
+ "value": "set fixtures"
+ },
+ {
+ "value": "org.assertj.swing.fixture.FrameFixture@4b7cd802",
+ "argumentInfo": {
+ "argumentName": "fixture",
+ "formattedValue": "org.assertj.swing.fixture.FrameFixture@4b7cd802"
+ }
+ },
+ {
+ "value": "org.assertj.swing.core.BasicRobot@715d6168",
+ "argumentInfo": {
+ "argumentName": "robotInstance",
+ "formattedValue": "org.assertj.swing.core.BasicRobot@715d6168"
+ }
+ },
+ {
+ "value": "org.jhotdraw.draw.DefaultDrawingEditor@29c4fdbe",
+ "argumentInfo": {
+ "argumentName": "drawingEditor",
+ "formattedValue": "org.jhotdraw.draw.DefaultDrawingEditor@29c4fdbe"
+ }
+ },
+ {
+ "value": "org.jhotdraw.draw.DefaultDrawingView[drawingCanvas,0,0,1920x887,alignmentX\u003d0.0,alignmentY\u003d0.0,border\u003d,flags\u003d16777224,maximumSize\u003d,minimumSize\u003d,preferredSize\u003d]",
+ "argumentInfo": {
+ "argumentName": "drawingView",
+ "formattedValue": "org.jhotdraw.draw.DefaultDrawingView[drawingCanvas,0,0,1920x887,alignmentX\u003d0.0,alignmentY\u003d0.0,border\u003d,flags\u003d16777224,maximumSize\u003d,minimumSize\u003d,preferredSize\u003d]"
+ }
+ }
+ ],
+ "status": "PASSED",
+ "durationInNanos": 929700,
+ "depth": 0,
+ "parentFailed": false
+ },
+ {
+ "name": "set fixtures",
+ "words": [
+ {
+ "value": "When",
+ "isIntroWord": true
+ },
+ {
+ "value": "set fixtures"
+ },
+ {
+ "value": "org.assertj.swing.fixture.FrameFixture@4b7cd802",
+ "argumentInfo": {
+ "argumentName": "fixture",
+ "formattedValue": "org.assertj.swing.fixture.FrameFixture@4b7cd802"
+ }
+ },
+ {
+ "value": "org.assertj.swing.core.BasicRobot@715d6168",
+ "argumentInfo": {
+ "argumentName": "robotInstance",
+ "formattedValue": "org.assertj.swing.core.BasicRobot@715d6168"
+ }
+ },
+ {
+ "value": "org.jhotdraw.draw.DefaultDrawingEditor@29c4fdbe",
+ "argumentInfo": {
+ "argumentName": "drawingEditor",
+ "formattedValue": "org.jhotdraw.draw.DefaultDrawingEditor@29c4fdbe"
+ }
+ },
+ {
+ "value": "org.jhotdraw.draw.DefaultDrawingView[drawingCanvas,0,0,1920x887,alignmentX\u003d0.0,alignmentY\u003d0.0,border\u003d,flags\u003d16777224,maximumSize\u003d,minimumSize\u003d,preferredSize\u003d]",
+ "argumentInfo": {
+ "argumentName": "drawingView",
+ "formattedValue": "org.jhotdraw.draw.DefaultDrawingView[drawingCanvas,0,0,1920x887,alignmentX\u003d0.0,alignmentY\u003d0.0,border\u003d,flags\u003d16777224,maximumSize\u003d,minimumSize\u003d,preferredSize\u003d]"
+ }
+ }
+ ],
+ "status": "PASSED",
+ "durationInNanos": 1179800,
+ "depth": 0,
+ "parentFailed": false
+ },
+ {
+ "name": "set view",
+ "words": [
+ {
+ "value": "When",
+ "isIntroWord": true
+ },
+ {
+ "value": "set view"
+ },
+ {
+ "value": "org.jhotdraw.draw.DefaultDrawingView[drawingCanvas,0,0,1920x887,alignmentX\u003d0.0,alignmentY\u003d0.0,border\u003d,flags\u003d16777224,maximumSize\u003d,minimumSize\u003d,preferredSize\u003d]",
+ "argumentInfo": {
+ "argumentName": "view",
+ "formattedValue": "org.jhotdraw.draw.DefaultDrawingView[drawingCanvas,0,0,1920x887,alignmentX\u003d0.0,alignmentY\u003d0.0,border\u003d,flags\u003d16777224,maximumSize\u003d,minimumSize\u003d,preferredSize\u003d]"
+ }
+ }
+ ],
+ "status": "PASSED",
+ "durationInNanos": 696600,
+ "depth": 0,
+ "parentFailed": false
+ },
+ {
+ "name": "set view",
+ "words": [
+ {
+ "value": "Then",
+ "isIntroWord": true
+ },
+ {
+ "value": "set view"
+ },
+ {
+ "value": "org.jhotdraw.draw.DefaultDrawingView[drawingCanvas,0,0,1920x887,alignmentX\u003d0.0,alignmentY\u003d0.0,border\u003d,flags\u003d16777224,maximumSize\u003d,minimumSize\u003d,preferredSize\u003d]",
+ "argumentInfo": {
+ "argumentName": "view",
+ "formattedValue": "org.jhotdraw.draw.DefaultDrawingView[drawingCanvas,0,0,1920x887,alignmentX\u003d0.0,alignmentY\u003d0.0,border\u003d,flags\u003d16777224,maximumSize\u003d,minimumSize\u003d,preferredSize\u003d]"
+ }
+ }
+ ],
+ "status": "PASSED",
+ "durationInNanos": 681400,
+ "depth": 0,
+ "parentFailed": false
+ },
+ {
+ "name": "the text tool is selected",
+ "words": [
+ {
+ "value": "Given",
+ "isIntroWord": true
+ },
+ {
+ "value": "the text tool is selected"
+ }
+ ],
+ "status": "PASSED",
+ "durationInNanos": 311449200,
+ "depth": 0,
+ "parentFailed": false
+ },
+ {
+ "name": "the user clicks on the canvas at",
+ "words": [
+ {
+ "value": "When",
+ "isIntroWord": true
+ },
+ {
+ "value": "the user clicks on the canvas at"
+ },
+ {
+ "value": "200",
+ "argumentInfo": {
+ "argumentName": "x",
+ "formattedValue": "200"
+ }
+ },
+ {
+ "value": "200",
+ "argumentInfo": {
+ "argumentName": "y",
+ "formattedValue": "200"
+ }
+ }
+ ],
+ "status": "PASSED",
+ "durationInNanos": 253738100,
+ "depth": 0,
+ "parentFailed": false
+ },
+ {
+ "name": "the user types",
+ "words": [
+ {
+ "value": "and",
+ "isIntroWord": true
+ },
+ {
+ "value": "the user types"
+ },
+ {
+ "value": "Hello Near World",
+ "argumentInfo": {
+ "argumentName": "text",
+ "formattedValue": "Hello Near World"
+ }
+ }
+ ],
+ "status": "PASSED",
+ "durationInNanos": 2744810300,
+ "depth": 0,
+ "parentFailed": false
+ },
+ {
+ "name": "a new text figure should exist",
+ "words": [
+ {
+ "value": "Then",
+ "isIntroWord": true
+ },
+ {
+ "value": "a new text figure should exist"
+ }
+ ],
+ "status": "PASSED",
+ "durationInNanos": 3601600,
+ "depth": 0,
+ "parentFailed": false
+ },
+ {
+ "name": "the figure should be selected",
+ "words": [
+ {
+ "value": "and",
+ "isIntroWord": true
+ },
+ {
+ "value": "the figure should be selected"
+ }
+ ],
+ "status": "PASSED",
+ "durationInNanos": 8048500,
+ "depth": 0,
+ "parentFailed": false
+ }
+ ],
+ "explicitArguments": [],
+ "derivedArguments": [],
+ "status": "SUCCESS",
+ "durationInNanos": 4254722000
+ }
+ ],
+ "casesAsTable": false,
+ "durationInNanos": 4254722000
+ },
+ {
+ "className": "org.jhotdraw.samples.svg.TextToolScenarioTest",
+ "testMethodName": "clicking_existing_text_with_selection_tool_enters_edit_mode",
+ "description": "clicking existing text with selection tool enters edit mode",
+ "tagIds": [],
+ "explicitParameters": [],
+ "derivedParameters": [],
+ "scenarioCases": [
+ {
+ "caseNr": 1,
+ "steps": [
+ {
+ "name": "set fixtures",
+ "words": [
+ {
+ "value": "Given",
+ "isIntroWord": true
+ },
+ {
+ "value": "set fixtures"
+ },
+ {
+ "value": "org.assertj.swing.fixture.FrameFixture@286026f9",
+ "argumentInfo": {
+ "argumentName": "fixture",
+ "formattedValue": "org.assertj.swing.fixture.FrameFixture@286026f9"
+ }
+ },
+ {
+ "value": "org.assertj.swing.core.BasicRobot@4ac86d6a",
+ "argumentInfo": {
+ "argumentName": "robotInstance",
+ "formattedValue": "org.assertj.swing.core.BasicRobot@4ac86d6a"
+ }
+ },
+ {
+ "value": "org.jhotdraw.draw.DefaultDrawingEditor@27109b22",
+ "argumentInfo": {
+ "argumentName": "drawingEditor",
+ "formattedValue": "org.jhotdraw.draw.DefaultDrawingEditor@27109b22"
+ }
+ },
+ {
+ "value": "org.jhotdraw.draw.DefaultDrawingView[drawingCanvas,0,0,1920x887,alignmentX\u003d0.0,alignmentY\u003d0.0,border\u003d,flags\u003d16777224,maximumSize\u003d,minimumSize\u003d,preferredSize\u003d]",
+ "argumentInfo": {
+ "argumentName": "drawingView",
+ "formattedValue": "org.jhotdraw.draw.DefaultDrawingView[drawingCanvas,0,0,1920x887,alignmentX\u003d0.0,alignmentY\u003d0.0,border\u003d,flags\u003d16777224,maximumSize\u003d,minimumSize\u003d,preferredSize\u003d]"
+ }
+ }
+ ],
+ "status": "PASSED",
+ "durationInNanos": 874100,
+ "depth": 0,
+ "parentFailed": false
+ },
+ {
+ "name": "set fixtures",
+ "words": [
+ {
+ "value": "When",
+ "isIntroWord": true
+ },
+ {
+ "value": "set fixtures"
+ },
+ {
+ "value": "org.assertj.swing.fixture.FrameFixture@286026f9",
+ "argumentInfo": {
+ "argumentName": "fixture",
+ "formattedValue": "org.assertj.swing.fixture.FrameFixture@286026f9"
+ }
+ },
+ {
+ "value": "org.assertj.swing.core.BasicRobot@4ac86d6a",
+ "argumentInfo": {
+ "argumentName": "robotInstance",
+ "formattedValue": "org.assertj.swing.core.BasicRobot@4ac86d6a"
+ }
+ },
+ {
+ "value": "org.jhotdraw.draw.DefaultDrawingEditor@27109b22",
+ "argumentInfo": {
+ "argumentName": "drawingEditor",
+ "formattedValue": "org.jhotdraw.draw.DefaultDrawingEditor@27109b22"
+ }
+ },
+ {
+ "value": "org.jhotdraw.draw.DefaultDrawingView[drawingCanvas,0,0,1920x887,alignmentX\u003d0.0,alignmentY\u003d0.0,border\u003d,flags\u003d16777224,maximumSize\u003d,minimumSize\u003d,preferredSize\u003d]",
+ "argumentInfo": {
+ "argumentName": "drawingView",
+ "formattedValue": "org.jhotdraw.draw.DefaultDrawingView[drawingCanvas,0,0,1920x887,alignmentX\u003d0.0,alignmentY\u003d0.0,border\u003d,flags\u003d16777224,maximumSize\u003d,minimumSize\u003d,preferredSize\u003d]"
+ }
+ }
+ ],
+ "status": "PASSED",
+ "durationInNanos": 561600,
+ "depth": 0,
+ "parentFailed": false
+ },
+ {
+ "name": "set view",
+ "words": [
+ {
+ "value": "When",
+ "isIntroWord": true
+ },
+ {
+ "value": "set view"
+ },
+ {
+ "value": "org.jhotdraw.draw.DefaultDrawingView[drawingCanvas,0,0,1920x887,alignmentX\u003d0.0,alignmentY\u003d0.0,border\u003d,flags\u003d16777224,maximumSize\u003d,minimumSize\u003d,preferredSize\u003d]",
+ "argumentInfo": {
+ "argumentName": "view",
+ "formattedValue": "org.jhotdraw.draw.DefaultDrawingView[drawingCanvas,0,0,1920x887,alignmentX\u003d0.0,alignmentY\u003d0.0,border\u003d,flags\u003d16777224,maximumSize\u003d,minimumSize\u003d,preferredSize\u003d]"
+ }
+ }
+ ],
+ "status": "PASSED",
+ "durationInNanos": 550600,
+ "depth": 0,
+ "parentFailed": false
+ },
+ {
+ "name": "set view",
+ "words": [
+ {
+ "value": "Then",
+ "isIntroWord": true
+ },
+ {
+ "value": "set view"
+ },
+ {
+ "value": "org.jhotdraw.draw.DefaultDrawingView[drawingCanvas,0,0,1920x887,alignmentX\u003d0.0,alignmentY\u003d0.0,border\u003d,flags\u003d16777224,maximumSize\u003d,minimumSize\u003d,preferredSize\u003d]",
+ "argumentInfo": {
+ "argumentName": "view",
+ "formattedValue": "org.jhotdraw.draw.DefaultDrawingView[drawingCanvas,0,0,1920x887,alignmentX\u003d0.0,alignmentY\u003d0.0,border\u003d,flags\u003d16777224,maximumSize\u003d,minimumSize\u003d,preferredSize\u003d]"
+ }
+ }
+ ],
+ "status": "PASSED",
+ "durationInNanos": 980200,
+ "depth": 0,
+ "parentFailed": false
+ },
+ {
+ "name": "the text tool is selected",
+ "words": [
+ {
+ "value": "Given",
+ "isIntroWord": true
+ },
+ {
+ "value": "the text tool is selected"
+ }
+ ],
+ "status": "PASSED",
+ "durationInNanos": 300273000,
+ "depth": 0,
+ "parentFailed": false
+ },
+ {
+ "name": "the user clicks on the canvas at",
+ "words": [
+ {
+ "value": "When",
+ "isIntroWord": true
+ },
+ {
+ "value": "the user clicks on the canvas at"
+ },
+ {
+ "value": "200",
+ "argumentInfo": {
+ "argumentName": "x",
+ "formattedValue": "200"
+ }
+ },
+ {
+ "value": "200",
+ "argumentInfo": {
+ "argumentName": "y",
+ "formattedValue": "200"
+ }
+ }
+ ],
+ "status": "PASSED",
+ "durationInNanos": 248783700,
+ "depth": 0,
+ "parentFailed": false
+ },
+ {
+ "name": "the user types",
+ "words": [
+ {
+ "value": "and",
+ "isIntroWord": true
+ },
+ {
+ "value": "the user types"
+ },
+ {
+ "value": "Hello Far World",
+ "argumentInfo": {
+ "argumentName": "text",
+ "formattedValue": "Hello Far World"
+ }
+ }
+ ],
+ "status": "PASSED",
+ "durationInNanos": 2611925500,
+ "depth": 0,
+ "parentFailed": false
+ },
+ {
+ "name": "the user finishes editing",
+ "words": [
+ {
+ "value": "and",
+ "isIntroWord": true
+ },
+ {
+ "value": "the user finishes editing"
+ }
+ ],
+ "status": "PASSED",
+ "durationInNanos": 249152600,
+ "depth": 0,
+ "parentFailed": false
+ },
+ {
+ "name": "the selection tool is selected",
+ "words": [
+ {
+ "value": "Given",
+ "isIntroWord": true
+ },
+ {
+ "value": "the selection tool is selected"
+ }
+ ],
+ "status": "PASSED",
+ "durationInNanos": 296281100,
+ "depth": 0,
+ "parentFailed": false
+ },
+ {
+ "name": "the user double clicks the figure at",
+ "words": [
+ {
+ "value": "When",
+ "isIntroWord": true
+ },
+ {
+ "value": "the user double clicks the figure at"
+ },
+ {
+ "value": "200",
+ "argumentInfo": {
+ "argumentName": "x",
+ "formattedValue": "200"
+ }
+ },
+ {
+ "value": "200",
+ "argumentInfo": {
+ "argumentName": "y",
+ "formattedValue": "200"
+ }
+ }
+ ],
+ "status": "PASSED",
+ "durationInNanos": 125254300,
+ "depth": 0,
+ "parentFailed": false
+ },
+ {
+ "name": "the figure should be in edit mode",
+ "words": [
+ {
+ "value": "Then",
+ "isIntroWord": true
+ },
+ {
+ "value": "the figure should be in edit mode"
+ }
+ ],
+ "status": "PASSED",
+ "durationInNanos": 62053600,
+ "depth": 0,
+ "parentFailed": false
+ }
+ ],
+ "explicitArguments": [],
+ "derivedArguments": [],
+ "status": "SUCCESS",
+ "durationInNanos": 4813757300
+ }
+ ],
+ "casesAsTable": false,
+ "durationInNanos": 4813757300
+ },
+ {
+ "className": "org.jhotdraw.samples.svg.TextToolScenarioTest",
+ "testMethodName": "text_figure_is_removed_if_empty_on_deselect",
+ "description": "text figure is removed if empty on deselect",
+ "tagIds": [],
+ "explicitParameters": [],
+ "derivedParameters": [],
+ "scenarioCases": [
+ {
+ "caseNr": 1,
+ "steps": [
+ {
+ "name": "set fixtures",
+ "words": [
+ {
+ "value": "Given",
+ "isIntroWord": true
+ },
+ {
+ "value": "set fixtures"
+ },
+ {
+ "value": "org.assertj.swing.fixture.FrameFixture@7f685c37",
+ "argumentInfo": {
+ "argumentName": "fixture",
+ "formattedValue": "org.assertj.swing.fixture.FrameFixture@7f685c37"
+ }
+ },
+ {
+ "value": "org.assertj.swing.core.BasicRobot@3eb3232b",
+ "argumentInfo": {
+ "argumentName": "robotInstance",
+ "formattedValue": "org.assertj.swing.core.BasicRobot@3eb3232b"
+ }
+ },
+ {
+ "value": "org.jhotdraw.draw.DefaultDrawingEditor@2929538b",
+ "argumentInfo": {
+ "argumentName": "drawingEditor",
+ "formattedValue": "org.jhotdraw.draw.DefaultDrawingEditor@2929538b"
+ }
+ },
+ {
+ "value": "org.jhotdraw.draw.DefaultDrawingView[drawingCanvas,0,0,1920x887,alignmentX\u003d0.0,alignmentY\u003d0.0,border\u003d,flags\u003d16777224,maximumSize\u003d,minimumSize\u003d,preferredSize\u003d]",
+ "argumentInfo": {
+ "argumentName": "drawingView",
+ "formattedValue": "org.jhotdraw.draw.DefaultDrawingView[drawingCanvas,0,0,1920x887,alignmentX\u003d0.0,alignmentY\u003d0.0,border\u003d,flags\u003d16777224,maximumSize\u003d,minimumSize\u003d,preferredSize\u003d]"
+ }
+ }
+ ],
+ "status": "PASSED",
+ "durationInNanos": 876700,
+ "depth": 0,
+ "parentFailed": false
+ },
+ {
+ "name": "set fixtures",
+ "words": [
+ {
+ "value": "When",
+ "isIntroWord": true
+ },
+ {
+ "value": "set fixtures"
+ },
+ {
+ "value": "org.assertj.swing.fixture.FrameFixture@7f685c37",
+ "argumentInfo": {
+ "argumentName": "fixture",
+ "formattedValue": "org.assertj.swing.fixture.FrameFixture@7f685c37"
+ }
+ },
+ {
+ "value": "org.assertj.swing.core.BasicRobot@3eb3232b",
+ "argumentInfo": {
+ "argumentName": "robotInstance",
+ "formattedValue": "org.assertj.swing.core.BasicRobot@3eb3232b"
+ }
+ },
+ {
+ "value": "org.jhotdraw.draw.DefaultDrawingEditor@2929538b",
+ "argumentInfo": {
+ "argumentName": "drawingEditor",
+ "formattedValue": "org.jhotdraw.draw.DefaultDrawingEditor@2929538b"
+ }
+ },
+ {
+ "value": "org.jhotdraw.draw.DefaultDrawingView[drawingCanvas,0,0,1920x887,alignmentX\u003d0.0,alignmentY\u003d0.0,border\u003d,flags\u003d16777224,maximumSize\u003d,minimumSize\u003d,preferredSize\u003d]",
+ "argumentInfo": {
+ "argumentName": "drawingView",
+ "formattedValue": "org.jhotdraw.draw.DefaultDrawingView[drawingCanvas,0,0,1920x887,alignmentX\u003d0.0,alignmentY\u003d0.0,border\u003d,flags\u003d16777224,maximumSize\u003d,minimumSize\u003d,preferredSize\u003d]"
+ }
+ }
+ ],
+ "status": "PASSED",
+ "durationInNanos": 527600,
+ "depth": 0,
+ "parentFailed": false
+ },
+ {
+ "name": "set view",
+ "words": [
+ {
+ "value": "When",
+ "isIntroWord": true
+ },
+ {
+ "value": "set view"
+ },
+ {
+ "value": "org.jhotdraw.draw.DefaultDrawingView[drawingCanvas,0,0,1920x887,alignmentX\u003d0.0,alignmentY\u003d0.0,border\u003d,flags\u003d16777224,maximumSize\u003d,minimumSize\u003d,preferredSize\u003d]",
+ "argumentInfo": {
+ "argumentName": "view",
+ "formattedValue": "org.jhotdraw.draw.DefaultDrawingView[drawingCanvas,0,0,1920x887,alignmentX\u003d0.0,alignmentY\u003d0.0,border\u003d,flags\u003d16777224,maximumSize\u003d,minimumSize\u003d,preferredSize\u003d]"
+ }
+ }
+ ],
+ "status": "PASSED",
+ "durationInNanos": 435300,
+ "depth": 0,
+ "parentFailed": false
+ },
+ {
+ "name": "set view",
+ "words": [
+ {
+ "value": "Then",
+ "isIntroWord": true
+ },
+ {
+ "value": "set view"
+ },
+ {
+ "value": "org.jhotdraw.draw.DefaultDrawingView[drawingCanvas,0,0,1920x887,alignmentX\u003d0.0,alignmentY\u003d0.0,border\u003d,flags\u003d16777224,maximumSize\u003d,minimumSize\u003d,preferredSize\u003d]",
+ "argumentInfo": {
+ "argumentName": "view",
+ "formattedValue": "org.jhotdraw.draw.DefaultDrawingView[drawingCanvas,0,0,1920x887,alignmentX\u003d0.0,alignmentY\u003d0.0,border\u003d,flags\u003d16777224,maximumSize\u003d,minimumSize\u003d,preferredSize\u003d]"
+ }
+ }
+ ],
+ "status": "PASSED",
+ "durationInNanos": 501100,
+ "depth": 0,
+ "parentFailed": false
+ },
+ {
+ "name": "the text tool is selected",
+ "words": [
+ {
+ "value": "Given",
+ "isIntroWord": true
+ },
+ {
+ "value": "the text tool is selected"
+ }
+ ],
+ "status": "PASSED",
+ "durationInNanos": 299522300,
+ "depth": 0,
+ "parentFailed": false
+ },
+ {
+ "name": "the user clicks on the canvas at",
+ "words": [
+ {
+ "value": "When",
+ "isIntroWord": true
+ },
+ {
+ "value": "the user clicks on the canvas at"
+ },
+ {
+ "value": "200",
+ "argumentInfo": {
+ "argumentName": "x",
+ "formattedValue": "200"
+ }
+ },
+ {
+ "value": "200",
+ "argumentInfo": {
+ "argumentName": "y",
+ "formattedValue": "200"
+ }
+ }
+ ],
+ "status": "PASSED",
+ "durationInNanos": 244351300,
+ "depth": 0,
+ "parentFailed": false
+ },
+ {
+ "name": "the user clears the text and deselects",
+ "words": [
+ {
+ "value": "and",
+ "isIntroWord": true
+ },
+ {
+ "value": "the user clears the text and deselects"
+ }
+ ],
+ "status": "PASSED",
+ "durationInNanos": 607333600,
+ "depth": 0,
+ "parentFailed": false
+ },
+ {
+ "name": "the canvas should be empty",
+ "words": [
+ {
+ "value": "Then",
+ "isIntroWord": true
+ },
+ {
+ "value": "the canvas should be empty"
+ }
+ ],
+ "status": "PASSED",
+ "durationInNanos": 193300,
+ "depth": 0,
+ "parentFailed": false
+ }
+ ],
+ "explicitArguments": [],
+ "derivedArguments": [],
+ "status": "SUCCESS",
+ "durationInNanos": 2079950300
+ }
+ ],
+ "casesAsTable": false,
+ "durationInNanos": 2079950300
+ }
+ ],
+ "tagMap": {}
+}
\ No newline at end of file
diff --git a/jhotdraw-samples/jhotdraw-samples-misc/pom.xml b/jhotdraw-samples/jhotdraw-samples-misc/pom.xml
index ca8104ee5..6d4cae29f 100644
--- a/jhotdraw-samples/jhotdraw-samples-misc/pom.xml
+++ b/jhotdraw-samples/jhotdraw-samples-misc/pom.xml
@@ -14,6 +14,13 @@
jhotdraw-core
${project.version}
+
+ org.jhotdraw
+ jhotdraw-core
+ ${project.version}
+ tests
+ test
+
org.devzendo
Quaqua
@@ -40,6 +47,25 @@
4.13.2
test
+
+ com.tngtech.jgiven
+ jgiven-junit
+ 1.3.1 test
+
+
+
+ org.assertj
+ assertj-core
+ 3.25.3
+ test
+
+
+
+ org.assertj
+ assertj-swing-junit
+ 3.17.1
+ test
+
diff --git a/jhotdraw-samples/jhotdraw-samples-misc/src/main/java/org/jhotdraw/samples/draw/DrawApplicationModel.java b/jhotdraw-samples/jhotdraw-samples-misc/src/main/java/org/jhotdraw/samples/draw/DrawApplicationModel.java
index ae9f128a2..45eeca61f 100644
--- a/jhotdraw-samples/jhotdraw-samples-misc/src/main/java/org/jhotdraw/samples/draw/DrawApplicationModel.java
+++ b/jhotdraw-samples/jhotdraw-samples-misc/src/main/java/org/jhotdraw/samples/draw/DrawApplicationModel.java
@@ -34,12 +34,7 @@
import org.jhotdraw.draw.decoration.ArrowTip;
import org.jhotdraw.draw.liner.CurvedLiner;
import org.jhotdraw.draw.liner.ElbowLiner;
-import org.jhotdraw.draw.tool.BezierTool;
-import org.jhotdraw.draw.tool.ConnectionTool;
-import org.jhotdraw.draw.tool.CreationTool;
-import org.jhotdraw.draw.tool.ImageTool;
-import org.jhotdraw.draw.tool.TextAreaCreationTool;
-import org.jhotdraw.draw.tool.TextCreationTool;
+import org.jhotdraw.draw.tool.*;
import org.jhotdraw.gui.JFileURIChooser;
import org.jhotdraw.gui.action.ButtonFactory;
import org.jhotdraw.util.*;
@@ -124,7 +119,7 @@ public void addDefaultCreationButtonsTo(JToolBar tb, final DrawingEditor editor,
ButtonFactory.addSelectionToolTo(tb, editor, drawingActions, selectionActions);
tb.addSeparator();
AbstractAttributedFigure af;
- CreationTool ct;
+ AbstractCreationTool ct;
ConnectionTool cnt;
ConnectionFigure lc;
ButtonFactory.addToolTo(tb, editor, new CreationTool(new RectangleFigure()), "edit.createRectangle", labels);
diff --git a/jhotdraw-samples/jhotdraw-samples-misc/src/main/java/org/jhotdraw/samples/draw/DrawingPanel.java b/jhotdraw-samples/jhotdraw-samples-misc/src/main/java/org/jhotdraw/samples/draw/DrawingPanel.java
index 418c02d46..ea9f83ad1 100644
--- a/jhotdraw-samples/jhotdraw-samples-misc/src/main/java/org/jhotdraw/samples/draw/DrawingPanel.java
+++ b/jhotdraw-samples/jhotdraw-samples-misc/src/main/java/org/jhotdraw/samples/draw/DrawingPanel.java
@@ -36,11 +36,7 @@
import org.jhotdraw.draw.decoration.ArrowTip;
import org.jhotdraw.draw.liner.CurvedLiner;
import org.jhotdraw.draw.liner.ElbowLiner;
-import org.jhotdraw.draw.tool.BezierTool;
-import org.jhotdraw.draw.tool.ConnectionTool;
-import org.jhotdraw.draw.tool.CreationTool;
-import org.jhotdraw.draw.tool.TextAreaCreationTool;
-import org.jhotdraw.draw.tool.TextCreationTool;
+import org.jhotdraw.draw.tool.*;
import org.jhotdraw.gui.JPopupButton;
import org.jhotdraw.gui.action.ButtonFactory;
import org.jhotdraw.undo.UndoRedoManager;
@@ -192,7 +188,7 @@ public void addDefaultCreationButtonsTo(JToolBar tb, final DrawingEditor editor,
ButtonFactory.addSelectionToolTo(tb, editor, drawingActions, selectionActions);
tb.addSeparator();
AbstractAttributedFigure af;
- CreationTool ct;
+ AbstractCreationTool ct;
ConnectionTool cnt;
ConnectionFigure lc;
ButtonFactory.addToolTo(tb, editor, new CreationTool(new RectangleFigure()), "edit.createRectangle", labels);
diff --git a/jhotdraw-samples/jhotdraw-samples-misc/src/main/java/org/jhotdraw/samples/svg/figures/SVGTextFigure.java b/jhotdraw-samples/jhotdraw-samples-misc/src/main/java/org/jhotdraw/samples/svg/figures/SVGTextFigure.java
index a96bb5211..465a9cba8 100644
--- a/jhotdraw-samples/jhotdraw-samples-misc/src/main/java/org/jhotdraw/samples/svg/figures/SVGTextFigure.java
+++ b/jhotdraw-samples/jhotdraw-samples-misc/src/main/java/org/jhotdraw/samples/svg/figures/SVGTextFigure.java
@@ -24,8 +24,8 @@
import org.jhotdraw.draw.handle.MoveHandle;
import org.jhotdraw.draw.handle.TransformHandleKit;
import org.jhotdraw.draw.locator.RelativeLocator;
+import org.jhotdraw.draw.tool.BaseTool;
import org.jhotdraw.draw.tool.TextEditingTool;
-import org.jhotdraw.draw.tool.Tool;
import org.jhotdraw.geom.Dimension2DDouble;
import org.jhotdraw.geom.Geom;
import org.jhotdraw.geom.Insets2D;
@@ -49,6 +49,7 @@ public class SVGTextFigure
extends SVGAttributedFigure
implements TextHolderFigure, SVGFigure {
+ private static final int MIN_COLUMN_COUNT = 4;
private static final long serialVersionUID = 1L;
protected Point2D.Double[] coordinates = new Point2D.Double[]{new Point2D.Double()};
protected double[] rotates = new double[]{0};
@@ -76,6 +77,8 @@ public SVGTextFigure(String text) {
// DRAWING
@Override
protected void drawText(java.awt.Graphics2D g) {
+ // SVGs have no concept of text per se, so it is being drawn in drawFill and drawStroke instead.
+ // This is probably a fat interface code smell, but fixing that hierarchy is out of scope.
}
@Override
@@ -117,13 +120,13 @@ public Rectangle2D.Double getBounds() {
cachedBounds = new Rectangle2D.Double();
cachedBounds.setRect(getTextShape().getBounds2D());
String text = getText();
- if (text == null || text.length() == 0) {
+ if (text == null || text.isEmpty()) {
text = " ";
}
FontRenderContext frc = getFontRenderContext();
- HashMap textAttributes = new HashMap();
+ HashMap textAttributes = new HashMap<>();
textAttributes.put(TextAttribute.FONT, getFont());
- if (get(FONT_UNDERLINE)) {
+ if (get(FONT_UNDERLINE) != null && get(FONT_UNDERLINE)) {
textAttributes.put(TextAttribute.UNDERLINE, TextAttribute.UNDERLINE_ON);
}
TextLayout textLayout = new TextLayout(text, textAttributes, frc);
@@ -182,13 +185,13 @@ public boolean contains(Point2D.Double p) {
private Shape getTextShape() {
if (cachedTextShape == null) {
String text = getText();
- if (text == null || text.length() == 0) {
+ if (text == null || text.isEmpty()) {
text = " ";
}
FontRenderContext frc = getFontRenderContext();
- HashMap textAttributes = new HashMap();
+ HashMap textAttributes = new HashMap<>();
textAttributes.put(TextAttribute.FONT, getFont());
- if (get(FONT_UNDERLINE)) {
+ if (get(FONT_UNDERLINE) != null && get(FONT_UNDERLINE)) {
textAttributes.put(TextAttribute.UNDERLINE, TextAttribute.UNDERLINE_ON);
}
TextLayout textLayout = new TextLayout(text, textAttributes, frc);
@@ -205,10 +208,6 @@ private Shape getTextShape() {
break;
}
tx.rotate(rotates[0]);
- /*
- if (get(TRANSFORM) != null) {
- tx.preConcatenate(get(TRANSFORM));
- }*/
cachedTextShape = tx.createTransformedShape(textLayout.getOutline(tx));
cachedTextShape = textLayout.getOutline(tx);
}
@@ -296,11 +295,11 @@ public String getText() {
@Override
public void set(AttributeKey key, T newValue) {
- if (key.equals(SVGAttributeKeys.TRANSFORM)
- || key.equals(SVGAttributeKeys.FONT_FACE)
- || key.equals(SVGAttributeKeys.FONT_BOLD)
- || key.equals(SVGAttributeKeys.FONT_ITALIC)
- || key.equals(SVGAttributeKeys.FONT_SIZE)) {
+ if (key.equals(AttributeKeys.TRANSFORM)
+ || key.equals(AttributeKeys.FONT_FACE)
+ || key.equals(AttributeKeys.FONT_BOLD)
+ || key.equals(AttributeKeys.FONT_ITALIC)
+ || key.equals(AttributeKeys.FONT_SIZE)) {
invalidate();
}
super.set(key, newValue);
@@ -325,30 +324,26 @@ public void setEditable(boolean b) {
@Override
public int getTextColumns() {
- //return (getText() == null) ? 4 : Math.min(getText().length(), 4);
- return 4;
+ return MIN_COLUMN_COUNT;
}
@Override
public Font getFont() {
- return SVGAttributeKeys.getFont(this);
+ return AttributeKeys.getFont(this);
}
@Override
public Color getTextColor() {
return get(FILL_COLOR);
- // return get(TEXT_COLOR);
}
@Override
public Color getFillColor() {
return get(FILL_COLOR) == null || get(FILL_COLOR).equals(Color.white) ? Color.black : Color.WHITE;
- // return get(FILL_COLOR);
}
@Override
public void setFontSize(float size) {
- // put(FONT_SIZE, new Double(size));
Point2D.Double p = new Point2D.Double(0, size);
AffineTransform tx = get(TRANSFORM);
if (tx != null) {
@@ -366,7 +361,6 @@ public void setFontSize(float size) {
@Override
public float getFontSize() {
- // return get(FONT_SIZE).floatValue();
Point2D.Double p = new Point2D.Double(0, get(FONT_SIZE));
AffineTransform tx = get(TRANSFORM);
if (tx != null) {
@@ -374,12 +368,7 @@ public float getFontSize() {
Point2D.Double p0 = new Point2D.Double(0, 0);
tx.transform(p0, p0);
p.y -= p0.y;
- /*
- try {
- tx.inverseTransform(p, p);
- } catch (NoninvertibleTransformException ex) {
- ex.printStackTrace();
- }*/
+
}
return (float) Math.abs(p.y);
}
@@ -402,24 +391,20 @@ public Dimension2DDouble getPreferredSize() {
@Override
public Collection createHandles(int detailLevel) {
- LinkedList handles = new LinkedList();
- switch (detailLevel % 2) {
- case -1: // Mouse hover handles
- handles.add(new BoundsOutlineHandle(this, false, true));
- break;
- case 0:
- handles.add(new BoundsOutlineHandle(this));
- handles.add(new MoveHandle(this, RelativeLocator.northWest()));
- handles.add(new MoveHandle(this, RelativeLocator.northEast()));
- handles.add(new MoveHandle(this, RelativeLocator.southWest()));
- handles.add(new MoveHandle(this, RelativeLocator.southEast()));
- handles.add(new FontSizeHandle(this));
- handles.add(new LinkHandle(this));
- break;
- case 1:
- TransformHandleKit.addTransformHandles(this, handles);
- break;
+ LinkedList handles = new LinkedList<>();
+ int parity = detailLevel % 2;
+ if (parity == -1) handles.add(new BoundsOutlineHandle(this, false, true)); // Adds mouse hover handles
+ if (parity == 1) TransformHandleKit.addTransformHandles(this, handles);
+ if (parity == 0) {
+ handles.add(new BoundsOutlineHandle(this));
+ handles.add(new MoveHandle(this, RelativeLocator.northWest()));
+ handles.add(new MoveHandle(this, RelativeLocator.northEast()));
+ handles.add(new MoveHandle(this, RelativeLocator.southWest()));
+ handles.add(new MoveHandle(this, RelativeLocator.southEast()));
+ handles.add(new FontSizeHandle(this));
+ handles.add(new LinkHandle(this));
}
+
return handles;
}
@@ -430,10 +415,9 @@ public Collection createHandles(int detailLevel) {
* Returns null, if no specialized tool is available.
*/
@Override
- public Tool getTool(Point2D.Double p) {
+ public BaseTool getTool(Point2D.Double p) {
if (isEditable() && contains(p)) {
- TextEditingTool tool = new TextEditingTool(this);
- return tool;
+ return new TextEditingTool(this);
}
return null;
}
@@ -461,7 +445,35 @@ public Insets2D.Double getInsets() {
return new Insets2D.Double();
}
+ public static SVGTextFigure createFrom(SVGTextFigure original) {
+ SVGTextFigure clone = new SVGTextFigure();
+
+ clone.setAttributes(original.getAttributes());
+
+ if (original.coordinates != null) {
+ clone.coordinates = Arrays.copyOf(original.coordinates, original.coordinates.length);
+ }
+
+ if (original.rotates != null) {
+ clone.rotates = Arrays.copyOf(original.rotates, original.rotates.length);
+ }
+
+ clone.cachedBounds = null;
+ clone.cachedDrawingArea = null;
+ clone.cachedTextShape = null;
+
+ return clone;
+ }
+
+ /**
+ * @deprecated Use {@link #createFrom(SVGTextFigure)} instead.
+ * This method is kept around for framework compatibility.
+ * */
+ // Using .clone is inherently flawed but unfortunately legacy concerns keep it around.
+ // I've deprecated it with reference to the copy factory above.
+ @Deprecated
@Override
+ @SuppressWarnings("java:S2975")
public SVGTextFigure clone() {
SVGTextFigure that = (SVGTextFigure) super.clone();
that.coordinates = new Point2D.Double[this.coordinates.length];
@@ -477,7 +489,7 @@ public SVGTextFigure clone() {
@Override
public boolean isEmpty() {
- return getText() == null || getText().length() == 0;
+ return getText() == null || getText().isEmpty();
}
@Override
diff --git a/jhotdraw-samples/jhotdraw-samples-misc/src/main/java/org/jhotdraw/samples/svg/gui/ToolsToolBar.java b/jhotdraw-samples/jhotdraw-samples-misc/src/main/java/org/jhotdraw/samples/svg/gui/ToolsToolBar.java
index e5ac32bb3..f104c0fe2 100644
--- a/jhotdraw-samples/jhotdraw-samples-misc/src/main/java/org/jhotdraw/samples/svg/gui/ToolsToolBar.java
+++ b/jhotdraw-samples/jhotdraw-samples-misc/src/main/java/org/jhotdraw/samples/svg/gui/ToolsToolBar.java
@@ -20,6 +20,7 @@
import org.jhotdraw.draw.DrawingEditor;
import org.jhotdraw.draw.DrawingView;
import org.jhotdraw.draw.action.*;
+import org.jhotdraw.draw.tool.AbstractCreationTool;
import org.jhotdraw.draw.tool.CreationTool;
import org.jhotdraw.draw.tool.TextAreaCreationTool;
import org.jhotdraw.draw.tool.TextCreationTool;
@@ -74,7 +75,7 @@ protected JComponent createDisclosedComponent(int state) {
p.setLayout(layout);
GridBagConstraints gbc;
AbstractButton btn;
- CreationTool creationTool;
+ AbstractCreationTool abstractCreationTool;
PathTool pathTool;
TextCreationTool textTool;
TextAreaCreationTool textAreaTool;
@@ -83,6 +84,8 @@ protected JComponent createDisclosedComponent(int state) {
btn = ButtonFactory.addSelectionToolTo(this, editor,
ButtonFactory.createDrawingActions(editor, disposables),
createSelectionActions(editor));
+ btn.setName("selectionToolButton");
+ btn.setToolTipText("Select Tool");
btn.setUI((PaletteButtonUI) PaletteButtonUI.createUI(btn));
btn.addMouseListener(new SelectionToolButtonHandler(editor));
gbc = new GridBagConstraints();
@@ -91,16 +94,16 @@ protected JComponent createDisclosedComponent(int state) {
p.add(btn, gbc);
labels.configureToolBarButton(btn, "selectionTool");
attributes = new HashMap, Object>();
- btn = ButtonFactory.addToolTo(this, editor, creationTool = new CreationTool(new SVGRectFigure(), attributes), "createRectangle", labels);
- creationTool.setToolDoneAfterCreation(false);
+ btn = ButtonFactory.addToolTo(this, editor, abstractCreationTool = new CreationTool(new SVGRectFigure(), attributes), "createRectangle", labels);
+ abstractCreationTool.setToolDoneAfterCreation(false);
btn.setUI((PaletteButtonUI) PaletteButtonUI.createUI(btn));
gbc = new GridBagConstraints();
gbc.gridx = 0;
gbc.gridy = 1;
gbc.insets = new Insets(3, 0, 0, 0);
p.add(btn, gbc);
- btn = ButtonFactory.addToolTo(this, editor, creationTool = new CreationTool(new SVGEllipseFigure(), attributes), "createEllipse", labels);
- creationTool.setToolDoneAfterCreation(false);
+ btn = ButtonFactory.addToolTo(this, editor, abstractCreationTool = new CreationTool(new SVGEllipseFigure(), attributes), "createEllipse", labels);
+ abstractCreationTool.setToolDoneAfterCreation(false);
btn.setUI((PaletteButtonUI) PaletteButtonUI.createUI(btn));
gbc = new GridBagConstraints();
gbc.gridx = 1;
@@ -118,8 +121,8 @@ protected JComponent createDisclosedComponent(int state) {
attributes = new HashMap, Object>();
attributes.put(AttributeKeys.FILL_COLOR, null);
attributes.put(PATH_CLOSED, false);
- btn = ButtonFactory.addToolTo(this, editor, creationTool = new CreationTool(new SVGPathFigure(), attributes), "createLine", labels);
- creationTool.setToolDoneAfterCreation(false);
+ btn = ButtonFactory.addToolTo(this, editor, abstractCreationTool = new CreationTool(new SVGPathFigure(), attributes), "createLine", labels);
+ abstractCreationTool.setToolDoneAfterCreation(false);
btn.setUI((PaletteButtonUI) PaletteButtonUI.createUI(btn));
gbc = new GridBagConstraints();
gbc.gridx = 1;
@@ -138,6 +141,8 @@ protected JComponent createDisclosedComponent(int state) {
attributes.put(AttributeKeys.FILL_COLOR, Color.black);
attributes.put(AttributeKeys.STROKE_COLOR, null);
btn = ButtonFactory.addToolTo(this, editor, textTool = new TextCreationTool(new SVGTextFigure(), attributes), "createText", labels);
+ btn.setName("textToolButton"); // For BDD
+ btn.setToolTipText("Text Tool");
textTool.setToolDoneAfterCreation(true);
btn.setUI((PaletteButtonUI) PaletteButtonUI.createUI(btn));
gbc = new GridBagConstraints();
diff --git a/jhotdraw-samples/jhotdraw-samples-misc/src/test/java/org/jhotdraw/samples/svg/TextToolScenarioTest.java b/jhotdraw-samples/jhotdraw-samples-misc/src/test/java/org/jhotdraw/samples/svg/TextToolScenarioTest.java
new file mode 100644
index 000000000..5242a6371
--- /dev/null
+++ b/jhotdraw-samples/jhotdraw-samples-misc/src/test/java/org/jhotdraw/samples/svg/TextToolScenarioTest.java
@@ -0,0 +1,127 @@
+package org.jhotdraw.samples.svg;
+
+import com.tngtech.jgiven.annotation.ScenarioState;
+import com.tngtech.jgiven.junit.ScenarioTest;
+import org.assertj.swing.core.BasicRobot;
+import org.assertj.swing.core.GenericTypeMatcher;
+import org.assertj.swing.core.Robot;
+import org.assertj.swing.edt.GuiActionRunner;
+import org.assertj.swing.finder.WindowFinder;
+import org.assertj.swing.fixture.FrameFixture;
+import org.assertj.swing.junit.testcase.AssertJSwingJUnitTestCase;
+import org.jhotdraw.draw.DrawingEditor;
+import org.jhotdraw.draw.DrawingView;
+import org.jhotdraw.draw.stages.GivenDrawingCanvas;
+import org.jhotdraw.draw.stages.ThenDrawingState;
+import org.jhotdraw.draw.tool.stages.WhenUserActs;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+import javax.swing.*;
+import java.awt.*;
+import java.awt.geom.Point2D;
+
+public class TextToolScenarioTest extends ScenarioTest {
+
+ private FrameFixture window;
+ private Robot robot;
+
+ private DrawingView view;
+
+ @Before
+ public void setup() {
+
+ robot = BasicRobot.robotWithNewAwtHierarchy();
+ GuiActionRunner.execute(() -> org.jhotdraw.samples.svg.Main.main(new String[0]));
+
+ window = WindowFinder.findFrame(new GenericTypeMatcher(JFrame.class) {
+ @Override
+ protected boolean isMatching(JFrame frame) {
+ return frame.isShowing() && frame.getTitle().toLowerCase().contains("svg");
+ }
+ }).withTimeout(5000).using(robot);
+
+ window.maximize();
+
+ this.view = (DrawingView) window.robot().finder().findByName("drawingCanvas");
+ DrawingEditor editor = view.getEditor();
+
+ given().setFixtures(window, robot, editor, view);
+ when().setFixtures(window, robot, editor, view);
+ when().setView(view);
+ then().setView(view);
+
+
+ }
+
+ @Test
+ public void user_can_create_and_type_text() {
+ given().the_text_tool_is_selected();
+
+ when().the_user_clicks_on_the_canvas_at(200,200)
+ .and().the_user_types("Hello Near World");
+ then().a_new_text_figure_should_exist()
+ .and().the_figure_should_be_selected();
+ }
+
+ @Test
+ public void text_figure_is_removed_if_empty_on_deselect() {
+ given().the_text_tool_is_selected();
+
+ when().the_user_clicks_on_the_canvas_at(200,200)
+ .and().the_user_clears_the_text_and_deselects();
+
+ then().the_canvas_should_be_empty();
+ }
+
+ @Test
+ public void clicking_existing_text_with_selection_tool_enters_edit_mode() {
+ // Create figure
+ given().the_text_tool_is_selected();
+ when().the_user_clicks_on_the_canvas_at(200,200)
+ .and().the_user_types("Hello Far World")
+ .and().the_user_finishes_editing();
+
+ given().the_selection_tool_is_selected();
+ when().the_user_double_clicks_the_figure_at(200,200);
+ then().the_figure_should_be_in_edit_mode();
+
+ }
+
+ @Test
+ public void figure_stays_at_original_location() {
+ int x = 200;
+ int y = 200;
+ given().the_text_tool_is_selected();
+ when().the_user_clicks_on_the_canvas_at(x,y)
+ .and().the_user_types("Red is defamation");
+
+ // Find where JHotDraw actually positioned it
+ Point2D.Double initialPosition = then().get_figure_anchor();
+
+ when().the_user_finishes_editing();
+
+ then().the_figure_should_exist_at( (int) initialPosition.x, (int) initialPosition.y);
+ }
+
+ @Test
+ public void pressing_escape_exits_edit_mode() {
+ given().the_text_tool_is_selected();
+ when().the_user_clicks_on_the_canvas_at(200,200)
+ .and().the_user_types("Pass Rot, Pop Green, Watch The Rots")
+ .and().the_user_presses_the_escape_key();
+
+ then().the_figure_should_not_be_in_edit_mode();
+
+ }
+
+ @After
+ public void tearDown() {
+ if (window != null) {
+ window.cleanUp();
+ }
+ }
+
+
+}