001/* ===========================================================
002 * JFreeChart : a free chart library for the Java(tm) platform
003 * ===========================================================
004 *
005 * (C) Copyright 2000-2009, 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 * ImageMapUtilities.java
029 * ----------------------
030 * (C) Copyright 2004-2009, by Richard Atkinson and Contributors.
031 *
032 * Original Author:  Richard Atkinson;
033 * Contributor(s):   David Gilbert (for Object Refinery Limited);
034 *                   Fawad Halim - bug 2690293;
035 *
036 * Changes
037 * -------
038 * 02-Aug-2004 : Initial version (RA);
039 * 13-Jan-2005 : Renamed ImageMapUtilities (DG);
040 * 19-Jan-2005 : Reversed order of tags for chart entities to get correct
041 *               layering (DG);
042 * ------------- JFREECHART 1.0.x ---------------------------------------------
043 * 06-Feb-2006 : API doc updates (DG);
044 * 04-Dec-2007 : Added htmlEscape() method, and escape 'name' in
045 *               getImageMap() (DG);
046 * 19-Mar-2009 : Added javascriptEscape() method - see bug 2690293 by FH (DG);
047 * 25-Mar-2009 : Reimplemented javascriptEscape() (DG);
048 *
049 */
050
051package org.jfree.chart.imagemap;
052
053import java.io.IOException;
054import java.io.PrintWriter;
055
056import org.jfree.chart.ChartRenderingInfo;
057import org.jfree.chart.entity.ChartEntity;
058import org.jfree.chart.entity.EntityCollection;
059import org.jfree.util.StringUtils;
060
061/**
062 * Collection of utility methods related to producing image maps.
063 * Functionality was originally in {@link org.jfree.chart.ChartUtilities}.
064 */
065public class ImageMapUtilities {
066
067    /**
068     * Writes an image map to an output stream.
069     *
070     * @param writer  the writer (<code>null</code> not permitted).
071     * @param name  the map name (<code>null</code> not permitted).
072     * @param info  the chart rendering info (<code>null</code> not permitted).
073     *
074     * @throws java.io.IOException if there are any I/O errors.
075     */
076    public static void writeImageMap(PrintWriter writer, String name,
077            ChartRenderingInfo info) throws IOException {
078
079        // defer argument checking...
080        ImageMapUtilities.writeImageMap(writer, name, info,
081                new StandardToolTipTagFragmentGenerator(),
082                new StandardURLTagFragmentGenerator());
083
084    }
085
086    /**
087     * Writes an image map to an output stream.
088     *
089     * @param writer  the writer (<code>null</code> not permitted).
090     * @param name  the map name (<code>null</code> not permitted).
091     * @param info  the chart rendering info (<code>null</code> not permitted).
092     * @param useOverLibForToolTips  whether to use OverLIB for tooltips
093     *                               (http://www.bosrup.com/web/overlib/).
094     *
095     * @throws java.io.IOException if there are any I/O errors.
096     */
097    public static void writeImageMap(PrintWriter writer,
098            String name, ChartRenderingInfo info,
099            boolean useOverLibForToolTips) throws IOException {
100
101        ToolTipTagFragmentGenerator toolTipTagFragmentGenerator = null;
102        if (useOverLibForToolTips) {
103            toolTipTagFragmentGenerator
104                    = new OverLIBToolTipTagFragmentGenerator();
105        }
106        else {
107            toolTipTagFragmentGenerator
108                    = new StandardToolTipTagFragmentGenerator();
109        }
110        ImageMapUtilities.writeImageMap(writer, name, info,
111                toolTipTagFragmentGenerator,
112                new StandardURLTagFragmentGenerator());
113
114    }
115
116    /**
117     * Writes an image map to an output stream.
118     *
119     * @param writer  the writer (<code>null</code> not permitted).
120     * @param name  the map name (<code>null</code> not permitted).
121     * @param info  the chart rendering info (<code>null</code> not permitted).
122     * @param toolTipTagFragmentGenerator  a generator for the HTML fragment
123     *     that will contain the tooltip text (<code>null</code> not permitted
124     *     if <code>info</code> contains tooltip information).
125     * @param urlTagFragmentGenerator  a generator for the HTML fragment that
126     *     will contain the URL reference (<code>null</code> not permitted if
127     *     <code>info</code> contains URLs).
128     *
129     * @throws java.io.IOException if there are any I/O errors.
130     */
131    public static void writeImageMap(PrintWriter writer, String name,
132            ChartRenderingInfo info,
133            ToolTipTagFragmentGenerator toolTipTagFragmentGenerator,
134            URLTagFragmentGenerator urlTagFragmentGenerator)
135        throws IOException {
136
137        writer.println(ImageMapUtilities.getImageMap(name, info,
138                toolTipTagFragmentGenerator, urlTagFragmentGenerator));
139    }
140
141    /**
142     * Creates an image map element that complies with the XHTML 1.0
143     * specification.
144     *
145     * @param name  the map name (<code>null</code> not permitted).
146     * @param info  the chart rendering info (<code>null</code> not permitted).
147     *
148     * @return The map element.
149     */
150    public static String getImageMap(String name, ChartRenderingInfo info) {
151        return ImageMapUtilities.getImageMap(name, info,
152                new StandardToolTipTagFragmentGenerator(),
153                new StandardURLTagFragmentGenerator());
154    }
155
156    /**
157     * Creates an image map element that complies with the XHTML 1.0
158     * specification.
159     *
160     * @param name  the map name (<code>null</code> not permitted).
161     * @param info  the chart rendering info (<code>null</code> not permitted).
162     * @param toolTipTagFragmentGenerator  a generator for the HTML fragment
163     *     that will contain the tooltip text (<code>null</code> not permitted
164     *     if <code>info</code> contains tooltip information).
165     * @param urlTagFragmentGenerator  a generator for the HTML fragment that
166     *     will contain the URL reference (<code>null</code> not permitted if
167     *     <code>info</code> contains URLs).
168     *
169     * @return The map tag.
170     */
171    public static String getImageMap(String name, ChartRenderingInfo info,
172            ToolTipTagFragmentGenerator toolTipTagFragmentGenerator,
173            URLTagFragmentGenerator urlTagFragmentGenerator) {
174
175        StringBuffer sb = new StringBuffer();
176        sb.append("<map id=\"" + htmlEscape(name) + "\" name=\""
177                + htmlEscape(name) + "\">");
178        sb.append(StringUtils.getLineSeparator());
179        EntityCollection entities = info.getEntityCollection();
180        if (entities != null) {
181            int count = entities.getEntityCount();
182            for (int i = count - 1; i >= 0; i--) {
183                ChartEntity entity = entities.getEntity(i);
184                if (entity.getToolTipText() != null
185                        || entity.getURLText() != null) {
186                    String area = entity.getImageMapAreaTag(
187                            toolTipTagFragmentGenerator,
188                            urlTagFragmentGenerator);
189                    if (area.length() > 0) {
190                        sb.append(area);
191                        sb.append(StringUtils.getLineSeparator());
192                    }
193                }
194            }
195        }
196        sb.append("</map>");
197        return sb.toString();
198
199    }
200
201    /**
202     * Returns a string that is equivalent to the input string, but with
203     * special characters converted to HTML escape sequences.
204     *
205     * @param input  the string to escape (<code>null</code> not permitted).
206     *
207     * @return A string with characters escaped.
208     *
209     * @since 1.0.9
210     */
211    public static String htmlEscape(String input) {
212        if (input == null) {
213            throw new IllegalArgumentException("Null 'input' argument.");
214        }
215        StringBuffer result = new StringBuffer();
216        int length = input.length();
217        for (int i = 0; i < length; i++) {
218            char c = input.charAt(i);
219            if (c == '&') {
220                result.append("&amp;");
221            }
222            else if (c == '\"') {
223                result.append("&quot;");
224            }
225            else if (c == '<') {
226                result.append("&lt;");
227            }
228            else if (c == '>') {
229                result.append("&gt;");
230            }
231            else if (c == '\'') {
232                result.append("&#39;");
233            }
234            else if (c == '\\') {
235                result.append("&#092;");
236            }
237            else {
238                result.append(c);
239            }
240        }
241        return result.toString();
242    }
243
244    /**
245     * Returns a string that is equivalent to the input string, but with
246     * special characters converted to JavaScript escape sequences.
247     *
248     * @param input  the string to escape (<code>null</code> not permitted).
249     *
250     * @return A string with characters escaped.
251     *
252     * @since 1.0.13
253     */
254    public static String javascriptEscape(String input) {
255        if (input == null) {
256            throw new IllegalArgumentException("Null 'input' argument.");
257        }
258        StringBuffer result = new StringBuffer();
259        int length = input.length();
260        for (int i = 0; i < length; i++) {
261            char c = input.charAt(i);
262            if (c == '\"') {
263                result.append("\\\"");
264            }
265            else if (c == '\'') {
266                result.append("\\'");
267            }
268            else if (c == '\\') {
269                result.append("\\\\");
270            }
271            else {
272                result.append(c);
273            }
274        }
275        return result.toString();
276    }
277}