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     */
045    package org.jfree.xml;
046    
047    import java.awt.BasicStroke;
048    import java.awt.Color;
049    import java.awt.Stroke;
050    import java.awt.geom.Rectangle2D;
051    import java.lang.reflect.Field;
052    
053    import org.xml.sax.Attributes;
054    import org.xml.sax.SAXException;
055    
056    /**
057     * Basic helper functions to ease up the process of parsing.
058     *
059     * @author Thomas Morgner
060     */
061    public 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    }