rendertheme: merge AttributeMatcher into Rule
- allow to match actual key-value-pairs. previously value matcher just checked *any* value not the one that matched key. See PositiveRuleKV/MultiKV
This commit is contained in:
parent
a3251a4aa6
commit
211ba90108
@ -1,45 +0,0 @@
|
||||
/*
|
||||
* Copyright 2010, 2011, 2012 mapsforge.org
|
||||
* Copyright 2013 Hannes Janetzek
|
||||
*
|
||||
* This file is part of the OpenScienceMap project (http://www.opensciencemap.org).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify it under the
|
||||
* terms of the GNU Lesser General Public License as published by the Free Software
|
||||
* Foundation, either version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
|
||||
* PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License along with
|
||||
* this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.oscim.theme.rule;
|
||||
|
||||
import org.oscim.core.Tag;
|
||||
|
||||
final class AnyMatcher implements AttributeMatcher {
|
||||
private static final AnyMatcher INSTANCE = new AnyMatcher();
|
||||
|
||||
static AnyMatcher getInstance() {
|
||||
return INSTANCE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Private constructor to prevent instantiation from other classes.
|
||||
*/
|
||||
private AnyMatcher() {
|
||||
// do nothing
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCoveredBy(AttributeMatcher attributeMatcher) {
|
||||
return attributeMatcher == this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean matches(Tag[] tags) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@ -1,26 +0,0 @@
|
||||
/*
|
||||
* Copyright 2010, 2011, 2012 mapsforge.org
|
||||
* Copyright 2013 Hannes Janetzek
|
||||
*
|
||||
* This file is part of the OpenScienceMap project (http://www.opensciencemap.org).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify it under the
|
||||
* terms of the GNU Lesser General Public License as published by the Free Software
|
||||
* Foundation, either version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
|
||||
* PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License along with
|
||||
* this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.oscim.theme.rule;
|
||||
|
||||
import org.oscim.core.Tag;
|
||||
|
||||
interface AttributeMatcher {
|
||||
boolean isCoveredBy(AttributeMatcher attributeMatcher);
|
||||
|
||||
boolean matches(Tag[] tags);
|
||||
}
|
||||
@ -1,57 +0,0 @@
|
||||
/*
|
||||
* Copyright 2010, 2011, 2012 mapsforge.org
|
||||
* Copyright 2013 Hannes Janetzek
|
||||
*
|
||||
* This file is part of the OpenScienceMap project (http://www.opensciencemap.org).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify it under the
|
||||
* terms of the GNU Lesser General Public License as published by the Free Software
|
||||
* Foundation, either version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
|
||||
* PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License along with
|
||||
* this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.oscim.theme.rule;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.oscim.core.Tag;
|
||||
|
||||
class MultiKeyMatcher implements AttributeMatcher {
|
||||
private final String[] mKeys;
|
||||
|
||||
MultiKeyMatcher(List<String> keys) {
|
||||
mKeys = new String[keys.size()];
|
||||
for (int i = 0, n = mKeys.length; i < n; ++i) {
|
||||
mKeys[i] = keys.get(i).intern();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCoveredBy(AttributeMatcher attributeMatcher) {
|
||||
if (attributeMatcher == this) {
|
||||
return true;
|
||||
}
|
||||
|
||||
Tag[] tags = new Tag[mKeys.length];
|
||||
int i = 0;
|
||||
for (String key : mKeys) {
|
||||
tags[i++] = new Tag(key, null);
|
||||
}
|
||||
return attributeMatcher.matches(tags);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean matches(Tag[] tags) {
|
||||
for (Tag tag : tags)
|
||||
for (String key : mKeys)
|
||||
if (key == tag.key)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@ -1,57 +0,0 @@
|
||||
/*
|
||||
* Copyright 2010, 2011, 2012 mapsforge.org
|
||||
* Copyright 2013 Hannes Janetzek
|
||||
*
|
||||
* This file is part of the OpenScienceMap project (http://www.opensciencemap.org).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify it under the
|
||||
* terms of the GNU Lesser General Public License as published by the Free Software
|
||||
* Foundation, either version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
|
||||
* PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License along with
|
||||
* this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.oscim.theme.rule;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.oscim.core.Tag;
|
||||
|
||||
class MultiValueMatcher implements AttributeMatcher {
|
||||
private final String[] mValues;
|
||||
|
||||
MultiValueMatcher(List<String> values) {
|
||||
mValues = new String[values.size()];
|
||||
for (int i = 0, n = mValues.length; i < n; ++i) {
|
||||
mValues[i] = values.get(i).intern();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCoveredBy(AttributeMatcher attributeMatcher) {
|
||||
if (attributeMatcher == this) {
|
||||
return true;
|
||||
}
|
||||
Tag[] tags = new Tag[mValues.length];
|
||||
|
||||
int i = 0;
|
||||
for (String val : mValues) {
|
||||
tags[i++] = new Tag(null, val);
|
||||
}
|
||||
return attributeMatcher.matches(tags);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean matches(Tag[] tags) {
|
||||
for (Tag tag : tags)
|
||||
for (String val : mValues)
|
||||
if (val == tag.value)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@ -1,78 +0,0 @@
|
||||
/*
|
||||
* Copyright 2010, 2011, 2012 mapsforge.org
|
||||
* Copyright 2013 Hannes Janetzek
|
||||
*
|
||||
* This file is part of the OpenScienceMap project (http://www.opensciencemap.org).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify it under the
|
||||
* terms of the GNU Lesser General Public License as published by the Free Software
|
||||
* Foundation, either version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
|
||||
* PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License along with
|
||||
* this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.oscim.theme.rule;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.oscim.core.Tag;
|
||||
|
||||
class NegativeMatcher implements AttributeMatcher {
|
||||
private final String[] mKeyList;
|
||||
private final String[] mValueList;
|
||||
|
||||
// (-) 'exclusive negation' matches when either KEY is not present
|
||||
// or KEY is present and any VALUE is NOT present
|
||||
//
|
||||
// (\) 'except negation' matches when KEY is present
|
||||
// none items of VALUE is present (TODO).
|
||||
// (can be emulated by <m k="a"><m k=a v="-|b|c">...</m></m>)
|
||||
//
|
||||
// (~) 'non-exclusive negation' matches when either KEY is not present
|
||||
// or KEY is present and any VALUE is present
|
||||
//
|
||||
private final boolean mExclusive;
|
||||
|
||||
NegativeMatcher(List<String> keyList, List<String> valueList, boolean exclusive) {
|
||||
mKeyList = new String[keyList.size()];
|
||||
for (int i = 0; i < mKeyList.length; i++)
|
||||
mKeyList[i] = keyList.get(i).intern();
|
||||
|
||||
mValueList = new String[valueList.size()];
|
||||
for (int i = 0; i < mValueList.length; i++)
|
||||
mValueList[i] = valueList.get(i).intern();
|
||||
|
||||
mExclusive = exclusive;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCoveredBy(AttributeMatcher attributeMatcher) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean matches(Tag[] tags) {
|
||||
if (keyListDoesNotContainKeys(tags))
|
||||
return true;
|
||||
|
||||
for (Tag tag : tags)
|
||||
for (String value : mValueList)
|
||||
if (value == tag.value)
|
||||
return !mExclusive;
|
||||
|
||||
return mExclusive;
|
||||
}
|
||||
|
||||
private boolean keyListDoesNotContainKeys(Tag[] tags) {
|
||||
for (Tag tag : tags)
|
||||
for (String key : mKeyList)
|
||||
if (key == tag.key)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@ -18,20 +18,61 @@
|
||||
package org.oscim.theme.rule;
|
||||
|
||||
import org.oscim.core.Tag;
|
||||
import org.oscim.theme.rule.RuleBuilder.RuleType;
|
||||
import org.oscim.theme.styles.RenderStyle;
|
||||
|
||||
class NegativeRule extends Rule {
|
||||
final AttributeMatcher mAttributeMatcher;
|
||||
|
||||
NegativeRule(int element, int zoom, int selector, AttributeMatcher attributeMatcher,
|
||||
public final String[] keys;
|
||||
public final String[] values;
|
||||
|
||||
/* (-) 'exclusive negation' matches when either KEY is not present
|
||||
* or KEY is present and any VALUE is NOT present
|
||||
*
|
||||
* (\) 'except negation' matches when KEY is present
|
||||
* none items of VALUE is present (TODO).
|
||||
* (can be emulated by <m k="a"><m k=a v="-|b|c">...</m></m>)
|
||||
*
|
||||
* (~) 'non-exclusive negation' matches when either KEY is not present
|
||||
* or KEY is present and any VALUE is present */
|
||||
|
||||
public final boolean exclusive;
|
||||
|
||||
NegativeRule(RuleType type, int element, int zoom, int selector,
|
||||
String[] keys, String[] values,
|
||||
Rule[] subRules, RenderStyle[] styles) {
|
||||
super(element, zoom, selector, subRules, styles);
|
||||
|
||||
mAttributeMatcher = attributeMatcher;
|
||||
for (int i = 0; i < keys.length; i++)
|
||||
keys[i] = keys[i].intern();
|
||||
|
||||
for (int i = 0; i < values.length; i++)
|
||||
values[i] = values[i].intern();
|
||||
|
||||
this.keys = keys;
|
||||
this.values = values;
|
||||
this.exclusive = type == RuleType.EXCLUDE;
|
||||
}
|
||||
|
||||
@Override
|
||||
boolean matchesTags(Tag[] tags) {
|
||||
return mAttributeMatcher.matches(tags);
|
||||
public boolean matchesTags(Tag[] tags) {
|
||||
if (keyListDoesNotContainKeys(tags))
|
||||
return true;
|
||||
|
||||
for (Tag tag : tags)
|
||||
for (String value : values)
|
||||
if (value == tag.value)
|
||||
return !exclusive;
|
||||
|
||||
return exclusive;
|
||||
}
|
||||
|
||||
private boolean keyListDoesNotContainKeys(Tag[] tags) {
|
||||
for (Tag tag : tags)
|
||||
for (String key : keys)
|
||||
if (key == tag.key)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,5 +1,4 @@
|
||||
/*
|
||||
* Copyright 2010, 2011, 2012 mapsforge.org
|
||||
* Copyright 2013 Hannes Janetzek
|
||||
*
|
||||
* This file is part of the OpenScienceMap project (http://www.opensciencemap.org).
|
||||
@ -20,28 +19,149 @@ package org.oscim.theme.rule;
|
||||
import org.oscim.core.Tag;
|
||||
import org.oscim.theme.styles.RenderStyle;
|
||||
|
||||
class PositiveRule extends Rule {
|
||||
final AttributeMatcher mKeyMatcher;
|
||||
final AttributeMatcher mValueMatcher;
|
||||
class PositiveRule {
|
||||
|
||||
PositiveRule(int element, int zoom, int selector, AttributeMatcher keyMatcher,
|
||||
AttributeMatcher valueMatcher, Rule[] subRules, RenderStyle[] styles) {
|
||||
super(element, zoom, selector, subRules, styles);
|
||||
static class PositiveRuleK extends Rule {
|
||||
private final String mKey;
|
||||
|
||||
if (keyMatcher instanceof AnyMatcher)
|
||||
mKeyMatcher = null;
|
||||
else
|
||||
mKeyMatcher = keyMatcher;
|
||||
PositiveRuleK(int element, int zoom, int selector, String key,
|
||||
Rule[] subRules, RenderStyle[] styles) {
|
||||
|
||||
if (valueMatcher instanceof AnyMatcher)
|
||||
mValueMatcher = null;
|
||||
else
|
||||
mValueMatcher = valueMatcher;
|
||||
super(element, zoom, selector, subRules, styles);
|
||||
mKey = key;
|
||||
}
|
||||
|
||||
@Override
|
||||
boolean matchesTags(Tag[] tags) {
|
||||
for (Tag tag : tags)
|
||||
if (mKey == tag.key)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
boolean matchesTags(Tag[] tags) {
|
||||
return (mKeyMatcher == null || mKeyMatcher.matches(tags))
|
||||
&& (mValueMatcher == null || mValueMatcher.matches(tags));
|
||||
static class PositiveRuleV extends Rule {
|
||||
private final String mValue;
|
||||
|
||||
PositiveRuleV(int element, int zoom, int selector, String value,
|
||||
Rule[] subRules, RenderStyle[] styles) {
|
||||
|
||||
super(element, zoom, selector, subRules, styles);
|
||||
mValue = value;
|
||||
}
|
||||
|
||||
@Override
|
||||
boolean matchesTags(Tag[] tags) {
|
||||
for (Tag tag : tags)
|
||||
if (mValue == tag.value)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
static class PositiveRuleKV extends Rule {
|
||||
private final String mKey;
|
||||
private final String mValue;
|
||||
|
||||
PositiveRuleKV(int element, int zoom, int selector, String key, String value,
|
||||
Rule[] subRules, RenderStyle[] styles) {
|
||||
|
||||
super(element, zoom, selector, subRules, styles);
|
||||
mKey = key;
|
||||
mValue = value;
|
||||
}
|
||||
|
||||
@Override
|
||||
boolean matchesTags(Tag[] tags) {
|
||||
for (Tag tag : tags)
|
||||
if (mKey == tag.key)
|
||||
return (mValue == tag.value);
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
static class PositiveRuleMultiKV extends Rule {
|
||||
private final String mKeys[];
|
||||
private final String mValues[];
|
||||
|
||||
PositiveRuleMultiKV(int element, int zoom, int selector, String keys[], String values[],
|
||||
Rule[] subRules, RenderStyle[] styles) {
|
||||
|
||||
super(element, zoom, selector, subRules, styles);
|
||||
if (keys.length == 0) {
|
||||
mKeys = null;
|
||||
} else {
|
||||
for (int i = 0; i < keys.length; i++)
|
||||
keys[i] = keys[i].intern();
|
||||
mKeys = keys;
|
||||
}
|
||||
|
||||
if (values.length == 0) {
|
||||
mValues = null;
|
||||
} else {
|
||||
for (int i = 0; i < values.length; i++)
|
||||
values[i] = values[i].intern();
|
||||
mValues = values;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
boolean matchesTags(Tag[] tags) {
|
||||
if (mKeys == null) {
|
||||
for (Tag tag : tags) {
|
||||
for (String value : mValues) {
|
||||
if (value == tag.value)
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
for (Tag tag : tags)
|
||||
for (String key : mKeys) {
|
||||
if (key == tag.key) {
|
||||
if (mValues == null)
|
||||
return true;
|
||||
|
||||
for (String value : mValues) {
|
||||
if (value == tag.value)
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public static Rule create(int element, int zoom, int selector,
|
||||
String[] keys, String values[], Rule[] subRules, RenderStyle[] styles) {
|
||||
int numKeys = keys.length;
|
||||
int numVals = values.length;
|
||||
|
||||
if (numKeys == 0 && numVals == 0)
|
||||
return new Rule(element, zoom, selector, subRules, styles);
|
||||
|
||||
for (int i = 0; i < numVals; i++)
|
||||
values[i] = values[i].intern();
|
||||
|
||||
for (int i = 0; i < numKeys; i++)
|
||||
keys[i] = keys[i].intern();
|
||||
|
||||
if (numKeys == 1 && numKeys == 0) {
|
||||
return new PositiveRuleK(element, zoom, selector, keys[0], subRules, styles);
|
||||
}
|
||||
|
||||
if (numKeys == 0 && numVals == 1) {
|
||||
return new PositiveRuleV(element, zoom, selector, values[0], subRules, styles);
|
||||
}
|
||||
|
||||
if (numKeys == 1 && numVals == 1)
|
||||
return new PositiveRuleKV(element, zoom, selector, keys[0], values[0], subRules, styles);
|
||||
|
||||
return new PositiveRuleMultiKV(element, zoom, selector, keys, values, subRules, styles);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@ -21,7 +21,7 @@ import java.util.List;
|
||||
import org.oscim.core.Tag;
|
||||
import org.oscim.theme.styles.RenderStyle;
|
||||
|
||||
public abstract class Rule {
|
||||
public class Rule {
|
||||
public final static RenderStyle[] EMPTY_STYLE = new RenderStyle[0];
|
||||
public final static Rule[] EMPTY_RULES = new Rule[0];
|
||||
|
||||
@ -44,7 +44,9 @@ public abstract class Rule {
|
||||
selectWhenMatched = (selector & Selector.WHEN_MATCHED) != 0;
|
||||
}
|
||||
|
||||
abstract boolean matchesTags(Tag[] tags);
|
||||
boolean matchesTags(Tag[] tags) {
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean matchElement(int type, Tag[] tags, int zoomLevel, List<RenderStyle> result) {
|
||||
|
||||
|
||||
@ -1,139 +1,104 @@
|
||||
package org.oscim.theme.rule;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Stack;
|
||||
|
||||
import org.oscim.theme.IRenderTheme.ThemeException;
|
||||
import org.oscim.theme.XmlThemeBuilder;
|
||||
import org.oscim.theme.styles.RenderStyle;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.xml.sax.Attributes;
|
||||
|
||||
public class RuleBuilder {
|
||||
boolean positiveRule;
|
||||
final static Logger log = LoggerFactory.getLogger(RuleBuilder.class);
|
||||
|
||||
private final static String[] EMPTY_KV = {};
|
||||
|
||||
public enum RuleType {
|
||||
POSITIVE,
|
||||
NEGATIVE,
|
||||
EXCLUDE
|
||||
}
|
||||
|
||||
int zoom;
|
||||
int element;
|
||||
int selector;
|
||||
RuleType type;
|
||||
|
||||
AttributeMatcher keyMatcher;
|
||||
AttributeMatcher valueMatcher;
|
||||
String keys[];
|
||||
String values[];
|
||||
|
||||
ArrayList<RenderStyle> renderStyles = new ArrayList<RenderStyle>(4);
|
||||
ArrayList<RuleBuilder> subRules = new ArrayList<RuleBuilder>(4);
|
||||
|
||||
private static final Map<List<String>, AttributeMatcher> MATCHERS_CACHE_KEY =
|
||||
new HashMap<List<String>, AttributeMatcher>();
|
||||
private static final Map<List<String>, AttributeMatcher> MATCHERS_CACHE_VALUE =
|
||||
new HashMap<List<String>, AttributeMatcher>();
|
||||
|
||||
private static final String STRING_NEGATION = "~";
|
||||
private static final String STRING_EXCLUSIVE = "-";
|
||||
private static final String STRING_WILDCARD = "*";
|
||||
private static final String SEPARATOR = "\\|";
|
||||
//private static final String STRING_WILDCARD = "*";
|
||||
|
||||
private static final int SELECT_FIRST = 1 << 0;
|
||||
private static final int SELECT_WHEN_MATCHED = 1 << 1;
|
||||
|
||||
public RuleBuilder(boolean positive, int element, int zoom, int selector,
|
||||
AttributeMatcher keyMatcher, AttributeMatcher valueMatcher) {
|
||||
this.positiveRule = positive;
|
||||
public RuleBuilder(RuleType type, int element, int zoom, int selector,
|
||||
String[] keys, String[] values) {
|
||||
this.type = type;
|
||||
this.element = element;
|
||||
this.zoom = zoom;
|
||||
this.selector = selector;
|
||||
this.keyMatcher = keyMatcher;
|
||||
this.valueMatcher = valueMatcher;
|
||||
this.keys = keys;
|
||||
this.values = values;
|
||||
}
|
||||
|
||||
public RuleBuilder(boolean positive, AttributeMatcher keyMatcher, AttributeMatcher valueMatcher) {
|
||||
this.positiveRule = positive;
|
||||
this.keyMatcher = keyMatcher;
|
||||
this.valueMatcher = valueMatcher;
|
||||
public RuleBuilder(RuleType type, String[] keys, String[] values) {
|
||||
this.element = Element.ANY;
|
||||
this.zoom = ~0;
|
||||
this.type = type;
|
||||
this.keys = keys;
|
||||
this.values = values;
|
||||
}
|
||||
|
||||
public RuleBuilder() {
|
||||
this.type = RuleType.POSITIVE;
|
||||
this.element = Element.ANY;
|
||||
this.zoom = ~0;
|
||||
this.keys = EMPTY_KV;
|
||||
this.values = EMPTY_KV;
|
||||
}
|
||||
|
||||
public static RuleBuilder create(Stack<RuleBuilder> ruleStack, String keys, String values) {
|
||||
|
||||
List<String> keyList = null, valueList = null;
|
||||
boolean negativeRule = false;
|
||||
boolean exclusionRule = false;
|
||||
String[] keyList = EMPTY_KV;
|
||||
String[] valueList = EMPTY_KV;
|
||||
RuleType type = RuleType.POSITIVE;
|
||||
|
||||
AttributeMatcher keyMatcher, valueMatcher = null;
|
||||
|
||||
if (values == null) {
|
||||
valueMatcher = AnyMatcher.getInstance();
|
||||
} else {
|
||||
valueList = new ArrayList<String>(Arrays.asList(values.split("\\|")));
|
||||
if (valueList.remove(STRING_NEGATION))
|
||||
negativeRule = true;
|
||||
else if (valueList.remove(STRING_EXCLUSIVE))
|
||||
exclusionRule = true;
|
||||
else {
|
||||
valueMatcher = getValueMatcher(valueList);
|
||||
valueMatcher = RuleOptimizer.optimize(valueMatcher, ruleStack);
|
||||
if (values != null) {
|
||||
if (values.startsWith(STRING_NEGATION)) {
|
||||
type = RuleType.NEGATIVE;
|
||||
if (values.length() > 2)
|
||||
valueList = values.substring(2)
|
||||
.split(SEPARATOR);
|
||||
} else if (values.startsWith(STRING_EXCLUSIVE)) {
|
||||
type = RuleType.EXCLUDE;
|
||||
if (values.length() > 2)
|
||||
valueList = values.substring(2)
|
||||
.split(SEPARATOR);
|
||||
} else {
|
||||
valueList = values.split(SEPARATOR);
|
||||
}
|
||||
}
|
||||
|
||||
if (keys == null) {
|
||||
if (negativeRule || exclusionRule) {
|
||||
if (keys != null) {
|
||||
keyList = keys.split("\\|");
|
||||
}
|
||||
|
||||
if (type != RuleType.POSITIVE) {
|
||||
if (keyList == null || keyList.length == 0) {
|
||||
throw new ThemeException("negative rule requires key");
|
||||
}
|
||||
keyMatcher = AnyMatcher.getInstance();
|
||||
} else {
|
||||
keyList = new ArrayList<String>(Arrays.asList(keys.split("\\|")));
|
||||
keyMatcher = getKeyMatcher(keyList);
|
||||
|
||||
if ((keyMatcher instanceof AnyMatcher) && (negativeRule || exclusionRule)) {
|
||||
throw new ThemeException("negative rule requires key");
|
||||
}
|
||||
|
||||
if (negativeRule) {
|
||||
AttributeMatcher m = new NegativeMatcher(keyList, valueList, false);
|
||||
return new RuleBuilder(false, m, null);
|
||||
} else if (exclusionRule) {
|
||||
AttributeMatcher m = new NegativeMatcher(keyList, valueList, true);
|
||||
return new RuleBuilder(false, m, null);
|
||||
}
|
||||
|
||||
keyMatcher = RuleOptimizer.optimize(keyMatcher, ruleStack);
|
||||
}
|
||||
|
||||
return new RuleBuilder(true, keyMatcher, valueMatcher);
|
||||
}
|
||||
|
||||
private static AttributeMatcher getKeyMatcher(List<String> keyList) {
|
||||
if (STRING_WILDCARD.equals(keyList.get(0))) {
|
||||
return AnyMatcher.getInstance();
|
||||
}
|
||||
|
||||
AttributeMatcher attributeMatcher = MATCHERS_CACHE_KEY.get(keyList);
|
||||
if (attributeMatcher == null) {
|
||||
if (keyList.size() == 1) {
|
||||
attributeMatcher = new SingleKeyMatcher(keyList.get(0));
|
||||
} else {
|
||||
attributeMatcher = new MultiKeyMatcher(keyList);
|
||||
}
|
||||
MATCHERS_CACHE_KEY.put(keyList, attributeMatcher);
|
||||
}
|
||||
return attributeMatcher;
|
||||
}
|
||||
|
||||
private static AttributeMatcher getValueMatcher(List<String> valueList) {
|
||||
if (STRING_WILDCARD.equals(valueList.get(0))) {
|
||||
return AnyMatcher.getInstance();
|
||||
}
|
||||
|
||||
AttributeMatcher attributeMatcher = MATCHERS_CACHE_VALUE.get(valueList);
|
||||
if (attributeMatcher == null) {
|
||||
if (valueList.size() == 1) {
|
||||
attributeMatcher = new SingleValueMatcher(valueList.get(0));
|
||||
} else {
|
||||
attributeMatcher = new MultiValueMatcher(valueList);
|
||||
}
|
||||
MATCHERS_CACHE_VALUE.put(valueList, attributeMatcher);
|
||||
}
|
||||
return attributeMatcher;
|
||||
return new RuleBuilder(type, keyList, valueList);
|
||||
}
|
||||
|
||||
private static void validate(byte zoomMin, byte zoomMax) {
|
||||
@ -211,8 +176,6 @@ public class RuleBuilder {
|
||||
}
|
||||
|
||||
public Rule onComplete() {
|
||||
MATCHERS_CACHE_KEY.clear();
|
||||
MATCHERS_CACHE_VALUE.clear();
|
||||
|
||||
RenderStyle[] styles = null;
|
||||
Rule[] rules = null;
|
||||
@ -228,12 +191,12 @@ public class RuleBuilder {
|
||||
rules[i] = subRules.get(i).onComplete();
|
||||
}
|
||||
|
||||
if (positiveRule)
|
||||
return new PositiveRule(element, zoom, selector, keyMatcher,
|
||||
valueMatcher, rules, styles);
|
||||
if (type != RuleType.POSITIVE)
|
||||
return new NegativeRule(type, element, zoom, selector,
|
||||
keys, values, rules, styles);
|
||||
else
|
||||
return new NegativeRule(element, zoom, selector, keyMatcher,
|
||||
rules, styles);
|
||||
return PositiveRule.create(element, zoom, selector,
|
||||
keys, values, rules, styles);
|
||||
}
|
||||
|
||||
public void addStyle(RenderStyle style) {
|
||||
|
||||
@ -1,133 +0,0 @@
|
||||
/*
|
||||
* Copyright 2010, 2011, 2012 mapsforge.org
|
||||
* Copyright 2013 Hannes Janetzek
|
||||
*
|
||||
* This file is part of the OpenScienceMap project (http://www.opensciencemap.org).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify it under the
|
||||
* terms of the GNU Lesser General Public License as published by the Free Software
|
||||
* Foundation, either version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
|
||||
* PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License along with
|
||||
* this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.oscim.theme.rule;
|
||||
|
||||
import java.util.Stack;
|
||||
|
||||
final class RuleOptimizer {
|
||||
|
||||
private static AttributeMatcher optimizeKeyMatcher(AttributeMatcher attributeMatcher,
|
||||
Stack<RuleBuilder> ruleStack) {
|
||||
for (int i = 0, n = ruleStack.size(); i < n; ++i) {
|
||||
if (ruleStack.get(i).positiveRule) {
|
||||
RuleBuilder positiveRule = ruleStack.get(i);
|
||||
|
||||
if (positiveRule.keyMatcher != null
|
||||
&& positiveRule.keyMatcher.isCoveredBy(attributeMatcher)) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return attributeMatcher;
|
||||
}
|
||||
|
||||
private static AttributeMatcher optimizeValueMatcher(
|
||||
AttributeMatcher attributeMatcher, Stack<RuleBuilder> ruleStack) {
|
||||
for (int i = 0, n = ruleStack.size(); i < n; ++i) {
|
||||
if (ruleStack.get(i).positiveRule) {
|
||||
RuleBuilder positiveRule = ruleStack.get(i);
|
||||
|
||||
if (positiveRule.valueMatcher != null
|
||||
&& positiveRule.valueMatcher.isCoveredBy(attributeMatcher)) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return attributeMatcher;
|
||||
}
|
||||
|
||||
static AttributeMatcher optimize(AttributeMatcher attributeMatcher,
|
||||
Stack<RuleBuilder> ruleStack) {
|
||||
if (attributeMatcher instanceof AnyMatcher)
|
||||
return attributeMatcher;// return null;
|
||||
else if (attributeMatcher instanceof NegativeMatcher) {
|
||||
return attributeMatcher;
|
||||
} else if (attributeMatcher instanceof SingleKeyMatcher) {
|
||||
return optimizeKeyMatcher(attributeMatcher, ruleStack);
|
||||
} else if (attributeMatcher instanceof SingleValueMatcher) {
|
||||
return optimizeValueMatcher(attributeMatcher, ruleStack);
|
||||
} else if (attributeMatcher instanceof MultiKeyMatcher) {
|
||||
return optimizeKeyMatcher(attributeMatcher, ruleStack);
|
||||
} else if (attributeMatcher instanceof MultiValueMatcher) {
|
||||
return optimizeValueMatcher(attributeMatcher, ruleStack);
|
||||
}
|
||||
throw new IllegalArgumentException("unknown AttributeMatcher: "
|
||||
+ attributeMatcher);
|
||||
}
|
||||
|
||||
// static ClosedMatcher optimize(ClosedMatcher closedMatcher, Stack<Rule> ruleStack) {
|
||||
// if (closedMatcher == null) {
|
||||
// return null;
|
||||
// }
|
||||
//
|
||||
// if (closedMatcher instanceof AnyMatcher) {
|
||||
// return null;
|
||||
// }
|
||||
//
|
||||
// for (int i = 0, n = ruleStack.size(); i < n; ++i) {
|
||||
// ClosedMatcher matcher = ruleStack.get(i).mClosedMatcher;
|
||||
// if (matcher == null)
|
||||
// return null;
|
||||
//
|
||||
// if (matcher.isCoveredBy(closedMatcher)) {
|
||||
// return null; // AnyMatcher.getInstance();
|
||||
//
|
||||
// } else if (!closedMatcher.isCoveredBy(ruleStack.get(i).mClosedMatcher)) {
|
||||
// LOG.warning("unreachable rule (closed)");
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// return closedMatcher;
|
||||
// }
|
||||
//
|
||||
// static ElementMatcher optimize(ElementMatcher elementMatcher, Stack<Rule> ruleStack) {
|
||||
//
|
||||
// if (elementMatcher == null) {
|
||||
// return null;
|
||||
// }
|
||||
//
|
||||
// if (elementMatcher instanceof AnyMatcher) {
|
||||
// return null;
|
||||
// }
|
||||
//
|
||||
// for (int i = 0, n = ruleStack.size(); i < n; ++i) {
|
||||
// ElementMatcher matcher = ruleStack.get(i).mElementMatcher;
|
||||
//
|
||||
// if (matcher == null)
|
||||
// return null;
|
||||
//
|
||||
// if (matcher.isCoveredBy(elementMatcher)) {
|
||||
// return null; // AnyMatcher.getInstance();
|
||||
//
|
||||
// } else if (!elementMatcher.isCoveredBy(ruleStack.get(i).mElementMatcher)) {
|
||||
// LOG.warning("unreachable rule (e)");
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// return elementMatcher;
|
||||
// }
|
||||
|
||||
/**
|
||||
* Private constructor to prevent instantiation from other classes.
|
||||
*/
|
||||
private RuleOptimizer() {
|
||||
// do nothing
|
||||
}
|
||||
}
|
||||
@ -1,44 +0,0 @@
|
||||
/*
|
||||
* Copyright 2010, 2011, 2012 mapsforge.org
|
||||
* Copyright 2013 Hannes Janetzek
|
||||
*
|
||||
* This file is part of the OpenScienceMap project (http://www.opensciencemap.org).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify it under the
|
||||
* terms of the GNU Lesser General Public License as published by the Free Software
|
||||
* Foundation, either version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
|
||||
* PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License along with
|
||||
* this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.oscim.theme.rule;
|
||||
|
||||
import org.oscim.core.Tag;
|
||||
|
||||
public class SingleKeyMatcher implements AttributeMatcher {
|
||||
private final String mKey;
|
||||
|
||||
public SingleKeyMatcher(String key) {
|
||||
mKey = key.intern();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCoveredBy(AttributeMatcher attributeMatcher) {
|
||||
Tag[] tags = { new Tag(mKey, null) };
|
||||
|
||||
return attributeMatcher == this || attributeMatcher.matches(tags);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean matches(Tag[] tags) {
|
||||
for (Tag tag : tags)
|
||||
if (mKey == tag.key)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@ -1,44 +0,0 @@
|
||||
/*
|
||||
* Copyright 2010, 2011, 2012 mapsforge.org
|
||||
* Copyright 2013 Hannes Janetzek
|
||||
*
|
||||
* This file is part of the OpenScienceMap project (http://www.opensciencemap.org).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify it under the
|
||||
* terms of the GNU Lesser General Public License as published by the Free Software
|
||||
* Foundation, either version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
|
||||
* PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License along with
|
||||
* this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.oscim.theme.rule;
|
||||
|
||||
import org.oscim.core.Tag;
|
||||
|
||||
public class SingleValueMatcher implements AttributeMatcher {
|
||||
private final String mValue;
|
||||
|
||||
public SingleValueMatcher(String value) {
|
||||
mValue = value.intern();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCoveredBy(AttributeMatcher attributeMatcher) {
|
||||
Tag[] tags = { new Tag(null, mValue) };
|
||||
|
||||
return attributeMatcher == this || attributeMatcher.matches(tags);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean matches(Tag[] tags) {
|
||||
for (Tag tag : tags)
|
||||
if (mValue == tag.value)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user