    001/* ========================================================================
    002 * JCommon : a free general purpose class library for the Java(tm) platform
    003 * ========================================================================
    004 *
    005 * (C) Copyright 2000-2005, by Object Refinery Limited and Contributors.
    006 *
    007 * Project Info:  http://www.jfree.org/jcommon/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 * ParserUtil.java
    029 * ---------------
    030 * (C)opyright 2002-2005, by Thomas Morgner and Contributors.
    031 *
    032 * Original Author:  Thomas Morgner (taquera@sherito.org);
    033 * Contributor(s):   David Gilbert (for Object Refinery Limited);
    034 *
    035 * $Id: ParserUtil.java,v 1.3 2005/10/18 13:25:44 mungady Exp $
    036 *
    037 * Changes
    038 * -------
    039 * 21-May-2002 : Contains utility functions to make parsing easier.
    040 * 10-Dec-2002 : Fixed issues reported by Checkstyle (DG);
    041 * 29-Apr-2003 : Distilled from the JFreeReport project and moved into JCommon;
    042 * 23-Sep-2003 : Minor Javadoc updates (DG);
    043 *
    044 */
    045package org.jfree.xml;
    046
    047import java.awt.BasicStroke;
    048import java.awt.Color;
    049import java.awt.Stroke;
    050import java.awt.geom.Rectangle2D;
    051import java.lang.reflect.Field;
    052
    053import org.xml.sax.Attributes;
    054import org.xml.sax.SAXException;
    055
    056/**
    057 * Basic helper functions to ease up the process of parsing.
    058 *
    059 * @author Thomas Morgner
    060 */
    061public class ParserUtil {
    062
    063    /**
    064     * Parses the string <code>text</code> into an int. If text is null or does not
    065     * contain a parsable value, the message given in <code>message</code> is used to
    066     * throw a SAXException.
    067     *
    068     * @param text  the text to parse.
    069     * @param message  the error message if parsing fails.
    070     *
    071     * @return the int value.
    072     *
    073     * @throws SAXException if there is a problem with the parsing.
    074     */
    075    public static int parseInt(final String text, final String message) throws SAXException {
    076        if (text == null) {
    077            throw new SAXException(message);
    078        }
    079
    080        try {
    081            return Integer.parseInt(text);
    082        }
    083        catch (NumberFormatException nfe) {
    084            throw new SAXException("NumberFormatError: " + message);
    085        }
    086    }
    087
    088    /**
    089     * Parses an integer.
    090     *
    091     * @param text  the text to parse.
    092     * @param defaultVal  the default value.
    093     *
    094     * @return the integer.
    095     */
    096    public static int parseInt(final String text, final int defaultVal) {
    097        if (text == null) {
    098            return defaultVal;
    099        }
    100
    101        try {
    102            return Integer.parseInt(text);
    103        }
    104        catch (NumberFormatException nfe) {
    105            return defaultVal;
    106        }
    107    }
    108
    109    /**
    110     * Parses the string <code>text</code> into an float. If text is null or does not
    111     * contain a parsable value, the message given in <code>message</code> is used to
    112     * throw a SAXException.
    113     *
    114     * @param text  the text to parse.
    115     * @param message  the error message if parsing fails.
    116     *
    117     * @return the float value.
    118     *
    119     * @throws SAXException if there is a problem with the parsing.
    120     */
    121    public static float parseFloat(final String text, final String message) throws SAXException {
    122        if (text == null) {
    123            throw new SAXException(message);
    124        }
    125        try {
    126            return Float.parseFloat(text);
    127        }
    128        catch (NumberFormatException nfe) {
    129            throw new SAXException("NumberFormatError: " + message);
    130        }
    131    }
    132
    133    /**
    134     * Parses the string <code>text</code> into an float. If text is null or does not
    135     * contain a parsable value, the message given in <code>message</code> is used to
    136     * throw a SAXException.
    137     *
    138     * @param text  the text to parse.
    139     * @param defaultVal the defaultValue returned if parsing fails.
    140     *
    141     * @return the float value.
    142     */
    143    public static float parseFloat(final String text, final float defaultVal) {
    144        if (text == null) {
    145            return defaultVal;
    146        }
    147        try {
    148            return Float.parseFloat(text);
    149        }
    150        catch (NumberFormatException nfe) {
    151            return defaultVal;
    152        }
    153    }
    154
    155    /**
    156     * Parses a boolean. If the string <code>text</code> contains the value of "true", the
    157     * true value is returned, else false is returned.
    158     *
    159     * @param text  the text to parse.
    160     * @param defaultVal  the default value.
    161     *
    162     * @return a boolean.
    163     */
    164    public static boolean parseBoolean(final String text, final boolean defaultVal) {
    165        if (text == null) {
    166            return defaultVal;
    167        }
    168        return text.equalsIgnoreCase("true");
    169    }
    170
    171    /**
    172     * Parses a string. If the <code>text</code> is null, defaultval is returned.
    173     *
    174     * @param text  the text to parse.
    175     * @param defaultVal  the default value.
    176     *
    177     * @return a string.
    178     */
    179    public static String parseString(final String text, final String defaultVal) {
    180        if (text == null) {
    181            return defaultVal;
    182        }
    183        return text;
    184    }
    185
    186    /**
    187     * Creates a basic stroke given the width contained as float in the given string.
    188     * If the string could not be parsed into a float, a basic stroke with the width of
    189     * 1 is returned.
    190     *
    191     * @param weight  a string containing a number (the stroke weight).
    192     *
    193     * @return the stroke.
    194     */
    195    public static Stroke parseStroke(final String weight) {
    196        try {
    197            if (weight != null) {
    198                final Float w = new Float(weight);
    199                return new BasicStroke(w.floatValue());
    200            }
    201        }
    202        catch (NumberFormatException nfe) {
    203            //Log.warn("Invalid weight for stroke", nfe);
    204        }
    205        return new BasicStroke(1);
    206    }
    207
    208    /**
    209     * Parses a color entry. If the entry is in hexadecimal or ocal notation, the color is
    210     * created using Color.decode(). If the string denotes a constant name of on of the color
    211     * constants defined in java.awt.Color, this constant is used.
    212     * <p>
    213     * As fallback the color black is returned if no color can be parsed.
    214     *
    215     * @param color  the color (as a string).
    216     *
    217     * @return the paint.
    218     */
    219    public static Color parseColor(final String color) {
    220        return parseColor(color, Color.black);
    221    }
    222
    223    /**
    224     * Parses a color entry. If the entry is in hexadecimal or octal notation, the color is
    225     * created using Color.decode(). If the string denotes a constant name of one of the color
    226     * constants defined in java.awt.Color, this constant is used.
    227     * <p>
    228     * As fallback the supplied default value is returned if no color can be parsed.
    229     *
    230     * @param color  the color (as a string).
    231     * @param defaultValue  the default value (returned if no color can be parsed).
    232     *
    233     * @return the paint.
    234     */
    235    public static Color parseColor(final String color, final Color defaultValue) {
    236        if (color == null) {
    237            return defaultValue;
    238        }
    239        try {
    240            // get color by hex or octal value
    241            return Color.decode(color);
    242        }
    243        catch (NumberFormatException nfe) {
    244            // if we can't decode lets try to get it by name
    245            try {
    246                // try to get a color by name using reflection
    247                // black is used for an instance and not for the color itselfs
    248                final Field f = Color.class.getField(color);
    249
    250                return (Color) f.get(null);
    251            }
    252            catch (Exception ce) {
    253                //Log.warn("No such Color : " + color);
    254                // if we can't get any color return black
    255                return defaultValue;
    256            }
    257        }
    258    }
    259
    260
    261    /**
    262     * Parses a position of an element. If a relative postion is given, the returnvalue
    263     * is a negative number between 0 and -100.
    264     *
    265     * @param value  the value.
    266     * @param exceptionMessage  the exception message.
    267     *
    268     * @return the float value.
    269     *
    270     * @throws SAXException if there is a problem parsing the string.
    271     */
    272    public static float parseRelativeFloat(final String value, final String exceptionMessage)
    273        throws SAXException {
    274        if (value == null) {
    275            throw new SAXException(exceptionMessage);
    276        }
    277        final String tvalue = value.trim();
    278        if (tvalue.endsWith("%")) {
    279            final String number = tvalue.substring(0, tvalue.indexOf("%"));
    280            final float f = parseFloat(number, exceptionMessage) * -1.0f;
    281            return f;
    282        }
    283        else {
    284            return parseFloat(tvalue, exceptionMessage);
    285        }
    286    }
    287
    288    /**
    289     * Parses an element position. The position is stored in the attributes "x", "y", "width" and
    290     * "height". The attributes are allowed to have relative notion.
    291     *
    292     * @param atts  the attributes.
    293     *
    294     * @return the element position.
    295     *
    296     * @throws SAXException if there is a problem getting the element position.
    297     */
    298    public static Rectangle2D getElementPosition(final Attributes atts) throws SAXException {
    299        final float x = ParserUtil.parseRelativeFloat(atts.getValue("x"),
    300            "Element x not specified");
    301        final float y = ParserUtil.parseRelativeFloat(atts.getValue("y"),
    302            "Element y not specified");
    303        final float w = ParserUtil.parseRelativeFloat(atts.getValue("width"),
    304            "Element width not specified");
    305        final float h = ParserUtil.parseRelativeFloat(atts.getValue("height"),
    306            "Element height not specified");
    307        final Rectangle2D.Float retval = new Rectangle2D.Float(x, y, w, h);
    308        return retval;
    309    }
    310
    311}