001/* ===========================================================
002 * JFreeChart : a free chart library for the Java(tm) platform
003 * ===========================================================
004 *
005 * (C) Copyright 2000-2013, 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 * [Oracle and Java are registered trademarks of Oracle and/or its affiliates. 
025 * Other names may be trademarks of their respective owners.]
026 *
027 * ----------------------
028 * ImageMapUtilities.java
029 * ----------------------
030 * (C) Copyright 2004-2013, 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 * 02-Jul-2013 : Use ParamChecks (DG);
049 *
050 */
051
052package org.jfree.chart.imagemap;
053
054import java.io.IOException;
055import java.io.PrintWriter;
056
057import org.jfree.chart.ChartRenderingInfo;
058import org.jfree.chart.entity.ChartEntity;
059import org.jfree.chart.entity.EntityCollection;
060import org.jfree.chart.util.ParamChecks;
061import org.jfree.util.StringUtils;
062
063/**
064 * Collection of utility methods related to producing image maps.
065 * Functionality was originally in {@link org.jfree.chart.ChartUtilities}.
066 */
067public class ImageMapUtilities {
068
069    /**
070     * Writes an image map to an output stream.
071     *
072     * @param writer  the writer (<code>null</code> not permitted).
073     * @param name  the map name (<code>null</code> not permitted).
074     * @param info  the chart rendering info (<code>null</code> not permitted).
075     *
076     * @throws java.io.IOException if there are any I/O errors.
077     */
078    public static void writeImageMap(PrintWriter writer, String name,
079            ChartRenderingInfo info) throws IOException {
080
081        // defer argument checking...
082        ImageMapUtilities.writeImageMap(writer, name, info,
083                new StandardToolTipTagFragmentGenerator(),
084                new StandardURLTagFragmentGenerator());
085
086    }
087
088    /**
089     * Writes an image map to an output stream.
090     *
091     * @param writer  the writer (<code>null</code> not permitted).
092     * @param name  the map name (<code>null</code> not permitted).
093     * @param info  the chart rendering info (<code>null</code> not permitted).
094     * @param useOverLibForToolTips  whether to use OverLIB for tooltips
095     *                               (http://www.bosrup.com/web/overlib/).
096     *
097     * @throws java.io.IOException if there are any I/O errors.
098     */
099    public static void writeImageMap(PrintWriter writer,
100            String name, ChartRenderingInfo info,
101            boolean useOverLibForToolTips) throws IOException {
102
103        ToolTipTagFragmentGenerator toolTipTagFragmentGenerator;
104        if (useOverLibForToolTips) {
105            toolTipTagFragmentGenerator
106                    = new OverLIBToolTipTagFragmentGenerator();
107        }
108        else {
109            toolTipTagFragmentGenerator
110                    = new StandardToolTipTagFragmentGenerator();
111        }
112        ImageMapUtilities.writeImageMap(writer, name, info,
113                toolTipTagFragmentGenerator,
114                new StandardURLTagFragmentGenerator());
115
116    }
117
118    /**
119     * Writes an image map to an output stream.
120     *
121     * @param writer  the writer (<code>null</code> not permitted).
122     * @param name  the map name (<code>null</code> not permitted).
123     * @param info  the chart rendering info (<code>null</code> not permitted).
124     * @param toolTipTagFragmentGenerator  a generator for the HTML fragment
125     *     that will contain the tooltip text (<code>null</code> not permitted
126     *     if <code>info</code> contains tooltip information).
127     * @param urlTagFragmentGenerator  a generator for the HTML fragment that
128     *     will contain the URL reference (<code>null</code> not permitted if
129     *     <code>info</code> contains URLs).
130     *
131     * @throws java.io.IOException if there are any I/O errors.
132     */
133    public static void writeImageMap(PrintWriter writer, String name,
134            ChartRenderingInfo info,
135            ToolTipTagFragmentGenerator toolTipTagFragmentGenerator,
136            URLTagFragmentGenerator urlTagFragmentGenerator)
137        throws IOException {
138
139        writer.println(ImageMapUtilities.getImageMap(name, info,
140                toolTipTagFragmentGenerator, urlTagFragmentGenerator));
141    }
142
143    /**
144     * Creates an image map element that complies with the XHTML 1.0
145     * specification.
146     *
147     * @param name  the map name (<code>null</code> not permitted).
148     * @param info  the chart rendering info (<code>null</code> not permitted).
149     *
150     * @return The map element.
151     */
152    public static String getImageMap(String name, ChartRenderingInfo info) {
153        return ImageMapUtilities.getImageMap(name, info,
154                new StandardToolTipTagFragmentGenerator(),
155                new StandardURLTagFragmentGenerator());
156    }
157
158    /**
159     * Creates an image map element that complies with the XHTML 1.0
160     * specification.
161     *
162     * @param name  the map name (<code>null</code> not permitted).
163     * @param info  the chart rendering info (<code>null</code> not permitted).
164     * @param toolTipTagFragmentGenerator  a generator for the HTML fragment
165     *     that will contain the tooltip text (<code>null</code> not permitted
166     *     if <code>info</code> contains tooltip information).
167     * @param urlTagFragmentGenerator  a generator for the HTML fragment that
168     *     will contain the URL reference (<code>null</code> not permitted if
169     *     <code>info</code> contains URLs).
170     *
171     * @return The map tag.
172     */
173    public static String getImageMap(String name, ChartRenderingInfo info,
174            ToolTipTagFragmentGenerator toolTipTagFragmentGenerator,
175            URLTagFragmentGenerator urlTagFragmentGenerator) {
176
177        StringBuilder sb = new StringBuilder();
178        sb.append("<map id=\"").append(htmlEscape(name));
179        sb.append("\" name=\"").append(htmlEscape(name)).append("\">");
180        sb.append(StringUtils.getLineSeparator());
181        EntityCollection entities = info.getEntityCollection();
182        if (entities != null) {
183            int count = entities.getEntityCount();
184            for (int i = count - 1; i >= 0; i--) {
185                ChartEntity entity = entities.getEntity(i);
186                if (entity.getToolTipText() != null
187                        || entity.getURLText() != null) {
188                    String area = entity.getImageMapAreaTag(
189                            toolTipTagFragmentGenerator,
190                            urlTagFragmentGenerator);
191                    if (area.length() > 0) {
192                        sb.append(area);
193                        sb.append(StringUtils.getLineSeparator());
194                    }
195                }
196            }
197        }
198        sb.append("</map>");
199        return sb.toString();
200
201    }
202
203    /**
204     * Returns a string that is equivalent to the input string, but with
205     * special characters converted to HTML escape sequences.
206     *
207     * @param input  the string to escape (<code>null</code> not permitted).
208     *
209     * @return A string with characters escaped.
210     *
211     * @since 1.0.9
212     */
213    public static String htmlEscape(String input) {
214        ParamChecks.nullNotPermitted(input, "input");
215        StringBuilder result = new StringBuilder();
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        ParamChecks.nullNotPermitted(input, "input");
256        StringBuilder result = new StringBuilder();
257        int length = input.length();
258        for (int i = 0; i < length; i++) {
259            char c = input.charAt(i);
260            if (c == '\"') {
261                result.append("\\\"");
262            }
263            else if (c == '\'') {
264                result.append("\\'");
265            }
266            else if (c == '\\') {
267                result.append("\\\\");
268            }
269            else {
270                result.append(c);
271            }
272        }
273        return result.toString();
274    }
275}