001 /*
002 * StyleAttribute.java
003 *
004 *
005 * The Salamander Project - 2D and 3D graphics libraries in Java
006 * Copyright (C) 2004 Mark McKay
007 *
008 * This library is free software; you can redistribute it and/or
009 * modify it under the terms of the GNU Lesser General Public
010 * License as published by the Free Software Foundation; either
011 * version 2.1 of the License, or (at your option) any later version.
012 *
013 * This library is distributed in the hope that it will be useful,
014 * but WITHOUT ANY WARRANTY; without even the implied warranty of
015 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
016 * Lesser General Public License for more details.
017 *
018 * You should have received a copy of the GNU Lesser General Public
019 * License along with this library; if not, write to the Free Software
020 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
021 *
022 * Mark McKay can be contacted at mark@kitfox.com. Salamander and other
023 * projects can be found at http://www.kitfox.com
024 *
025 * Created on January 27, 2004, 2:53 PM
026 */
027
028 package com.kitfox.svg.xml;
029
030 import java.awt.*;
031 import java.net.*;
032 import java.io.*;
033 import java.util.regex.*;
034
035 /**
036 * @author Mark McKay
037 * @author <a href="mailto:mark@kitfox.com">Mark McKay</a>
038 */
039 public class StyleAttribute implements Serializable
040 {
041 public static final long serialVersionUID = 0;
042
043 static final Matcher matchUrl = Pattern.compile("\\s*url\\((.*)\\)\\s*").matcher("");
044 static final Matcher matchFpNumUnits = Pattern.compile("\\s*([-+]?((\\d*\\.\\d+)|(\\d+))([-+]?[eE]\\d+)?)\\s*(px|cm|mm|in|pc|pt|em|ex)\\s*").matcher("");
045
046 String name;
047 String stringValue;
048
049 boolean colorCompatable = false;
050 boolean urlCompatable = false;
051
052 /** Creates a new instance of StyleAttribute */
053 public StyleAttribute()
054 {
055 this(null, null);
056 }
057
058 public StyleAttribute(String name)
059 {
060 this.name = name;
061 stringValue = null;
062 }
063
064 public StyleAttribute(String name, String stringValue)
065 {
066 this.name = name;
067 this.stringValue = stringValue;
068 }
069
070 public String getName() { return name; }
071 public StyleAttribute setName(String name) { this.name = name; return this; }
072
073 public String getStringValue() { return stringValue; }
074
075 public String[] getStringList()
076 {
077 return XMLParseUtil.parseStringList(stringValue);
078 }
079
080 public void setStringValue(String value)
081 {
082 stringValue = value;
083 }
084
085 public boolean getBooleanValue() {
086 return stringValue.toLowerCase().equals("true");
087 }
088
089 public int getIntValue() {
090 return XMLParseUtil.findInt(stringValue);
091 }
092
093 public int[] getIntList() {
094 return XMLParseUtil.parseIntList(stringValue);
095 }
096
097 public double getDoubleValue() {
098 return XMLParseUtil.findDouble(stringValue);
099 }
100
101 public double[] getDoubleList() {
102 return XMLParseUtil.parseDoubleList(stringValue);
103 }
104
105 public float getFloatValue() {
106 return XMLParseUtil.findFloat(stringValue);
107 }
108
109 public float[] getFloatList() {
110 return XMLParseUtil.parseFloatList(stringValue);
111 }
112
113 public float getRatioValue() {
114 return (float)XMLParseUtil.parseRatio(stringValue);
115 // try { return Float.parseFloat(stringValue); }
116 // catch (Exception e) {}
117 // return 0f;
118 }
119
120 public String getUnits() {
121 matchFpNumUnits.reset(stringValue);
122 if (!matchFpNumUnits.matches()) return null;
123 return matchFpNumUnits.group(6);
124 }
125
126 public NumberWithUnits getNumberWithUnits() {
127 return XMLParseUtil.parseNumberWithUnits(stringValue);
128 }
129
130 public float getFloatValueWithUnits()
131 {
132 NumberWithUnits number = getNumberWithUnits();
133 return convertUnitsToPixels(number.getUnits(), number.getValue());
134 }
135
136 static public float convertUnitsToPixels(int unitType, float value)
137 {
138 if (unitType == NumberWithUnits.UT_UNITLESS || unitType == NumberWithUnits.UT_PERCENT)
139 {
140 return value;
141 }
142
143 float pixPerInch;
144 try
145 {
146 pixPerInch = (float)Toolkit.getDefaultToolkit().getScreenResolution();
147 }
148 catch (HeadlessException ex)
149 {
150 //default to 72 dpi
151 pixPerInch = 72;
152 }
153 final float inchesPerCm = .3936f;
154
155 switch (unitType)
156 {
157 case NumberWithUnits.UT_IN:
158 return value * pixPerInch;
159 case NumberWithUnits.UT_CM:
160 return value * inchesPerCm * pixPerInch;
161 case NumberWithUnits.UT_MM:
162 return value * .1f * inchesPerCm * pixPerInch;
163 case NumberWithUnits.UT_PT:
164 return value * (1f / 72f) * pixPerInch;
165 case NumberWithUnits.UT_PC:
166 return value * (1f / 6f) * pixPerInch;
167 }
168
169 return value;
170 }
171
172 public Color getColorValue()
173 {
174 return ColorTable.parseColor(stringValue);
175 }
176
177 public String parseURLFn()
178 {
179 matchUrl.reset(stringValue);
180 if (!matchUrl.matches()) return null;
181 return matchUrl.group(1);
182 }
183
184 public URL getURLValue(URL docRoot)
185 {
186 String fragment = parseURLFn();
187 if (fragment == null) return null;
188 try {
189 return new URL(docRoot, fragment);
190 }
191 catch (Exception e)
192 {
193 e.printStackTrace();
194 return null;
195 }
196 }
197
198 public URL getURLValue(URI docRoot)
199 {
200 String fragment = parseURLFn();
201 if (fragment == null) return null;
202 try {
203 URI ref = docRoot.resolve(fragment);
204 return ref.toURL();
205 }
206 catch (Exception e)
207 {
208 e.printStackTrace();
209 return null;
210 }
211 }
212
213 public URI getURIValue()
214 {
215 return getURIValue(null);
216 }
217
218 /**
219 * Parse this sytle attribute as a URL and return it in URI form resolved
220 * against the passed base.
221 *
222 * @param base - URI to resolve against. If null, will return value without
223 * attempting to resolve it.
224 */
225 public URI getURIValue(URI base)
226 {
227 try {
228 String fragment = parseURLFn();
229 if (fragment == null) fragment = stringValue.replaceAll("\\s+", "");
230 if (fragment == null) return null;
231
232 //======================
233 //This gets around a bug in the 1.5.0 JDK
234 if (Pattern.matches("[a-zA-Z]:!\\\\.*", fragment))
235 {
236 File file = new File(fragment);
237 return file.toURI();
238 }
239 //======================
240
241 //[scheme:]scheme-specific-part[#fragment]
242
243 URI uriFrag = new URI(fragment);
244 if (uriFrag.isAbsolute())
245 {
246 //Has scheme
247 return uriFrag;
248 }
249
250 if (base == null) return uriFrag;
251
252 URI relBase = new URI(null, base.getSchemeSpecificPart(), null);
253 URI relUri;
254 if (relBase.isOpaque())
255 {
256 relUri = new URI(null, base.getSchemeSpecificPart(), uriFrag.getFragment());
257 }
258 else
259 {
260 relUri = relBase.resolve(uriFrag);
261 }
262 return new URI(base.getScheme() + ":" + relUri);
263 }
264 catch (Exception e)
265 {
266 e.printStackTrace();
267 return null;
268 }
269 }
270
271 public static void main(String[] args)
272 {
273 try
274 {
275 URI uri = new URI("jar:http://www.kitfox.com/jackal/jackal.jar!/res/doc/about.svg");
276 uri = uri.resolve("#myFragment");
277
278 System.err.println(uri.toString());
279
280 uri = new URI("http://www.kitfox.com/jackal/jackal.html");
281 uri = uri.resolve("#myFragment");
282
283 System.err.println(uri.toString());
284 }
285 catch (Exception e)
286 {
287 e.printStackTrace();
288 }
289 }
290 }