//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 java.net.URI; import java.util.LinkedList; import java.util.List; import net.sf.sdedit.diagram.Lifeline; import net.sf.sdedit.util.Direction; /** * A <tt>Note</tt> is a sequence element that looks like a piece of paper with * some text on it. It appears on the right of a lifeline. It can optionally be * connected to messages or points in lifelines by dotted lines. If a note is * labeled with a string starting with "link:" it represents a * hyperlink to another sequence diagram in another tab. * * @author Markus Strauch * */ public class Note extends SequenceElement { /** * The unique number of the note. */ private int number; /** * The distance between the text and the border of the note. */ private int padding; /** * The distance between the lifeline on the left of the note and the note. */ private int margin; /** * A list of points where dotted lines starting at the note are directed * onto. */ private List<Point> targets; /** * An array of the four points where the dotted lines may start. */ private Point [] anchors; /** * The lifeline on the left of the note. */ private Lifeline location; /** * Flag denoting if the note consumes its own vertical space. If this flag * is false, messages that do not concern the lifelines on the left and * on the right of the note can consume the space. */ private boolean consuming; /** * The file that is to opened when the note is clicked (may be <tt>null</tt>). */ private URI link; /** * Creates a new <tt>Note</tt>. * * @param location the lifeline on the left of the note * @param number the unique number of the note * @param text the multiline text that appears inside the note box * @param consuming flag denoting if the note consumes its own vertical * space */ public Note(Lifeline location, int number, String[] text, boolean consuming) { super(location.getDiagram(), location, location.getRightNeighbour(), text, Direction.RIGHT, 0); this.number = number; this.consuming = consuming; this.location = location; padding = configuration().getNotePadding(); margin = configuration().getNoteMargin(); int totalTextHeight = textHeight(); setHeight(margin * 2 + padding + totalTextHeight); setWidth(margin * 2 + padding * 2 + leftPadding() + rightPadding() + textWidth()); targets = new LinkedList<Point>(); } /** * Returns the flag denoting if the note consumes its own vertical space. If this flag * is false, messages that do not concern the lifelines on the left and * on the right of the note can consume the space. * * @return the flag denoting if this note consumes its own vertical space. */ public boolean isConsuming() { return consuming; } /** * Returns the unique number of the note. * * @return the unique number of the note. */ public int getNumber() { return number; } /** * Adds a point such that a dotted line from the note to the point appears * on the diagram. * * @param target a point such that a dotted line from the note to the point appears * on the diagram */ public void addTarget(Point target) { targets.add(target); } /** * Returns the lifeline to the left of the note. * * @return the lifeline to the left of the note */ public Lifeline getLocation() { return location; } /** * Sets the diagram file, represented as a <tt>URI</tt> that is to be opened * when the note is clicked. The <tt>URI</tt> will be resolved against the * location of the file of the diagram to which this note belongs. * * @param link the diagram file that is to be opened when the note is clicked */ public void setLink(URI link) { this.link = link; } /** * Returns the diagram file, represented as a <tt>URI</tt> that is to be opened * when the note is clicked. The <tt>URI</tt> will be resolved against the * location of the file of the diagram to which this note belongs. * * @return the diagram file, represented as a <tt>URI</tt> that is to be opened * when the note is clicked */ public URI getLink() { return link; } /** * Returns the distance to the power of 2 between two points * * @param p0 a point * @param p1 another point * @return the distance to the power of 2 between the points */ private int distance2(Point p0, Point p1) { int d0 = Math.abs(p0.x - p1.x); int d1 = Math.abs(p0.y - p1.y); return d0 * d0 + d1 * d1; } private Point findStart(Point anch) { Point a = null; int min = Integer.MAX_VALUE; for (int i = 0; i < 4; i++) { int d = distance2(anch, anchors[i]); if (d <= min) { a = anchors[i]; min = d; } } return a; } @Override public void computeLayoutInformation() { int left = getLeftEndpoint().getLeft() + getLeftEndpoint().getWidth(); setLeft(left); anchors = new Point[4]; anchors[0] = new Point(getLeft() + margin, getTop() + getHeight() / 2); anchors[1] = new Point(getLeft() + getWidth() / 2, getTop() + margin); anchors[2] = new Point(getLeft() + getWidth() / 2, getTop() + getHeight() - margin); anchors[3] = new Point(getLeft() + getWidth() - margin, getTop() + getHeight() / 2); } @Override public void draw(Graphics2D g2d) { g2d.setColor(Color.BLACK); g2d.setStroke(solid); int left = getLeft(); int cornerx = left + getWidth() - margin - padding; int cornery = getTop() + margin + padding; g2d.drawLine(left + margin, getTop() + margin, cornerx, getTop() + margin); g2d.drawLine(left + margin, getTop() + margin, left + margin, getTop() + getHeight() - margin); g2d.drawLine(left + margin, getTop() + getHeight() - margin, left + getWidth() - margin, getTop() + getHeight() - margin); g2d.drawLine(left + getWidth() - margin, getTop() + getHeight() - margin, left + getWidth() - margin, cornery); g2d.drawLine(cornerx, cornery, cornerx, getTop() + margin); g2d.drawLine(cornerx, cornery, left + getWidth() - margin, cornery); g2d.drawLine(cornerx, getTop() + margin, left + getWidth() - margin, cornery); drawMultilineString(g2d, left + margin + padding, getTop() + getHeight() - margin - padding, false, null); for (Point anchor : targets) { Point start = findStart(anchor); g2d.setStroke(dotted); g2d.drawLine(anchor.x, anchor.y, start.x, start.y); } } @Override public boolean intersects(java.awt.Rectangle rectangle) { if (targets.isEmpty()) { return super.intersects(rectangle); } int left = getLeft(), right = left + getWidth(), top = getTop(), bottom = top + getHeight(); for (Point a : targets) { left = Math.min(left, a.x); right = Math.max(right, a.x); top = Math.min(top, a.y); bottom = Math.max(bottom, a.y); } return rectangle.intersects(left - 10, top - 10, right - left + 20, bottom - top + 20); } }