001: /* ===========================================================
002: * JFreeChart : a free chart library for the Java(tm) platform
003: * ===========================================================
004: *
005: * (C) Copyright 2000-2007, by Object Refinery Limited and Contributors.
006: *
007: * Project Info: http://www.jfree.org/jfreechart/index.html
008: *
009: * This library is free software; you can redistribute it and/or modify it
010: * under the terms of the GNU Lesser General Public License as published by
011: * the Free Software Foundation; either version 2.1 of the License, or
012: * (at your option) any later version.
013: *
014: * This library is distributed in the hope that it will be useful, but
015: * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
016: * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
017: * License for more details.
018: *
019: * You should have received a copy of the GNU Lesser General Public
020: * License along with this library; if not, write to the Free Software
021: * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
022: * USA.
023: *
024: * [Java is a trademark or registered trademark of Sun Microsystems, Inc.
025: * in the United States and other countries.]
026: *
027: * ----------------
028: * ChartEntity.java
029: * ----------------
030: * (C) Copyright 2002-2007, by Object Refinery Limited and Contributors.
031: *
032: * Original Author: David Gilbert (for Object Refinery Limited);
033: * Contributor(s): Richard Atkinson;
034: * Xavier Poinsard;
035: * Robert Fuller;
036: *
037: * $Id: ChartEntity.java,v 1.8.2.2 2007/02/06 11:28:53 mungady Exp $
038: *
039: * Changes:
040: * --------
041: * 23-May-2002 : Version 1 (DG);
042: * 12-Jun-2002 : Added Javadoc comments (DG);
043: * 26-Jun-2002 : Added methods for image maps (DG);
044: * 05-Aug-2002 : Added constructor and accessors for URL support in image maps
045: * Added getImageMapAreaTag() - previously in subclasses (RA);
046: * 05-Sep-2002 : Added getImageMapAreaTag(boolean) to support OverLIB for
047: * tooltips http://www.bosrup.com/web/overlib (RA);
048: * 03-Oct-2002 : Fixed errors reported by Checkstyle (DG);
049: * 08-Oct-2002 : Changed getImageMapAreaTag to use title instead of alt
050: * attribute so HTML image maps now work in Mozilla and Opera as
051: * well as Internet Explorer (RA);
052: * 13-Mar-2003 : Change getImageMapAreaTag to only return a tag when there is a
053: * tooltip or URL, as suggested by Xavier Poinsard (see Feature
054: * Request 688079) (DG);
055: * 12-Aug-2003 : Added support for custom image maps using
056: * ToolTipTagFragmentGenerator and URLTagFragmentGenerator (RA);
057: * 02-Sep-2003 : Incorporated fix (791901) submitted by Robert Fuller (DG);
058: * 19-May-2004 : Added equals() method and implemented Cloneable and
059: * Serializable (DG);
060: * 29-Sep-2004 : Implemented PublicCloneable (DG);
061: * 13-Jan-2005 : Fixed for compliance with XHTML 1.0 (DG);
062: * 18-Apr-2005 : Use StringBuffer (DG);
063: * 20-Apr-2005 : Added toString() implementation (DG);
064: * ------------- JFREECHART 1.0.x ---------------------------------------------
065: * 06-Feb-2007 : API doc update (DG);
066: *
067: */
068:
069: package org.jfree.chart.entity;
070:
071: import java.awt.Shape;
072: import java.awt.geom.PathIterator;
073: import java.awt.geom.Rectangle2D;
074: import java.io.IOException;
075: import java.io.ObjectInputStream;
076: import java.io.ObjectOutputStream;
077: import java.io.Serializable;
078:
079: import org.jfree.chart.imagemap.ToolTipTagFragmentGenerator;
080: import org.jfree.chart.imagemap.URLTagFragmentGenerator;
081: import org.jfree.io.SerialUtilities;
082: import org.jfree.util.ObjectUtilities;
083: import org.jfree.util.PublicCloneable;
084:
085: /**
086: * A class that captures information about some component of a chart (a bar,
087: * line etc).
088: */
089: public class ChartEntity implements Cloneable, PublicCloneable,
090: Serializable {
091:
092: /** For serialization. */
093: private static final long serialVersionUID = -4445994133561919083L;
094:
095: /** The area occupied by the entity (in Java 2D space). */
096: private transient Shape area;
097:
098: /** The tool tip text for the entity. */
099: private String toolTipText;
100:
101: /** The URL text for the entity. */
102: private String urlText;
103:
104: /**
105: * Creates a new chart entity.
106: *
107: * @param area the area (<code>null</code> not permitted).
108: */
109: public ChartEntity(Shape area) {
110: // defer argument checks...
111: this (area, null);
112: }
113:
114: /**
115: * Creates a new chart entity.
116: *
117: * @param area the area (<code>null</code> not permitted).
118: * @param toolTipText the tool tip text (<code>null</code> permitted).
119: */
120: public ChartEntity(Shape area, String toolTipText) {
121: // defer argument checks...
122: this (area, toolTipText, null);
123: }
124:
125: /**
126: * Creates a new entity.
127: *
128: * @param area the area (<code>null</code> not permitted).
129: * @param toolTipText the tool tip text (<code>null</code> permitted).
130: * @param urlText the URL text for HTML image maps (<code>null</code>
131: * permitted).
132: */
133: public ChartEntity(Shape area, String toolTipText, String urlText) {
134: if (area == null) {
135: throw new IllegalArgumentException("Null 'area' argument.");
136: }
137: this .area = area;
138: this .toolTipText = toolTipText;
139: this .urlText = urlText;
140: }
141:
142: /**
143: * Returns the area occupied by the entity (in Java 2D space).
144: *
145: * @return The area (never <code>null</code>).
146: */
147: public Shape getArea() {
148: return this .area;
149: }
150:
151: /**
152: * Sets the area for the entity.
153: * <P>
154: * This class conveys information about chart entities back to a client.
155: * Setting this area doesn't change the entity (which has already been
156: * drawn).
157: *
158: * @param area the area (<code>null</code> not permitted).
159: */
160: public void setArea(Shape area) {
161: if (area == null) {
162: throw new IllegalArgumentException("Null 'area' argument.");
163: }
164: this .area = area;
165: }
166:
167: /**
168: * Returns the tool tip text for the entity.
169: *
170: * @return The tool tip text (possibly <code>null</code>).
171: */
172: public String getToolTipText() {
173: return this .toolTipText;
174: }
175:
176: /**
177: * Sets the tool tip text.
178: *
179: * @param text the text (<code>null</code> permitted).
180: */
181: public void setToolTipText(String text) {
182: this .toolTipText = text;
183: }
184:
185: /**
186: * Returns the URL text for the entity.
187: *
188: * @return The URL text (possibly <code>null</code>).
189: */
190: public String getURLText() {
191: return this .urlText;
192: }
193:
194: /**
195: * Sets the URL text.
196: *
197: * @param text the text (<code>null</code> permitted).
198: */
199: public void setURLText(String text) {
200: this .urlText = text;
201: }
202:
203: /**
204: * Returns a string describing the entity area. This string is intended
205: * for use in an AREA tag when generating an image map.
206: *
207: * @return The shape type (never <code>null</code>).
208: */
209: public String getShapeType() {
210: if (this .area instanceof Rectangle2D) {
211: return "rect";
212: } else {
213: return "poly";
214: }
215: }
216:
217: /**
218: * Returns the shape coordinates as a string.
219: *
220: * @return The shape coordinates (never <code>null</code>).
221: */
222: public String getShapeCoords() {
223: if (this .area instanceof Rectangle2D) {
224: return getRectCoords((Rectangle2D) this .area);
225: } else {
226: return getPolyCoords(this .area);
227: }
228: }
229:
230: /**
231: * Returns a string containing the coordinates (x1, y1, x2, y2) for a given
232: * rectangle. This string is intended for use in an image map.
233: *
234: * @param rectangle the rectangle (<code>null</code> not permitted).
235: *
236: * @return Upper left and lower right corner of a rectangle.
237: */
238: private String getRectCoords(Rectangle2D rectangle) {
239: if (rectangle == null) {
240: throw new IllegalArgumentException(
241: "Null 'rectangle' argument.");
242: }
243: int x1 = (int) rectangle.getX();
244: int y1 = (int) rectangle.getY();
245: int x2 = x1 + (int) rectangle.getWidth();
246: int y2 = y1 + (int) rectangle.getHeight();
247: // fix by rfuller
248: if (x2 == x1) {
249: x2++;
250: }
251: if (y2 == y1) {
252: y2++;
253: }
254: // end fix by rfuller
255: return x1 + "," + y1 + "," + x2 + "," + y2;
256: }
257:
258: /**
259: * Returns a string containing the coordinates for a given shape. This
260: * string is intended for use in an image map.
261: *
262: * @param shape the shape (<code>null</code> not permitted).
263: *
264: * @return The coordinates for a given shape as string.
265: */
266: private String getPolyCoords(Shape shape) {
267: if (shape == null) {
268: throw new IllegalArgumentException("Null 'shape' argument.");
269: }
270: StringBuffer result = new StringBuffer();
271: boolean first = true;
272: float[] coords = new float[6];
273: PathIterator pi = shape.getPathIterator(null, 1.0);
274: while (!pi.isDone()) {
275: pi.currentSegment(coords);
276: if (first) {
277: first = false;
278: result.append((int) coords[0]);
279: result.append(",").append((int) coords[1]);
280: } else {
281: result.append(",");
282: result.append((int) coords[0]);
283: result.append(",");
284: result.append((int) coords[1]);
285: }
286: pi.next();
287: }
288: return result.toString();
289: }
290:
291: /**
292: * Returns an HTML image map tag for this entity. The returned fragment
293: * should be <code>XHTML 1.0</code> compliant.
294: *
295: * @param toolTipTagFragmentGenerator a generator for the HTML fragment
296: * that will contain the tooltip text (<code>null</code> not permitted
297: * if this entity contains tooltip information).
298: * @param urlTagFragmentGenerator a generator for the HTML fragment that
299: * will contain the URL reference (<code>null</code> not permitted if
300: * this entity has a URL).
301: *
302: * @return The HTML tag.
303: */
304: public String getImageMapAreaTag(
305: ToolTipTagFragmentGenerator toolTipTagFragmentGenerator,
306: URLTagFragmentGenerator urlTagFragmentGenerator) {
307:
308: StringBuffer tag = new StringBuffer();
309: boolean hasURL = (this .urlText == null ? false : !this .urlText
310: .equals(""));
311: boolean hasToolTip = (this .toolTipText == null ? false
312: : !this .toolTipText.equals(""));
313: if (hasURL || hasToolTip) {
314: tag.append("<area shape=\"" + getShapeType() + "\""
315: + " coords=\"" + getShapeCoords() + "\"");
316: if (hasToolTip) {
317: tag.append(toolTipTagFragmentGenerator
318: .generateToolTipFragment(this .toolTipText));
319: }
320: if (hasURL) {
321: tag.append(urlTagFragmentGenerator
322: .generateURLFragment(this .urlText));
323: }
324: // if there is a tool tip, we expect it to generate the title and
325: // alt values, so we only add an empty alt if there is no tooltip
326: if (!hasToolTip) {
327: tag.append(" alt=\"\"");
328: }
329: tag.append("/>");
330: }
331: return tag.toString();
332: }
333:
334: /**
335: * Returns a string representation of the chart entity, useful for
336: * debugging.
337: *
338: * @return A string.
339: */
340: public String toString() {
341: StringBuffer buf = new StringBuffer("ChartEntity: ");
342: buf.append("tooltip = ");
343: buf.append(this .toolTipText);
344: return buf.toString();
345: }
346:
347: /**
348: * Tests the entity for equality with an arbitrary object.
349: *
350: * @param obj the object to test against (<code>null</code> permitted).
351: *
352: * @return A boolean.
353: */
354: public boolean equals(Object obj) {
355: if (obj == this ) {
356: return true;
357: }
358: if (obj instanceof ChartEntity) {
359: ChartEntity that = (ChartEntity) obj;
360: if (!this .area.equals(that.area)) {
361: return false;
362: }
363: if (!ObjectUtilities.equal(this .toolTipText,
364: that.toolTipText)) {
365: return false;
366: }
367: if (!ObjectUtilities.equal(this .urlText, that.urlText)) {
368: return false;
369: }
370: return true;
371: }
372: return false;
373: }
374:
375: /**
376: * Returns a clone of the entity.
377: *
378: * @return A clone.
379: *
380: * @throws CloneNotSupportedException if there is a problem cloning the
381: * entity.
382: */
383: public Object clone() throws CloneNotSupportedException {
384: return super .clone();
385: }
386:
387: /**
388: * Provides serialization support.
389: *
390: * @param stream the output stream.
391: *
392: * @throws IOException if there is an I/O error.
393: */
394: private void writeObject(ObjectOutputStream stream)
395: throws IOException {
396: stream.defaultWriteObject();
397: SerialUtilities.writeShape(this .area, stream);
398: }
399:
400: /**
401: * Provides serialization support.
402: *
403: * @param stream the input stream.
404: *
405: * @throws IOException if there is an I/O error.
406: * @throws ClassNotFoundException if there is a classpath problem.
407: */
408: private void readObject(ObjectInputStream stream)
409: throws IOException, ClassNotFoundException {
410: stream.defaultReadObject();
411: this.area = SerialUtilities.readShape(stream);
412: }
413:
414: }
|