X-Git-Url: http://source.jalview.org/gitweb/?a=blobdiff_plain;f=src%2Fjalview%2Fdatamodel%2Ffeatures%2FFeatureMatcherSet.java;h=b51f2f0a5cc95e3de1f9e3be3404709d1cea6781;hb=14b1b2a878190d5fffda298c4b9a901c72c74ad3;hp=eb5538731314bab2ef0ae95f928c4c2807dde929;hpb=b320470d1ddb95476d3678477b72f6f791a51404;p=jalview.git diff --git a/src/jalview/datamodel/features/FeatureMatcherSet.java b/src/jalview/datamodel/features/FeatureMatcherSet.java index eb55387..b51f2f0 100644 --- a/src/jalview/datamodel/features/FeatureMatcherSet.java +++ b/src/jalview/datamodel/features/FeatureMatcherSet.java @@ -6,8 +6,24 @@ import jalview.util.MessageManager; import java.util.ArrayList; import java.util.List; +/** + * A class that models one or more match conditions, which may be combined with + * AND or OR (but not a mixture) + * + * @author gmcarstairs + */ public class FeatureMatcherSet implements FeatureMatcherSetI { + private static final String OR = "OR"; + + private static final String AND = "AND"; + + private static final String SPACE = " "; + + private static final String CLOSE_BRACKET = ")"; + + private static final String OPEN_BRACKET = "("; + private static final String OR_I18N = MessageManager .getString("label.or"); @@ -19,6 +35,112 @@ public class FeatureMatcherSet implements FeatureMatcherSetI boolean andConditions; /** + * A factory constructor that converts a stringified object (as output by + * toStableString) to an object instance. + * + * Format: + * + * where OR and AND are not case-sensitive, and may not be mixed. Brackets are + * optional if there is only one condition. + * + * @param descriptor + * @return + * @see FeatureMatcher#fromString(String) + */ + public static FeatureMatcherSet fromString(final String descriptor) + { + String invalid = "Invalid descriptor: " + descriptor; + boolean firstCondition = true; + FeatureMatcherSet result = new FeatureMatcherSet(); + + String leftToParse = descriptor.trim(); + + while (leftToParse.length() > 0) + { + /* + * inspect AND or OR condition, check not mixed + */ + boolean and = true; + if (!firstCondition) + { + int spacePos = leftToParse.indexOf(SPACE); + if (spacePos == -1) + { + // trailing junk after a match condition + System.err.println(invalid); + return null; + } + String conjunction = leftToParse.substring(0, spacePos); + leftToParse = leftToParse.substring(spacePos + 1).trim(); + if (conjunction.equalsIgnoreCase(AND)) + { + and = true; + } + else if (conjunction.equalsIgnoreCase(OR)) + { + and = false; + } + else + { + // not an AND or an OR - invalid + System.err.println(invalid); + return null; + } + } + + /* + * now extract the next condition and AND or OR it + */ + String nextCondition = leftToParse; + if (leftToParse.startsWith(OPEN_BRACKET)) + { + int closePos = leftToParse.indexOf(CLOSE_BRACKET); + if (closePos == -1) + { + System.err.println(invalid); + return null; + } + nextCondition = leftToParse.substring(1, closePos); + leftToParse = leftToParse.substring(closePos + 1).trim(); + } + else + { + leftToParse = ""; + } + + FeatureMatcher fm = FeatureMatcher.fromString(nextCondition); + if (fm == null) + { + System.err.println(invalid); + return null; + } + try + { + if (and) + { + result.and(fm); + } + else + { + result.or(fm); + } + firstCondition = false; + } catch (IllegalStateException e) + { + // thrown if OR and AND are mixed + System.err.println(invalid); + return null; + } + + } + return result; + } + + /** * Constructor */ public FeatureMatcherSet() @@ -66,7 +188,7 @@ public class FeatureMatcherSet implements FeatureMatcherSetI } @Override - public FeatureMatcherSetI and(FeatureMatcherI m) + public void and(FeatureMatcherI m) { if (!andConditions && matchConditions.size() > 1) { @@ -74,12 +196,10 @@ public class FeatureMatcherSet implements FeatureMatcherSetI } matchConditions.add(m); andConditions = true; - - return this; } @Override - public FeatureMatcherSetI or(FeatureMatcherI m) + public void or(FeatureMatcherI m) { if (andConditions && matchConditions.size() > 1) { @@ -87,8 +207,6 @@ public class FeatureMatcherSet implements FeatureMatcherSetI } matchConditions.add(m); andConditions = false; - - return this; } @Override @@ -103,20 +221,34 @@ public class FeatureMatcherSet implements FeatureMatcherSetI return matchConditions; } + /** + * Answers a string representation of this object suitable for display, and + * possibly internationalized. The format is not guaranteed stable and may + * change in future. + */ @Override public String toString() { StringBuilder sb = new StringBuilder(); boolean first = true; + boolean multiple = matchConditions.size() > 1; for (FeatureMatcherI matcher : matchConditions) { if (!first) { String joiner = andConditions ? AND_18N : OR_I18N; - sb.append(" ").append(joiner.toLowerCase()).append(" "); + sb.append(SPACE).append(joiner.toLowerCase()).append(SPACE); } first = false; - sb.append("(").append(matcher.toString()).append(")"); + if (multiple) + { + sb.append(OPEN_BRACKET).append(matcher.toString()) + .append(CLOSE_BRACKET); + } + else + { + sb.append(matcher.toString()); + } } return sb.toString(); } @@ -127,4 +259,36 @@ public class FeatureMatcherSet implements FeatureMatcherSetI return matchConditions == null || matchConditions.isEmpty(); } + /** + * {@inheritDoc} The output of this method should be parseable by method + * fromString to restore the original object. + */ + @Override + public String toStableString() + { + StringBuilder sb = new StringBuilder(); + boolean moreThanOne = matchConditions.size() > 1; + boolean first = true; + + for (FeatureMatcherI matcher : matchConditions) + { + if (!first) + { + String joiner = andConditions ? AND : OR; + sb.append(SPACE).append(joiner).append(SPACE); + } + first = false; + if (moreThanOne) + { + sb.append(OPEN_BRACKET).append(matcher.toStableString()) + .append(CLOSE_BRACKET); + } + else + { + sb.append(matcher.toStableString()); + } + } + return sb.toString(); + } + }