001 // License: GPL. For details, see LICENSE file.
002 package org.openstreetmap.josm.gui.mappaint.xml;
003
004 import java.awt.Color;
005 import java.util.Arrays;
006 import java.util.Collection;
007 import java.util.LinkedList;
008
009 import org.openstreetmap.josm.Main;
010 import org.openstreetmap.josm.gui.mappaint.MapPaintStyles.IconReference;
011 import org.openstreetmap.josm.gui.mappaint.Range;
012 import org.openstreetmap.josm.tools.ColorHelper;
013 import org.xml.sax.Attributes;
014 import org.xml.sax.helpers.DefaultHandler;
015
016 public class XmlStyleSourceHandler extends DefaultHandler
017 {
018 private boolean inDoc, inRule, inCondition, inLine, inLineMod, inIcon, inArea, inScaleMax, inScaleMin;
019 private boolean hadLine, hadLineMod, hadIcon, hadArea;
020 private RuleElem rule = new RuleElem();
021
022 XmlStyleSource style;
023
024 static class RuleElem {
025 XmlCondition cond = new XmlCondition();
026 Collection<XmlCondition> conditions;
027 double scaleMax;
028 double scaleMin;
029 LinePrototype line = new LinePrototype();
030 LinemodPrototype linemod = new LinemodPrototype();
031 AreaPrototype area = new AreaPrototype();
032 IconPrototype icon = new IconPrototype();
033 public void init()
034 {
035 conditions = null;
036 scaleMax = Double.POSITIVE_INFINITY;
037 scaleMin = 0;
038 line.init();
039 cond.init();
040 linemod.init();
041 area.init();
042 icon.init();
043 }
044 }
045
046 public XmlStyleSourceHandler(XmlStyleSource style) {
047 this.style = style;
048 inDoc=inRule=inCondition=inLine=inIcon=inArea=false;
049 rule.init();
050 }
051
052 Color convertColor(String colString)
053 {
054 int i = colString.indexOf("#");
055 Color ret;
056 if (i < 0) {
057 ret = Main.pref.getColor("mappaint."+style.getPrefName()+"."+colString, Color.red);
058 } else if(i == 0) {
059 ret = ColorHelper.html2color(colString);
060 } else {
061 ret = Main.pref.getColor("mappaint."+style.getPrefName()+"."+colString.substring(0,i),
062 ColorHelper.html2color(colString.substring(i)));
063 }
064 return ret;
065 }
066
067 @Override public void startDocument() {
068 inDoc = true;
069 }
070
071 @Override public void endDocument() {
072 inDoc = false;
073 }
074
075 private void error(String message) {
076 String warning = style.getDisplayString() + " (" + rule.cond.key + "=" + rule.cond.value + "): " + message;
077 System.err.println(warning);
078 style.logError(new Exception(warning));
079 }
080
081 private void startElementLine(String qName, Attributes atts, LinePrototype line) {
082 for (int count=0; count<atts.getLength(); count++)
083 {
084 if(atts.getQName(count).equals("width"))
085 {
086 String val = atts.getValue(count);
087 if (! (val.startsWith("+") || val.startsWith("-") || val.endsWith("%"))) {
088 line.setWidth(Integer.parseInt(val));
089 }
090 }
091 else if (atts.getQName(count).equals("colour")) {
092 line.color=convertColor(atts.getValue(count));
093 } else if (atts.getQName(count).equals("realwidth")) {
094 line.realWidth=Integer.parseInt(atts.getValue(count));
095 } else if (atts.getQName(count).equals("dashed")) {
096 Float[] dashed;
097 try {
098 String[] parts = atts.getValue(count).split(",");
099 dashed = new Float[parts.length];
100 for (int i = 0; i < parts.length; i++) {
101 dashed[i] = (float) Integer.parseInt(parts[i]);
102 }
103 } catch (NumberFormatException nfe) {
104 boolean isDashed = Boolean.parseBoolean(atts.getValue(count));
105 if(isDashed) {
106 dashed = new Float[]{9f};
107 } else {
108 dashed = null;
109 }
110 }
111 line.setDashed(dashed == null ? null : Arrays.asList(dashed));
112 } else if (atts.getQName(count).equals("dashedcolour")) {
113 line.dashedColor=convertColor(atts.getValue(count));
114 } else if(atts.getQName(count).equals("priority")) {
115 line.priority = Integer.parseInt(atts.getValue(count));
116 } else if (!(atts.getQName(count).equals("mode") && line instanceof LinemodPrototype)){
117 error("The element \"" + qName + "\" has unknown attribute \"" + atts.getQName(count) + "\"!");
118 }
119 }
120 }
121
122 private void startElementLinemod(String qName, Attributes atts, LinemodPrototype line) {
123 startElementLine(qName, atts, line);
124 for (int count=0; count<atts.getLength(); count++)
125 {
126 if(atts.getQName(count).equals("width"))
127 {
128 String val = atts.getValue(count);
129 if(val.startsWith("+"))
130 {
131 line.setWidth(Integer.parseInt(val.substring(1)));
132 line.widthMode = LinemodPrototype.WidthMode.OFFSET;
133 }
134 else if(val.startsWith("-"))
135 {
136 line.setWidth(Integer.parseInt(val));
137 line.widthMode = LinemodPrototype.WidthMode.OFFSET;
138 }
139 else if(val.endsWith("%"))
140 {
141 line.setWidth(Integer.parseInt(val.substring(0, val.length()-1)));
142 line.widthMode = LinemodPrototype.WidthMode.PERCENT;
143 } else {
144 line.setWidth(Integer.parseInt(val));
145 }
146 } else if(atts.getQName(count).equals("mode")) {
147 line.over = !atts.getValue(count).equals("under");
148 }
149 }
150 }
151
152 @Override public void startElement(String uri,String name, String qName, Attributes atts) {
153 if (inDoc==true)
154 {
155 if (qName.equals("rule")) {
156 inRule=true;
157 } else if (qName.equals("rules"))
158 {
159 if (style.name == null) {
160 style.name = atts.getValue("name");
161 }
162 if (style.title == null) {
163 style.title = atts.getValue("shortdescription");
164 }
165 if (style.icon == null) {
166 style.icon = atts.getValue("icon");
167 }
168 }
169 else if (qName.equals("scale_max")) {
170 inScaleMax = true;
171 } else if (qName.equals("scale_min")) {
172 inScaleMin = true;
173 } else if (qName.equals("condition") && inRule)
174 {
175 inCondition=true;
176 XmlCondition c = rule.cond;
177 if(c.key != null)
178 {
179 if(rule.conditions == null) {
180 rule.conditions = new LinkedList<XmlCondition>();
181 }
182 rule.conditions.add(new XmlCondition(rule.cond));
183 c = new XmlCondition();
184 rule.conditions.add(c);
185 }
186 for (int count=0; count<atts.getLength(); count++)
187 {
188 if(atts.getQName(count).equals("k")) {
189 c.key = atts.getValue(count);
190 } else if(atts.getQName(count).equals("v")) {
191 c.value = atts.getValue(count);
192 } else if(atts.getQName(count).equals("b")) {
193 c.boolValue = atts.getValue(count);
194 } else {
195 error("The element \"" + qName + "\" has unknown attribute \"" + atts.getQName(count) + "\"!");
196 }
197 }
198 if(c.key == null) {
199 error("The condition has no key!");
200 }
201 }
202 else if (qName.equals("line"))
203 {
204 hadLine = inLine = true;
205 startElementLine(qName, atts, rule.line);
206 }
207 else if (qName.equals("linemod"))
208 {
209 hadLineMod = inLineMod = true;
210 startElementLinemod(qName, atts, rule.linemod);
211 }
212 else if (qName.equals("icon"))
213 {
214 inIcon = true;
215 for (int count=0; count<atts.getLength(); count++)
216 {
217 if (atts.getQName(count).equals("src")) {
218 IconReference icon = new IconReference(atts.getValue(count), style);
219 hadIcon = (icon != null);
220 rule.icon.icon = icon;
221 } else if (atts.getQName(count).equals("annotate")) {
222 rule.icon.annotate = Boolean.parseBoolean (atts.getValue(count));
223 } else if(atts.getQName(count).equals("priority")) {
224 rule.icon.priority = Integer.parseInt(atts.getValue(count));
225 } else {
226 error("The element \"" + qName + "\" has unknown attribute \"" + atts.getQName(count) + "\"!");
227 }
228 }
229 }
230 else if (qName.equals("area"))
231 {
232 hadArea = inArea = true;
233 for (int count=0; count<atts.getLength(); count++)
234 {
235 if (atts.getQName(count).equals("colour")) {
236 rule.area.color=convertColor(atts.getValue(count));
237 } else if (atts.getQName(count).equals("closed")) {
238 rule.area.closed=Boolean.parseBoolean(atts.getValue(count));
239 } else if(atts.getQName(count).equals("priority")) {
240 rule.area.priority = Integer.parseInt(atts.getValue(count));
241 } else {
242 error("The element \"" + qName + "\" has unknown attribute \"" + atts.getQName(count) + "\"!");
243 }
244 }
245 } else {
246 error("The element \"" + qName + "\" is unknown!");
247 }
248 }
249 }
250
251 @Override public void endElement(String uri,String name, String qName)
252 {
253 if (inRule && qName.equals("rule"))
254 {
255 if(hadLine)
256 {
257 style.add(rule.cond, rule.conditions,
258 new LinePrototype(rule.line, new Range(rule.scaleMin, rule.scaleMax)));
259 }
260 if(hadLineMod)
261 {
262 style.add(rule.cond, rule.conditions,
263 new LinemodPrototype(rule.linemod, new Range(rule.scaleMin, rule.scaleMax)));
264 }
265 if(hadIcon)
266 {
267 style.add(rule.cond, rule.conditions,
268 new IconPrototype(rule.icon, new Range(rule.scaleMin, rule.scaleMax)));
269 }
270 if(hadArea)
271 {
272 style.add(rule.cond, rule.conditions,
273 new AreaPrototype(rule.area, new Range(rule.scaleMin, rule.scaleMax)));
274 }
275 inRule = false;
276 hadLine = hadLineMod = hadIcon = hadArea = false;
277 rule.init();
278 }
279 else if (inCondition && qName.equals("condition")) {
280 inCondition = false;
281 } else if (inLine && qName.equals("line")) {
282 inLine = false;
283 } else if (inLineMod && qName.equals("linemod")) {
284 inLineMod = false;
285 } else if (inIcon && qName.equals("icon")) {
286 inIcon = false;
287 } else if (inArea && qName.equals("area")) {
288 inArea = false;
289 } else if (qName.equals("scale_max")) {
290 inScaleMax = false;
291 } else if (qName.equals("scale_min")) {
292 inScaleMin = false;
293 }
294 }
295
296 @Override public void characters(char ch[], int start, int length)
297 {
298 if (inScaleMax == true) {
299 rule.scaleMax = Long.parseLong(new String(ch, start, length));
300 } else if (inScaleMin == true) {
301 rule.scaleMin = Long.parseLong(new String(ch, start, length));
302 }
303 }
304 }