// Copyright (c) 2006 - 2008, Markus Strauch.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// * Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
// THE POSSIBILITY OF SUCH DAMAGE.
package net.sf.sdedit.drawable;
import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.Point;
import net.sf.sdedit.config.Configuration;
import net.sf.sdedit.message.AnswerToSelf;
import net.sf.sdedit.message.Message;
import net.sf.sdedit.util.Direction;
public class LoopArrow extends Arrow
{
private boolean isAnswer;
private int xExtent;
private Drawable from;
private Drawable to;
private Point[] pts;
private Point textPosition;
/**
* Creates a new LoopArrow.
*
* @param msg
* a self-message or answer to self
* @param stroke
* the stroke to be used for drawing the arrow
* @param align
* Align.LEFT if the message is to be drawn on the left of a
* lifeline, otherwise Align.RIGHT
* @param y
* the vertical position where to start drawing
*/
public LoopArrow(Message msg, ArrowStroke stroke, Direction align, int y) {
super(msg, stroke, align, y);
init();
}
private void init() {
Message message = getMessage();
Configuration conf = message.getConfiguration();
xExtent = conf.getSelfMessageHorizontalSpace();
setWidth(diagram.messagePadding + xExtent + diagram.subLifelineWidth + textWidth());
isAnswer = message instanceof AnswerToSelf;
from = message.getCaller().getView();
to = message.getCallee().getView();
if (getAlign() == Direction.LEFT) {
// loop arrows on the left must have a left neighbour
setLeftEndpoint(message.getCallee().getLeftNeighbour().getView());
if (message.getCaller().getSideLevel() < message.getCallee()
.getSideLevel()) {
setRightEndpoint(message.getCaller().getView());
} else {
setRightEndpoint(message.getCallee().getView());
}
} else {
int p = message.getCallee().getPosition();
if (p < message.getDiagram().getNumberOfLifelines() - 1
&& message.getDiagram().getLifelineAt(p + 1).isAlive()) {
setRightEndpoint(message.getCallee().getRightNeighbour()
.getView());
} else {
setRightEndpoint(message.getDiagram().getPaintDevice()
.getRightBound());
}
if (message.getCaller().getSideLevel() < message.getCallee()
.getSideLevel()) {
setLeftEndpoint(message.getCaller().getView());
} else {
setLeftEndpoint(message.getCallee().getView());
}
}
}
@Override
public void draw(Graphics2D g) {
int t = getMessage().getData().getThread();
Color back = !configuration().isOpaqueMessageText() ||
t == -1 ? null : THREAD_COLORS[t];
drawMultilineString(g, textPosition.x, textPosition.y, isAnswer, back);
g.setColor(Color.BLACK);
overrideColor(g);
int sgn = getAlign() == Direction.RIGHT ? 1 : -1;
g.setStroke(getStroke() == ArrowStroke.SOLID ? solid : dashed);
g.drawLine(pts[0].x, pts[0].y, pts[1].x, pts[1].y);
g.drawLine(pts[1].x, pts[1].y, pts[2].x, pts[2].y);
g.drawLine(pts[2].x, pts[2].y, pts[3].x, pts[3].y);
drawArrowHead(g, pts[3].x, pts[3].y, sgn);
g.setStroke(solid);
}
public int getInnerHeight() {
return textHeight();
}
/**
* Returns an array of four points, representing the positions of the points
* that are connected by the lines of which the loop arrow is made up.
*
* @return an array of four points, representing the positions of the points
* that are connected by the lines of which the loop arrow is made
* up
*/
public Point[] getLinePoints() {
return pts;
}
public Point getAnchor () {
return pts[1];
}
/**
* Returns the position of the left bottom of the label of the loop
* arrow.
*
* @return the position of the left bottom of the label of the loop
* arrow
*/
public Point getTextPosition() {
return textPosition;
}
@Override
public void computeLayoutInformation() {
int y_to = getTop() + textHeight();
int y_from = getTop();
int x_from, x_to;
if (getAlign() == Direction.RIGHT) {
x_from = from.getLeft() + from.getWidth();
x_to = to.getLeft() + to.getWidth();
setLeft(Math.min(x_from, x_to));
} else {
x_from = from.getLeft();
x_to = to.getLeft();
setLeft(Math.min(x_from - getWidth(), x_to - getWidth()));
}
int outer_x = getAlign() == Direction.RIGHT ? Math.max(x_to + xExtent,
x_from + xExtent) : Math.min(x_to - xExtent, x_from - xExtent);
pts = new Point[4];
pts[0] = new Point(x_from, y_from);
pts[1] = new Point(outer_x, y_from);
pts[2] = new Point(outer_x, y_to);
pts[3] = new Point(x_to, y_to);
int textOffset = getAlign() == Direction.RIGHT ? diagram.messagePadding : -textWidth()
- diagram.messagePadding;
int textY = isAnswer ? y_to : y_from + textHeight();
textPosition = new Point(outer_x + textOffset, textY);
}
}