Ptidej-v5.2-master/PADL Serialiser DB4O Tests/rsc/JHotDraw v5.1/src/CH/ifa/draw/figures/PolyLineFigure.java
/*
 * @(#)PolyLineFigure.java 5.1
 *
 */

package CH.ifa.draw.figures;

import java.awt.Color;
import java.awt.Graphics;
import java.awt.Point;
import java.awt.Rectangle;
import java.io.IOException;
import java.util.Enumeration;
import java.util.Vector;

import CH.ifa.draw.framework.Connector;
import CH.ifa.draw.framework.Locator;
import CH.ifa.draw.standard.AbstractFigure;
import CH.ifa.draw.util.Geom;
import CH.ifa.draw.util.StorableInput;
import CH.ifa.draw.util.StorableOutput;

/**
 * A poly line figure consists of a list of points.
 * It has an optional line decoration at the start and end.
 *
 * @see LineDecoration
 */
public  class PolyLineFigure extends AbstractFigure {

	public final static int ARROW_TIP_NONE  = 0;
	public final static int ARROW_TIP_START = 1;
	public final static int ARROW_TIP_END   = 2;
	public final static int ARROW_TIP_BOTH  = 3;

	protected Vector              fPoints;
	protected LineDecoration      fStartDecoration = null;
	protected LineDecoration      fEndDecoration = null;
	protected Color               fFrameColor = Color.black;

	/*
	 * Serialization support.
	 */
	private static final long serialVersionUID = -7951352179906577773L;
	private int polyLineFigureSerializedDataVersion = 1;

	public PolyLineFigure() {
		fPoints = new Vector(4);
	}

	public PolyLineFigure(int size) {
		fPoints = new Vector(size);
	}

	public PolyLineFigure(int x, int y) {
	    fPoints = new Vector();
	    fPoints.addElement(new Point(x, y));
	}

	public Rectangle displayBox() {
		Enumeration k = points();
		Rectangle r = new Rectangle((Point) k.nextElement());

		while (k.hasMoreElements())
			r.add((Point) k.nextElement());

		return r;
	}

	public boolean isEmpty() {
		return (size().width < 3) && (size().height < 3);
	}

	public Vector handles() {
		Vector handles = new Vector(fPoints.size());
		for (int i = 0; i < fPoints.size(); i++)
			handles.addElement(new PolyLineHandle(this, locator(i), i));
		return handles;
	}

	public void basicDisplayBox(Point origin, Point corner) {
	}

	/**
	 * Adds a node to the list of points.
	 */
	public void addPoint(int x, int y) {
		fPoints.addElement(new Point(x, y));
		changed();
	}

	public Enumeration points() {
		return fPoints.elements();
	}

	public int pointCount() {
		return fPoints.size();
	}

	protected void basicMoveBy(int dx, int dy) {
		Enumeration k = fPoints.elements();
		while (k.hasMoreElements())
			((Point) k.nextElement()).translate(dx, dy);
	}

	/**
	 * Changes the position of a node.
	 */
	public void setPointAt(Point p, int i) {
		willChange();
		fPoints.setElementAt(p, i);
		changed();
	}

	/**
	 * Insert a node at the given point.
	 */
	public void insertPointAt(Point p, int i) {
		fPoints.insertElementAt(p, i);
		changed();
	}

	public void removePointAt(int i) {
		willChange();
		fPoints.removeElementAt(i);
		changed();
	}

	/**
	 * Splits the segment at the given point if a segment was hit.
	 * @return the index of the segment or -1 if no segment was hit.
	 */
	public int splitSegment(int x, int y) {
		int i = findSegment(x, y);
		if (i != -1)
			insertPointAt(new Point(x, y), i+1);
		return i+1;
	}

	public Point pointAt(int i) {
		return (Point)fPoints.elementAt(i);
	}

	/**
	 * Joins to segments into one if the given point hits a node
	 * of the polyline.
	 * @return true if the two segments were joined.
	 */
	public boolean joinSegments(int x, int y) {
		for (int i= 1; i < fPoints.size()-1; i++) {
			Point p = pointAt(i);
			if (Geom.length(x, y, p.x, p.y) < 3) {
				removePointAt(i);
				return true;
			}
		}
		return false;
	}

	public Connector connectorAt(int x, int y) {
		return new PolyLineConnector(this);
	}

	/**
	 * Sets the start decoration.
	 */
	public void setStartDecoration(LineDecoration l) {
		fStartDecoration = l;
	}

	/**
	 * Sets the end decoration.
	 */
	public void setEndDecoration(LineDecoration l) {
		fEndDecoration = l;
	}

	public void draw(Graphics g) {
		g.setColor(getFrameColor());
		Point p1, p2;
		for (int i = 0; i < fPoints.size()-1; i++) {
			p1 = (Point) fPoints.elementAt(i);
			p2 = (Point) fPoints.elementAt(i+1);
			g.drawLine(p1.x, p1.y, p2.x, p2.y);
		}
		decorate(g);
	}

	public boolean containsPoint(int x, int y) {
		Rectangle bounds = displayBox();
		bounds.grow(4,4);
		if (!bounds.contains(x, y))
			return false;

		Point p1, p2;
		for (int i = 0; i < fPoints.size()-1; i++) {
			p1 = (Point) fPoints.elementAt(i);
			p2 = (Point) fPoints.elementAt(i+1);
			if (Geom.lineContainsPoint(p1.x, p1.y, p2.x, p2.y, x, y))
				return true;
		}
		return false;
	}

	/**
	 * Gets the segment of the polyline that is hit by
	 * the given point.
	 * @return the index of the segment or -1 if no segment was hit.
	 */
	public int findSegment(int x, int y) {
		Point p1, p2;
		for (int i = 0; i < fPoints.size()-1; i++) {
			p1 = (Point) fPoints.elementAt(i);
			p2 = (Point) fPoints.elementAt(i+1);
			if (Geom.lineContainsPoint(p1.x, p1.y, p2.x, p2.y, x, y))
				return i;
		}
		return -1;
	}

	private void decorate(Graphics g) {
		if (fStartDecoration != null) {
			Point p1 = (Point)fPoints.elementAt(0);
			Point p2 = (Point)fPoints.elementAt(1);
			fStartDecoration.draw(g, p1.x, p1.y, p2.x, p2.y);
		}
		if (fEndDecoration != null) {
			Point p3 = (Point)fPoints.elementAt(fPoints.size()-2);
			Point p4 = (Point)fPoints.elementAt(fPoints.size()-1);
			fEndDecoration.draw(g, p4.x, p4.y, p3.x, p3.y);
		}
	}

	/**
	 * Gets the attribute with the given name.
	 * PolyLineFigure maps "ArrowMode"to a
	 * line decoration.
	 */
	public Object getAttribute(String name) {
		if (name.equals("FrameColor")) {
			return getFrameColor();
		}
		else if (name.equals("ArrowMode")) {
			int value = 0;
			if (fStartDecoration != null)
				value |= ARROW_TIP_START;
			if (fEndDecoration != null)
				value |= ARROW_TIP_END;
			return new Integer(value);
		}
		return super.getAttribute(name);
	}

	/**
	 * Sets the attribute with the given name.
	 * PolyLineFigure interprets "ArrowMode"to set
	 * the line decoration.
	 */
	public void setAttribute(String name, Object value) {
		if (name.equals("FrameColor")) {
			setFrameColor((Color)value);
			changed();
		}
		else if (name.equals("ArrowMode")) {
			Integer intObj = (Integer) value;
			if (intObj != null) {
				int decoration = intObj.intValue();
				if ((decoration & ARROW_TIP_START) != 0)
					fStartDecoration = new ArrowTip();
				else
					fStartDecoration = null;
				if ((decoration & ARROW_TIP_END) != 0)
					fEndDecoration = new ArrowTip();
				else
					fEndDecoration = null;
			}
			changed();
		}
		else
			super.setAttribute(name, value);
	}

	public void write(StorableOutput dw) {
		super.write(dw);
		dw.writeInt(fPoints.size());
		Enumeration k = fPoints.elements();
		while (k.hasMoreElements()) {
			Point p = (Point) k.nextElement();
			dw.writeInt(p.x);
			dw.writeInt(p.y);
		}
		dw.writeStorable(fStartDecoration);
		dw.writeStorable(fEndDecoration);
		dw.writeColor(fFrameColor);
	}

	public void read(StorableInput dr) throws IOException {
		super.read(dr);
		int size = dr.readInt();
		fPoints = new Vector(size);
		for (int i=0; i<size; i++) {
			int x = dr.readInt();
			int y = dr.readInt();
			fPoints.addElement(new Point(x,y));
		}
		fStartDecoration = (LineDecoration)dr.readStorable();
		fEndDecoration = (LineDecoration)dr.readStorable();
		fFrameColor = dr.readColor();
	}

	/**
	 * Creates a locator for the point with the given index.
	 */
	public static Locator locator(int pointIndex) {
		return new PolyLineLocator(pointIndex);
	}

	protected Color getFrameColor() {
		return fFrameColor;
	}

	protected void setFrameColor(Color c) {
		fFrameColor = c;
	}
}
