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}