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