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 }