RenderTheme: add <m select="first">
- this stops checking sub-rules after first match - the rules renderinstruction will only applied when any subrule matched
This commit is contained in:
parent
fc1a907af0
commit
0762e13c0f
@ -20,8 +20,8 @@ import org.oscim.core.Tag;
|
|||||||
class NegativeRule extends Rule {
|
class NegativeRule extends Rule {
|
||||||
final AttributeMatcher mAttributeMatcher;
|
final AttributeMatcher mAttributeMatcher;
|
||||||
|
|
||||||
NegativeRule(int element, int zoom, AttributeMatcher attributeMatcher) {
|
NegativeRule(int element, int zoom, boolean matchFirst, AttributeMatcher attributeMatcher) {
|
||||||
super(element, zoom);
|
super(element, zoom, matchFirst);
|
||||||
|
|
||||||
mAttributeMatcher = attributeMatcher;
|
mAttributeMatcher = attributeMatcher;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -20,8 +20,9 @@ class PositiveRule extends Rule {
|
|||||||
final AttributeMatcher mKeyMatcher;
|
final AttributeMatcher mKeyMatcher;
|
||||||
final AttributeMatcher mValueMatcher;
|
final AttributeMatcher mValueMatcher;
|
||||||
|
|
||||||
PositiveRule(int element, int zoom, AttributeMatcher keyMatcher, AttributeMatcher valueMatcher) {
|
PositiveRule(int element, int zoom, boolean matchFirst, AttributeMatcher keyMatcher,
|
||||||
super(element, zoom);
|
AttributeMatcher valueMatcher) {
|
||||||
|
super(element, zoom, matchFirst);
|
||||||
|
|
||||||
if (keyMatcher instanceof AnyMatcher)
|
if (keyMatcher instanceof AnyMatcher)
|
||||||
mKeyMatcher = null;
|
mKeyMatcher = null;
|
||||||
|
|||||||
@ -22,6 +22,7 @@ import java.util.Map;
|
|||||||
import java.util.Stack;
|
import java.util.Stack;
|
||||||
|
|
||||||
import org.oscim.core.Tag;
|
import org.oscim.core.Tag;
|
||||||
|
import org.oscim.theme.IRenderTheme.ThemeException;
|
||||||
import org.oscim.theme.RenderThemeHandler;
|
import org.oscim.theme.RenderThemeHandler;
|
||||||
import org.oscim.theme.renderinstruction.RenderInstruction;
|
import org.oscim.theme.renderinstruction.RenderInstruction;
|
||||||
import org.xml.sax.Attributes;
|
import org.xml.sax.Attributes;
|
||||||
@ -32,14 +33,14 @@ public abstract class Rule {
|
|||||||
private static final Map<List<String>, AttributeMatcher> MATCHERS_CACHE_VALUE =
|
private static final Map<List<String>, AttributeMatcher> MATCHERS_CACHE_VALUE =
|
||||||
new HashMap<List<String>, AttributeMatcher>();
|
new HashMap<List<String>, AttributeMatcher>();
|
||||||
|
|
||||||
//private static final Pattern SPLIT_PATTERN = Pattern.compile("\\|");
|
|
||||||
private static final String STRING_NEGATION = "~";
|
private static final String STRING_NEGATION = "~";
|
||||||
private static final String STRING_EXCLUSIVE = "-";
|
private static final String STRING_EXCLUSIVE = "-";
|
||||||
private static final String STRING_WILDCARD = "*";
|
private static final String STRING_WILDCARD = "*";
|
||||||
|
|
||||||
private static Rule createRule(Stack<Rule> ruleStack, int element, String keys,
|
private static Rule createRule(Stack<Rule> ruleStack, int element, String keys,
|
||||||
String values, byte zoomMin, byte zoomMax) {
|
String values, byte zoomMin, byte zoomMax, boolean matchFirst) {
|
||||||
|
|
||||||
|
// zoom-level bitmask
|
||||||
int zoom = 0;
|
int zoom = 0;
|
||||||
for (int z = zoomMin; z <= zoomMax && z < 32; z++)
|
for (int z = zoomMin; z <= zoomMax && z < 32; z++)
|
||||||
zoom |= (1 << z);
|
zoom |= (1 << z);
|
||||||
@ -53,7 +54,6 @@ public abstract class Rule {
|
|||||||
if (values == null) {
|
if (values == null) {
|
||||||
valueMatcher = AnyMatcher.getInstance();
|
valueMatcher = AnyMatcher.getInstance();
|
||||||
} else {
|
} else {
|
||||||
//valueList = new ArrayList<String>(Arrays.asList(SPLIT_PATTERN.split(values)));
|
|
||||||
valueList = new ArrayList<String>(Arrays.asList(values.split("\\|")));
|
valueList = new ArrayList<String>(Arrays.asList(values.split("\\|")));
|
||||||
if (valueList.remove(STRING_NEGATION))
|
if (valueList.remove(STRING_NEGATION))
|
||||||
negativeRule = true;
|
negativeRule = true;
|
||||||
@ -67,30 +67,29 @@ public abstract class Rule {
|
|||||||
|
|
||||||
if (keys == null) {
|
if (keys == null) {
|
||||||
if (negativeRule || exclusionRule) {
|
if (negativeRule || exclusionRule) {
|
||||||
throw new IllegalArgumentException("negative rule requires key");
|
throw new ThemeException("negative rule requires key");
|
||||||
}
|
}
|
||||||
keyMatcher = AnyMatcher.getInstance();
|
keyMatcher = AnyMatcher.getInstance();
|
||||||
} else {
|
} else {
|
||||||
//keyList = new ArrayList<String>(Arrays.asList(SPLIT_PATTERN.split(keys)));
|
|
||||||
keyList = new ArrayList<String>(Arrays.asList(keys.split("\\|")));
|
keyList = new ArrayList<String>(Arrays.asList(keys.split("\\|")));
|
||||||
keyMatcher = getKeyMatcher(keyList);
|
keyMatcher = getKeyMatcher(keyList);
|
||||||
|
|
||||||
if ((keyMatcher instanceof AnyMatcher) && (negativeRule || exclusionRule)) {
|
if ((keyMatcher instanceof AnyMatcher) && (negativeRule || exclusionRule)) {
|
||||||
throw new IllegalArgumentException("negative rule requires key");
|
throw new ThemeException("negative rule requires key");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (negativeRule) {
|
if (negativeRule) {
|
||||||
AttributeMatcher attributeMatcher = new NegativeMatcher(keyList, valueList, false);
|
AttributeMatcher m = new NegativeMatcher(keyList, valueList, false);
|
||||||
return new NegativeRule(element, zoom, attributeMatcher);
|
return new NegativeRule(element, zoom, matchFirst, m);
|
||||||
} else if (exclusionRule) {
|
} else if (exclusionRule) {
|
||||||
AttributeMatcher attributeMatcher = new NegativeMatcher(keyList, valueList, true);
|
AttributeMatcher m = new NegativeMatcher(keyList, valueList, true);
|
||||||
return new NegativeRule(element, zoom, attributeMatcher);
|
return new NegativeRule(element, zoom, matchFirst, m);
|
||||||
}
|
}
|
||||||
|
|
||||||
keyMatcher = RuleOptimizer.optimize(keyMatcher, ruleStack);
|
keyMatcher = RuleOptimizer.optimize(keyMatcher, ruleStack);
|
||||||
}
|
}
|
||||||
|
|
||||||
return new PositiveRule(element, zoom, keyMatcher, valueMatcher);
|
return new PositiveRule(element, zoom, matchFirst, keyMatcher, valueMatcher);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static AttributeMatcher getKeyMatcher(List<String> keyList) {
|
private static AttributeMatcher getKeyMatcher(List<String> keyList) {
|
||||||
@ -128,16 +127,12 @@ public abstract class Rule {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static void validate(byte zoomMin, byte zoomMax) {
|
private static void validate(byte zoomMin, byte zoomMax) {
|
||||||
if (zoomMin < 0) {
|
if (zoomMin < 0)
|
||||||
throw new IllegalArgumentException("zoom-min must not be negative: "
|
throw new ThemeException("zoom-min must not be negative: " + zoomMin);
|
||||||
+ zoomMin);
|
else if (zoomMax < 0)
|
||||||
} else if (zoomMax < 0) {
|
throw new ThemeException("zoom-max must not be negative: " + zoomMax);
|
||||||
throw new IllegalArgumentException("zoom-max must not be negative: "
|
else if (zoomMin > zoomMax)
|
||||||
+ zoomMax);
|
throw new ThemeException("zoom-min must be less or equal zoom-max: " + zoomMin);
|
||||||
} else if (zoomMin > zoomMax) {
|
|
||||||
throw new IllegalArgumentException("zoom-min must be less or equal zoom-max: "
|
|
||||||
+ zoomMin);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Rule create(String elementName, Attributes attributes, Stack<Rule> ruleStack) {
|
public static Rule create(String elementName, Attributes attributes, Stack<Rule> ruleStack) {
|
||||||
@ -147,6 +142,7 @@ public abstract class Rule {
|
|||||||
String values = null;
|
String values = null;
|
||||||
byte zoomMin = 0;
|
byte zoomMin = 0;
|
||||||
byte zoomMax = Byte.MAX_VALUE;
|
byte zoomMax = Byte.MAX_VALUE;
|
||||||
|
boolean matchFirst = false;
|
||||||
|
|
||||||
for (int i = 0; i < attributes.getLength(); ++i) {
|
for (int i = 0; i < attributes.getLength(); ++i) {
|
||||||
String name = attributes.getLocalName(i);
|
String name = attributes.getLocalName(i);
|
||||||
@ -172,6 +168,8 @@ public abstract class Rule {
|
|||||||
zoomMin = Byte.parseByte(value);
|
zoomMin = Byte.parseByte(value);
|
||||||
} else if ("zoom-max".equals(name)) {
|
} else if ("zoom-max".equals(name)) {
|
||||||
zoomMax = Byte.parseByte(value);
|
zoomMax = Byte.parseByte(value);
|
||||||
|
} else if ("select".equals(name)) {
|
||||||
|
matchFirst = "first".equals(value);
|
||||||
} else {
|
} else {
|
||||||
RenderThemeHandler.logUnknownAttribute(elementName, name, value, i);
|
RenderThemeHandler.logUnknownAttribute(elementName, name, value, i);
|
||||||
}
|
}
|
||||||
@ -183,91 +181,114 @@ public abstract class Rule {
|
|||||||
element = Element.LINE;
|
element = Element.LINE;
|
||||||
|
|
||||||
validate(zoomMin, zoomMax);
|
validate(zoomMin, zoomMax);
|
||||||
return createRule(ruleStack, element, keys, values, zoomMin, zoomMax);
|
|
||||||
|
return createRule(ruleStack, element, keys, values, zoomMin, zoomMax, matchFirst);
|
||||||
}
|
}
|
||||||
|
|
||||||
private ArrayList<RenderInstruction> mRenderInstructions;
|
private Rule[] mSubRules;
|
||||||
private ArrayList<Rule> mSubRules;
|
private RenderInstruction[] mRenderInstructions;
|
||||||
|
|
||||||
private Rule[] mSubRuleArray;
|
|
||||||
private RenderInstruction[] mRenderInstructionArray;
|
|
||||||
|
|
||||||
final int mZoom;
|
final int mZoom;
|
||||||
final int mElement;
|
final int mElement;
|
||||||
|
final boolean mMatchFirst;
|
||||||
|
|
||||||
Rule(int type, int zoom) {
|
static class Builder {
|
||||||
|
ArrayList<RenderInstruction> renderInstructions = new ArrayList<RenderInstruction>(4);
|
||||||
|
ArrayList<Rule> subRules = new ArrayList<Rule>(4);
|
||||||
|
|
||||||
|
public void clear() {
|
||||||
|
renderInstructions.clear();
|
||||||
|
renderInstructions = null;
|
||||||
|
subRules.clear();
|
||||||
|
subRules = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private Builder builder;
|
||||||
|
|
||||||
|
Rule(int type, int zoom, boolean matchFirst) {
|
||||||
|
builder = new Builder();
|
||||||
mElement = type;
|
mElement = type;
|
||||||
mZoom = zoom;
|
mZoom = zoom;
|
||||||
|
mMatchFirst = matchFirst;
|
||||||
mRenderInstructions = new ArrayList<RenderInstruction>(4);
|
|
||||||
mSubRules = new ArrayList<Rule>(4);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void addRenderingInstruction(RenderInstruction renderInstruction) {
|
public void addRenderingInstruction(RenderInstruction renderInstruction) {
|
||||||
mRenderInstructions.add(renderInstruction);
|
builder.renderInstructions.add(renderInstruction);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void addSubRule(Rule rule) {
|
public void addSubRule(Rule rule) {
|
||||||
mSubRules.add(rule);
|
builder.subRules.add(rule);
|
||||||
}
|
}
|
||||||
|
|
||||||
abstract boolean matchesTags(Tag[] tags);
|
abstract boolean matchesTags(Tag[] tags);
|
||||||
|
|
||||||
public void matchElement(int type, Tag[] tags, int zoomLevel,
|
public boolean matchElement(int type, Tag[] tags, int zoomLevel,
|
||||||
List<RenderInstruction> matchingList) {
|
List<RenderInstruction> matchingList) {
|
||||||
|
|
||||||
if (((mElement & type) != 0) && ((mZoom & zoomLevel) != 0) && (matchesTags(tags))) {
|
if (((mElement & type) != 0) && ((mZoom & zoomLevel) != 0) && (matchesTags(tags))) {
|
||||||
|
|
||||||
// add instructions for this rule
|
boolean matched = false;
|
||||||
for (RenderInstruction ri : mRenderInstructionArray)
|
|
||||||
matchingList.add(ri);
|
|
||||||
|
|
||||||
// check subrules
|
// check subrules
|
||||||
for (Rule subRule : mSubRuleArray)
|
for (Rule subRule : mSubRules) {
|
||||||
subRule.matchElement(type, tags, zoomLevel, matchingList);
|
if (subRule.matchElement(type, tags, zoomLevel, matchingList) && mMatchFirst) {
|
||||||
|
matched = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!mMatchFirst || matched) {
|
||||||
|
// add instructions for this rule
|
||||||
|
for (RenderInstruction ri : mRenderInstructions)
|
||||||
|
matchingList.add(ri);
|
||||||
|
}
|
||||||
|
|
||||||
|
// this rule did match
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// this rule did not match
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void onComplete() {
|
public void onComplete() {
|
||||||
MATCHERS_CACHE_KEY.clear();
|
MATCHERS_CACHE_KEY.clear();
|
||||||
MATCHERS_CACHE_VALUE.clear();
|
MATCHERS_CACHE_VALUE.clear();
|
||||||
|
|
||||||
mRenderInstructionArray = new RenderInstruction[mRenderInstructions.size()];
|
mRenderInstructions = new RenderInstruction[builder.renderInstructions.size()];
|
||||||
mRenderInstructions.toArray(mRenderInstructionArray);
|
builder.renderInstructions.toArray(mRenderInstructions);
|
||||||
|
|
||||||
mSubRuleArray = new Rule[mSubRules.size()];
|
mSubRules = new Rule[builder.subRules.size()];
|
||||||
mSubRules.toArray(mSubRuleArray);
|
builder.subRules.toArray(mSubRules);
|
||||||
|
|
||||||
mRenderInstructions.clear();
|
builder.clear();
|
||||||
mRenderInstructions = null;
|
builder = null;
|
||||||
mSubRules.clear();
|
|
||||||
mSubRules = null;
|
|
||||||
|
|
||||||
for (Rule subRule : mSubRuleArray)
|
for (Rule subRule : mSubRules)
|
||||||
subRule.onComplete();
|
subRule.onComplete();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void onDestroy() {
|
public void onDestroy() {
|
||||||
for (RenderInstruction ri : mRenderInstructionArray)
|
for (RenderInstruction ri : mRenderInstructions)
|
||||||
ri.destroy();
|
ri.destroy();
|
||||||
|
|
||||||
for (Rule subRule : mSubRuleArray)
|
for (Rule subRule : mSubRules)
|
||||||
subRule.onDestroy();
|
subRule.onDestroy();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void scaleStrokeWidth(float scaleFactor) {
|
public void scaleStrokeWidth(float scaleFactor) {
|
||||||
for (RenderInstruction ri : mRenderInstructionArray)
|
for (RenderInstruction ri : mRenderInstructions)
|
||||||
ri.scaleStrokeWidth(scaleFactor);
|
ri.scaleStrokeWidth(scaleFactor);
|
||||||
|
|
||||||
for (Rule subRule : mSubRuleArray)
|
for (Rule subRule : mSubRules)
|
||||||
subRule.scaleStrokeWidth(scaleFactor);
|
subRule.scaleStrokeWidth(scaleFactor);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void scaleTextSize(float scaleFactor) {
|
public void scaleTextSize(float scaleFactor) {
|
||||||
for (RenderInstruction ri : mRenderInstructionArray)
|
for (RenderInstruction ri : mRenderInstructions)
|
||||||
ri.scaleTextSize(scaleFactor);
|
ri.scaleTextSize(scaleFactor);
|
||||||
for (Rule subRule : mSubRuleArray)
|
for (Rule subRule : mSubRules)
|
||||||
subRule.scaleTextSize(scaleFactor);
|
subRule.scaleTextSize(scaleFactor);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user