label.matchCondition_notcontains = Does not contain
label.matchCondition_matches = Matches
label.matchCondition_notmatches = Does not match
+label.matchCondition_present = Is present
+label.matchCondition_notpresent = Is not present
label.matchCondition_eq = =
label.matchCondition_ne = not =
label.matchCondition_lt = <
label.matchCondition_notcontains = No contiene
label.matchCondition_matches = Es igual a
label.matchCondition_notmatches = No es igual a
+label.matchCondition_present = Está presente
+label.matchCondition_notpresent = No está presente
label.matchCondition_eq = =
label.matchCondition_ne = not =
label.matchCondition_lt = <
import java.awt.event.ItemListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
+import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.List;
private static final int BELOW_THRESHOLD_OPTION = 2;
+ private static final DecimalFormat DECFMT_2_2 = new DecimalFormat(
+ "##.##");
+
/*
* FeatureRenderer holds colour scheme and filters for feature types
*/
* and an empty filter for the user to populate (add)
*/
KeyedMatcherI noFilter = new KeyedMatcher(Condition.values()[0], "",
- (String) null);
+ (String[]) null);
filters.add(noFilter);
/*
*/
populateConditions((String) attCombo.getSelectedItem(), cond,
condCombo);
+ condCombo.setPreferredSize(new Dimension(150, 20));
condCombo.addItemListener(itemListener);
filterRow.add(condCombo);
filterRow.add(patternField);
/*
+ * disable pattern field for condition 'Present / NotPresent'
+ */
+ Condition selectedCondition = (Condition) condCombo.getSelectedItem();
+ if (selectedCondition == Condition.Present
+ || selectedCondition == Condition.NotPresent)
+ {
+ patternField.setEnabled(false);
+ }
+
+ /*
+ * if a numeric condition is selected, show the value range
+ * as a tooltip on the value input field
+ */
+ if (selectedCondition.isNumeric())
+ {
+ float[] minMax = FeatureAttributes.getInstance()
+ .getMinMax(featureType, attName);
+ if (minMax != null)
+ {
+ String tip = String.format("(%s - %s)",
+ DECFMT_2_2.format(minMax[0]), DECFMT_2_2.format(minMax[1]));
+ patternField.setToolTipText(tip);
+ }
+ }
+
+ /*
* add remove button if filter is populated (non-empty pattern)
*/
if (pattern != null && pattern.trim().length() > 0)
* Answers true unless a numeric condition has been selected with a non-numeric
* value. Sets the value field to RED with a tooltip if in error.
* <p>
- * If the pattern entered is empty, this method returns false, but does not mark
- * the field as invalid. This supports selecting an attribute for a new
+ * If the pattern is expected but is empty, this method returns false, but does
+ * not mark the field as invalid. This supports selecting an attribute for a new
* condition before a match pattern has been entered.
*
* @param value
}
Condition cond = (Condition) condCombo.getSelectedItem();
+ if (cond == Condition.Present || cond == Condition.NotPresent)
+ {
+ return true;
+ }
+
value.setBackground(Color.white);
value.setToolTipText("");
String v1 = value.getText().trim();
for (KeyedMatcherI filter : filters)
{
String pattern = filter.getMatcher().getPattern();
- if (pattern.trim().length() > 0)
+ Condition condition = filter.getMatcher().getCondition();
+ if (pattern.trim().length() > 0 || condition == Condition.Present
+ || condition == Condition.NotPresent)
{
if (anded)
{
public enum Condition
{
Contains(false), NotContains(false), Matches(false), NotMatches(false),
+ Present(false), NotPresent(false),
EQ(true), NE(true), LT(true), LE(true), GT(true), GE(true);
private static Map<Condition, String> displayNames = new HashMap<>();
}
/**
- * Answers a string description of this matcher, suitable for debugging or
- * logging. The format may change in future.
+ * Answers a string description of this matcher, suitable for display, debugging
+ * or logging. The format may change in future.
*/
@Override
public String toString()
{
StringBuilder sb = new StringBuilder();
sb.append(String.join(COLON, key)).append(" ")
- .append(matcher.getCondition().toString()).append(" ");
- if (matcher.getCondition().isNumeric())
+ .append(matcher.getCondition().toString());
+ Condition condition = matcher.getCondition();
+ if (condition.isNumeric())
{
- sb.append(matcher.getPattern());
+ sb.append(" ").append(matcher.getPattern());
}
- else
+ else if (condition != Condition.Present
+ && condition != Condition.NotPresent)
{
- sb.append("'").append(matcher.getPattern()).append("'");
+ sb.append(" '").append(matcher.getPattern()).append("'");
}
return sb.toString();
else
{
// pattern matches will be non-case-sensitive
- pattern = compareTo.toUpperCase();
+ pattern = compareTo == null ? null : compareTo.toUpperCase();
}
// if we add regex conditions (e.g. matchesPattern), then
if (val == null)
{
return condition == Condition.NotContains
- || condition == Condition.NotMatches;
+ || condition == Condition.NotMatches
+ || condition == Condition.NotPresent;
}
String upper = val.toUpperCase().trim();
case NotContains:
matched = upper.indexOf(pattern) == -1;
break;
+ case Present:
+ matched = true;
+ break;
+ default:
+ break;
}
return matched;
}
case GE:
matched = f >= value;
break;
+ default:
+ break;
}
return matched;
assertEquals(Condition.NotContains.toString(), "Does not contain");
assertEquals(Condition.Matches.toString(), "Matches");
assertEquals(Condition.NotMatches.toString(), "Does not match");
+ assertEquals(Condition.Present.toString(), "Is present");
+ assertEquals(Condition.NotPresent.toString(), "Is not present");
assertEquals(Condition.LT.toString(), "<");
assertEquals(Condition.LE.toString(), "<=");
assertEquals(Condition.GT.toString(), ">");
*/
KeyedMatcherI km = new KeyedMatcher(Condition.LT, 1.2f, "AF");
assertEquals(km.toString(), "AF < 1.2");
+
+ /*
+ * Present / NotPresent omit the value pattern
+ */
+ km = new KeyedMatcher(Condition.Present, "", "AF");
+ assertEquals(km.toString(), "AF Is present");
+ km = new KeyedMatcher(Condition.NotPresent, "", "AF");
+ assertEquals(km.toString(), "AF Is not present");
}
@Test
assertTrue(m.matches(null));
/*
+ * value is present (is not null)
+ */
+ m = new Matcher(Condition.Present, null);
+ assertTrue(m.matches("benign"));
+ assertTrue(m.matches(""));
+ assertFalse(m.matches(null));
+
+ /*
+ * value is not present (is null)
+ */
+ m = new Matcher(Condition.NotPresent, null);
+ assertFalse(m.matches("benign"));
+ assertFalse(m.matches(""));
+ assertTrue(m.matches(null));
+
+ /*
* a float with a string match condition will be treated as string
*/
Matcher m1 = new Matcher(Condition.Contains, "32");