package jalview.datamodel.features;
import jalview.datamodel.SequenceFeature;
+import jalview.util.MessageManager;
import jalview.util.matcher.Condition;
import jalview.util.matcher.Matcher;
import jalview.util.matcher.MatcherI;
*/
public class FeatureMatcher implements FeatureMatcherI
{
+ /*
+ * a dummy matcher that comes in useful for the 'add a filter' gui row
+ */
+ public static final FeatureMatcherI NULL_MATCHER = FeatureMatcher
+ .byLabel(Condition.values()[0], "");
+
private static final String COLON = ":";
/*
}
@Override
- public String[] getKey()
+ public String[] getAttribute()
{
return key;
}
public String toString()
{
StringBuilder sb = new StringBuilder();
- sb.append(String.join(COLON, key)).append(" ")
- .append(matcher.getCondition().toString());
+ if (byLabel)
+ {
+ sb.append(MessageManager.getString("label.label"));
+ }
+ else if (byScore)
+ {
+ sb.append(MessageManager.getString("label.score"));
+ }
+ else
+ {
+ sb.append(String.join(COLON, key));
+ }
+
Condition condition = matcher.getCondition();
+ sb.append(" ").append(condition.toString().toLowerCase());
if (condition.isNumeric())
{
sb.append(" ").append(matcher.getPattern());
return sb.toString();
}
+
+ @Override
+ public boolean isByLabel()
+ {
+ return byLabel;
+ }
+
+ @Override
+ public boolean isByScore()
+ {
+ return byScore;
+ }
}
boolean matches(SequenceFeature feature);
/**
- * Answers the value key this matcher operates on
+ * Answers the attribute key this matcher operates on (or null if match is by
+ * Label or Score)
*
* @return
*/
- String[] getKey();
+ String[] getAttribute();
+
+ /**
+ * Answers true if match is against feature label (description), else false
+ *
+ * @return
+ */
+ boolean isByLabel();
+
+ /**
+ * Answers true if match is against feature score, else false
+ *
+ * @return
+ */
+ boolean isByScore();
/**
* Answers the match condition that is applied
package jalview.datamodel.features;
import jalview.datamodel.SequenceFeature;
+import jalview.util.MessageManager;
import java.util.ArrayList;
import java.util.List;
public class FeatureMatcherSet implements FeatureMatcherSetI
{
+ private static final String OR_I18N = MessageManager
+ .getString("label.or");
+
+ private static final String AND_18N = MessageManager
+ .getString("label.and");
+
List<FeatureMatcherI> matchConditions;
boolean andConditions;
{
if (!first)
{
- sb.append(andConditions ? " AND " : " OR ");
+ String joiner = andConditions ? AND_18N : OR_I18N;
+ sb.append(" ").append(joiner.toLowerCase()).append(" ");
}
first = false;
sb.append("(").append(matcher.toString()).append(")");
Condition condition;
/*
- * the string value (upper-cased), or the regex, to compare to
+ * the string pattern as entered, or the regex, to compare to
* also holds the string form of float value if a numeric condition
*/
String pattern;
/*
+ * the pattern in upper case, for non-case-sensitive matching
+ */
+ String uppercasePattern;
+
+ /*
* the compiled regex if using a pattern match condition
* (reserved for possible future enhancement)
*/
*/
public Matcher(Condition cond, String compareTo)
{
+ Objects.requireNonNull(cond);
condition = cond;
if (cond.isNumeric())
{
value = Float.valueOf(compareTo);
pattern = String.valueOf(value);
+ uppercasePattern = pattern;
}
else
{
- // pattern matches will be non-case-sensitive
- pattern = compareTo == null ? null : compareTo.toUpperCase();
+ pattern = compareTo;
+ if (pattern != null)
+ {
+ uppercasePattern = pattern.toUpperCase();
+ }
}
// if we add regex conditions (e.g. matchesPattern), then
*/
public Matcher(Condition cond, float compareTo)
{
- Objects.requireNonNull(cond);
- condition = cond;
- value = compareTo;
- pattern = String.valueOf(compareTo).toUpperCase();
+ this(cond, String.valueOf(compareTo));
}
/**
boolean matched = false;
switch(condition) {
case Matches:
- matched = upper.equals(pattern);
+ matched = upper.equals(uppercasePattern);
break;
case NotMatches:
- matched = !upper.equals(pattern);
+ matched = !upper.equals(uppercasePattern);
break;
case Contains:
- matched = upper.indexOf(pattern) > -1;
+ matched = upper.indexOf(uppercasePattern) > -1;
break;
case NotContains:
- matched = upper.indexOf(pattern) == -1;
+ matched = upper.indexOf(uppercasePattern) == -1;
break;
case Present:
matched = true;
/**
* equals is overridden so that we can safely remove Matcher objects from
- * collections (e.g. delete an attribut match condition for a feature colour)
+ * collections (e.g. delete an attribute match condition for a feature colour)
*/
@Override
public boolean equals(Object obj)
return false;
}
Matcher m = (Matcher) obj;
- return condition == m.condition && value == m.value
- && pattern.equals(m.pattern);
+ if (condition != m.condition || value != m.value)
+ {
+ return false;
+ }
+ if (pattern == null)
+ {
+ return m.pattern == null;
+ }
+ return uppercasePattern.equals(m.uppercasePattern);
}
@Override
public String toString()
{
StringBuilder sb = new StringBuilder();
- sb.append(condition.name()).append(" ");
+ sb.append(condition.toString()).append(" ");
if (condition.isNumeric())
{
sb.append(pattern);
import java.util.HashMap;
import java.util.Iterator;
+import java.util.Locale;
import java.util.Map;
import org.testng.annotations.Test;
@Test(groups = "Functional")
public void testToString()
{
+ Locale.setDefault(Locale.ENGLISH);
FeatureMatcherI fm1 = FeatureMatcher.byAttribute(Condition.LT, "1.2",
"AF");
assertEquals(fm1.toString(), "AF < 1.2");
FeatureMatcher fm2 = FeatureMatcher.byAttribute(Condition.NotContains,
- "path",
- "CLIN_SIG");
- assertEquals(fm2.toString(), "CLIN_SIG Does not contain 'PATH'");
+ "path", "CLIN_SIG");
+ assertEquals(fm2.toString(), "CLIN_SIG does not contain 'path'");
/*
* AND them
assertEquals(fms.toString(), "(AF < 1.2)");
fms.and(fm2);
assertEquals(fms.toString(),
- "(AF < 1.2) AND (CLIN_SIG Does not contain 'PATH')");
+ "(AF < 1.2) and (CLIN_SIG does not contain 'path')");
/*
* OR them
assertEquals(fms.toString(), "(AF < 1.2)");
fms.or(fm2);
assertEquals(fms.toString(),
- "(AF < 1.2) OR (CLIN_SIG Does not contain 'PATH')");
+ "(AF < 1.2) or (CLIN_SIG does not contain 'path')");
try
{
assertFalse(fms.matches(sf));
csq.put("Consequence", "junk");
assertFalse(fms.matches(sf));
-
+
/*
* a string pattern matcher
*/
import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertFalse;
+import static org.testng.Assert.assertNull;
import static org.testng.Assert.assertTrue;
import jalview.datamodel.SequenceFeature;
+import jalview.util.MessageManager;
import jalview.util.matcher.Condition;
+import java.util.Locale;
+
import org.testng.annotations.Test;
public class FeatureMatcherTest
@Test
public void testToString()
{
+ Locale.setDefault(Locale.ENGLISH);
+
/*
* toString uses the i18n translation of the enum conditions
*/
* Present / NotPresent omit the value pattern
*/
fm = FeatureMatcher.byAttribute(Condition.Present, "", "AF");
- assertEquals(fm.toString(), "AF Is present");
+ assertEquals(fm.toString(), "AF is present");
fm = FeatureMatcher.byAttribute(Condition.NotPresent, "", "AF");
- assertEquals(fm.toString(), "AF Is not present");
+ assertEquals(fm.toString(), "AF is not present");
+
+ /*
+ * by Label
+ */
+ fm = FeatureMatcher.byLabel(Condition.Matches, "foobar");
+ assertEquals(fm.toString(),
+ MessageManager.getString("label.label") + " matches 'foobar'");
+
+ /*
+ * by Score
+ */
+ fm = FeatureMatcher.byScore(Condition.GE, "12.2");
+ assertEquals(fm.toString(),
+ MessageManager.getString("label.score") + " >= 12.2");
}
@Test
- public void testGetKey()
+ public void testGetAttribute()
{
FeatureMatcherI fm = FeatureMatcher.byAttribute(Condition.GE, "-2",
"AF");
- assertEquals(fm.getKey(), new String[] { "AF" });
+ assertEquals(fm.getAttribute(), new String[] { "AF" });
/*
* compound key (attribute / subattribute)
*/
fm = FeatureMatcher.byAttribute(Condition.GE, "-2F", "CSQ",
"Consequence");
- assertEquals(fm.getKey(), new String[] { "CSQ", "Consequence" });
+ assertEquals(fm.getAttribute(), new String[] { "CSQ", "Consequence" });
+
+ /*
+ * answers null if match is by Label or by Score
+ */
+ assertNull(FeatureMatcher.byLabel(Condition.NotContains, "foo")
+ .getAttribute());
+ assertNull(FeatureMatcher.byScore(Condition.LE, "-1").getAttribute());
+ }
+
+ @Test
+ public void testIsByLabel()
+ {
+ assertTrue(FeatureMatcher.byLabel(Condition.NotContains, "foo")
+ .isByLabel());
+ assertFalse(FeatureMatcher.byScore(Condition.LE, "-1").isByLabel());
+ assertFalse(FeatureMatcher.byAttribute(Condition.LE, "-1", "AC")
+ .isByLabel());
+ }
+
+ @Test
+ public void testIsByScore()
+ {
+ assertFalse(FeatureMatcher.byLabel(Condition.NotContains, "foo")
+ .isByScore());
+ assertTrue(FeatureMatcher.byScore(Condition.LE, "-1").isByScore());
+ assertFalse(FeatureMatcher.byAttribute(Condition.LE, "-1", "AC")
+ .isByScore());
}
@Test
import static org.testng.Assert.assertTrue;
import static org.testng.Assert.fail;
+import java.util.Locale;
+
import org.testng.annotations.Test;
+import junit.extensions.PA;
+
public class MatcherTest
{
@Test(groups = "Functional")
{
MatcherI m = new Matcher(Condition.Contains, "foo");
assertEquals(m.getCondition(), Condition.Contains);
- assertEquals(m.getPattern(), "FOO"); // all comparisons upper-cased
+ assertEquals(m.getPattern(), "foo");
+ assertEquals(PA.getValue(m, "uppercasePattern"), "FOO");
assertEquals(m.getFloatValue(), 0f);
m = new Matcher(Condition.GT, -2.1f);
m = new Matcher(Condition.NotContains, "-1.2f");
assertEquals(m.getCondition(), Condition.NotContains);
- assertEquals(m.getPattern(), "-1.2F");
+ assertEquals(m.getPattern(), "-1.2f");
assertEquals(m.getFloatValue(), 0f);
m = new Matcher(Condition.GE, "-1.2f");
@Test(groups = "Functional")
public void testToString()
{
+ Locale.setDefault(Locale.ENGLISH);
+
MatcherI m = new Matcher(Condition.LT, 1.2e-6f);
- assertEquals(m.toString(), "LT 1.2E-6");
+ assertEquals(m.toString(), "< 1.2E-6");
m = new Matcher(Condition.NotMatches, "ABC");
- assertEquals(m.toString(), "NotMatches 'ABC'");
+ assertEquals(m.toString(), "Does not match 'ABC'");
m = new Matcher(Condition.Contains, -1.2f);
assertEquals(m.toString(), "Contains '-1.2'");