Flesh out predicate building for advanced search filters

This commit is contained in:
drdev
2015-09-06 00:14:34 +00:00
parent 703fecdefd
commit 91e4f5d2d6
4 changed files with 455 additions and 79 deletions

View File

@@ -18,11 +18,11 @@
package forge.card; package forge.card;
import java.io.Serializable; import java.io.Serializable;
import java.util.Iterator; import java.util.*;
import java.util.NoSuchElementException;
import com.google.common.collect.UnmodifiableIterator; import com.google.common.collect.UnmodifiableIterator;
import forge.card.MagicColor.Color;
import forge.card.mana.ManaCost; import forge.card.mana.ManaCost;
import forge.util.BinaryUtil; import forge.util.BinaryUtil;
@@ -302,6 +302,16 @@ public final class ColorSet implements Comparable<ColorSet>, Iterable<Byte>, Ser
return fromMask(~this.myColor & ccOther.myColor); return fromMask(~this.myColor & ccOther.myColor);
} }
public Set<Color> toEnumSet() {
List<Color> list = new ArrayList<Color>();
for (Color c : Color.values()) {
if (hasAnyColor(c.getColormask())) {
list.add(c);
}
}
return EnumSet.copyOf(list);
}
@Override @Override
public Iterator<Byte> iterator() { public Iterator<Byte> iterator() {
return new ColorIterator(); return new ColorIterator();

View File

@@ -151,4 +151,32 @@ public final class MagicColor {
private Constant() { private Constant() {
} }
} }
public enum Color {
WHITE(Constant.WHITE, MagicColor.WHITE),
BLUE(Constant.BLUE, MagicColor.BLUE),
BLACK(Constant.BLACK, MagicColor.BLACK),
RED(Constant.RED, MagicColor.RED),
GREEN(Constant.GREEN, MagicColor.GREEN),
COLORLESS(Constant.COLORLESS, MagicColor.COLORLESS);
private final String name;
private final byte colormask;
private Color(String name0, byte colormask0) {
name = name0;
colormask = colormask0;
}
public String getName() {
return name;
}
public byte getColormask() {
return colormask;
}
@Override
public String toString() {
return name;
}
}
} }

View File

@@ -21,6 +21,7 @@ import com.google.common.base.Function;
import com.google.common.base.Predicate; import com.google.common.base.Predicate;
import com.google.common.base.Predicates; import com.google.common.base.Predicates;
import com.google.common.collect.Lists; import com.google.common.collect.Lists;
import forge.StaticData; import forge.StaticData;
import forge.card.CardEdition; import forge.card.CardEdition;
import forge.deck.CardPool; import forge.deck.CardPool;
@@ -35,8 +36,10 @@ import java.io.File;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collections; import java.util.Collections;
import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Map.Entry; import java.util.Map.Entry;
import java.util.Set;
/** /**
@@ -293,8 +296,18 @@ public class GameFormat implements Comparable<GameFormat> {
} }
return NoFormat; return NoFormat;
} }
public Iterable<GameFormat> getAllFormatsOfDeck(Deck deck) { public Set<GameFormat> getAllFormatsOfCard(PaperCard card) {
Set<GameFormat> result = new HashSet<GameFormat>();
for (GameFormat gf : naturallyOrdered) {
if (gf.getFilterRules().apply(card)) {
result.add(gf);
}
}
return result;
}
public List<GameFormat> getAllFormatsOfDeck(Deck deck) {
List<GameFormat> result = new ArrayList<GameFormat>(); List<GameFormat> result = new ArrayList<GameFormat>();
CardPool allCards = deck.getAllCardsInASinglePool(); CardPool allCards = deck.getAllCardsInASinglePool();
for(GameFormat gf : naturallyOrdered) { for(GameFormat gf : naturallyOrdered) {

View File

@@ -3,14 +3,20 @@ package forge.itemmanager;
import java.util.Arrays; import java.util.Arrays;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Set;
import com.google.common.base.Function; import com.google.common.base.Function;
import com.google.common.base.Predicate; import com.google.common.base.Predicate;
import forge.card.CardEdition; import forge.card.CardEdition;
import forge.card.CardRarity; import forge.card.CardRarity;
import forge.card.CardRules;
import forge.card.CardType; import forge.card.CardType;
import forge.card.MagicColor; import forge.card.MagicColor;
import forge.card.CardType.CoreType;
import forge.card.CardType.Supertype;
import forge.game.GameFormat; import forge.game.GameFormat;
import forge.item.InventoryItem; import forge.item.InventoryItem;
import forge.item.PaperCard; import forge.item.PaperCard;
@@ -20,30 +26,137 @@ import forge.util.gui.SOptionPane;
public class AdvancedSearch { public class AdvancedSearch {
private enum FilterOption { private enum FilterOption {
CARD_NAME("Name", PaperCard.class, FilterOperator.STRING_OPS, new StringValueSelector()), CARD_NAME("Name", PaperCard.class, FilterOperator.STRING_OPS, new StringEvaluator<PaperCard>() {
CARD_RULES_TEXT("Rules Text", PaperCard.class, FilterOperator.STRING_OPS, new StringValueSelector()), @Override
CARD_SET("Set", PaperCard.class, FilterOperator.SINGLE_LIST_OPS, new CustomListValueSelector<CardEdition>(FModel.getMagicDb().getSortedEditions(), CardEdition.FN_GET_CODE)), protected String getItemValue(PaperCard input) {
CARD_FORMAT("Format", PaperCard.class, FilterOperator.SINGLE_LIST_OPS, new CustomListValueSelector<GameFormat>((List<GameFormat>)FModel.getFormats().getOrderedList())), return input.getName();
CARD_COLOR("Color", PaperCard.class, FilterOperator.MULTI_LIST_OPS, new CustomListValueSelector<String>(MagicColor.Constant.COLORS_AND_COLORLESS)), }
CARD_TYPE("Type", PaperCard.class, FilterOperator.MULTI_LIST_OPS, new CustomListValueSelector<String>(CardType.getSortedCoreAndSuperTypes())), }),
CARD_SUB_TYPE("Subtype", PaperCard.class, FilterOperator.MULTI_LIST_OPS, new CustomListValueSelector<String>(CardType.getSortedSubTypes())), CARD_RULES_TEXT("Rules Text", PaperCard.class, FilterOperator.STRING_OPS, new StringEvaluator<PaperCard>() {
CARD_CMC("CMC", PaperCard.class, FilterOperator.NUMBER_OPS, new NumericValueSelector(0, 20)), @Override
CARD_GENERIC_COST("Generic Cost", PaperCard.class, FilterOperator.NUMBER_OPS, new NumericValueSelector(0, 20)), protected String getItemValue(PaperCard input) {
CARD_POWER("Power", PaperCard.class, FilterOperator.NUMBER_OPS, new NumericValueSelector(0, 20)), return input.getRules().getOracleText();
CARD_TOUGHNESS("Toughness", PaperCard.class, FilterOperator.NUMBER_OPS, new NumericValueSelector(0, 20)), }
CARD_MANA_COST("Mana Cost", PaperCard.class, FilterOperator.STRING_OPS, new StringValueSelector()), }),
CARD_RARITY("Rarity", PaperCard.class, FilterOperator.SINGLE_LIST_OPS, new CustomListValueSelector<CardRarity>(Arrays.asList(CardRarity.values()))); CARD_SET("Set", PaperCard.class, FilterOperator.SINGLE_LIST_OPS, new CustomListEvaluator<PaperCard, CardEdition>(FModel.getMagicDb().getSortedEditions(), CardEdition.FN_GET_CODE) {
@Override
protected CardEdition getItemValue(PaperCard input) {
return FModel.getMagicDb().getEditions().get(input.getEdition());
}
}),
CARD_FORMAT("Format", PaperCard.class, FilterOperator.SINGLE_LIST_OPS, new CustomListEvaluator<PaperCard, GameFormat>((List<GameFormat>)FModel.getFormats().getOrderedList()) {
@Override
protected GameFormat getItemValue(PaperCard input) {
throw new RuntimeException("getItemValues should be called instead");
}
@Override
protected Set<GameFormat> getItemValues(PaperCard input) {
return FModel.getFormats().getAllFormatsOfCard(input);
}
}),
CARD_COLOR("Color", PaperCard.class, FilterOperator.MULTI_LIST_OPS, new CustomListEvaluator<PaperCard, MagicColor.Color>(Arrays.asList(MagicColor.Color.values())) {
@Override
protected MagicColor.Color getItemValue(PaperCard input) {
throw new RuntimeException("getItemValues should be called instead");
}
@Override
protected Set<MagicColor.Color> getItemValues(PaperCard input) {
return input.getRules().getColor().toEnumSet();
}
}),
CARD_COLOR_IDENTITY("Color Identity", PaperCard.class, FilterOperator.MULTI_LIST_OPS, new CustomListEvaluator<PaperCard, MagicColor.Color>(Arrays.asList(MagicColor.Color.values())) {
@Override
protected MagicColor.Color getItemValue(PaperCard input) {
throw new RuntimeException("getItemValues should be called instead");
}
@Override
protected Set<MagicColor.Color> getItemValues(PaperCard input) {
return input.getRules().getColorIdentity().toEnumSet();
}
}),
CARD_TYPE("Type", PaperCard.class, FilterOperator.MULTI_LIST_OPS, new CustomListEvaluator<PaperCard, String>(CardType.getSortedCoreAndSuperTypes()) {
@Override
protected String getItemValue(PaperCard input) {
throw new RuntimeException("getItemValues should be called instead");
}
@Override
protected Set<String> getItemValues(PaperCard input) {
final CardType type = input.getRules().getType();
final Set<String> types = new HashSet<String>();
for (Supertype t : type.getSupertypes()) {
types.add(t.name());
}
for (CoreType t : type.getCoreTypes()) {
types.add(t.name());
}
return types;
}
}),
CARD_SUB_TYPE("Subtype", PaperCard.class, FilterOperator.MULTI_LIST_OPS, new CustomListEvaluator<PaperCard, String>(CardType.getSortedSubTypes()) {
@Override
protected String getItemValue(PaperCard input) {
throw new RuntimeException("getItemValues should be called instead");
}
@Override
protected Set<String> getItemValues(PaperCard input) {
return (Set<String>)input.getRules().getType().getSubtypes();
}
}),
CARD_CMC("CMC", PaperCard.class, FilterOperator.NUMBER_OPS, new NumericEvaluator<PaperCard>(0, 20) {
@Override
protected Integer getItemValue(PaperCard input) {
return input.getRules().getManaCost().getCMC();
}
}),
CARD_GENERIC_COST("Generic Cost", PaperCard.class, FilterOperator.NUMBER_OPS, new NumericEvaluator<PaperCard>(0, 20) {
@Override
protected Integer getItemValue(PaperCard input) {
return input.getRules().getManaCost().getGenericCost();
}
}),
CARD_POWER("Power", PaperCard.class, FilterOperator.NUMBER_OPS, new NumericEvaluator<PaperCard>(0, 20) {
@Override
protected Integer getItemValue(PaperCard input) {
CardRules rules = input.getRules();
if (rules.getType().isCreature()) {
return rules.getIntPower();
}
return null;
}
}),
CARD_TOUGHNESS("Toughness", PaperCard.class, FilterOperator.NUMBER_OPS, new NumericEvaluator<PaperCard>(0, 20) {
@Override
protected Integer getItemValue(PaperCard input) {
CardRules rules = input.getRules();
if (rules.getType().isCreature()) {
return rules.getIntToughness();
}
return null;
}
}),
CARD_MANA_COST("Mana Cost", PaperCard.class, FilterOperator.STRING_OPS, new StringEvaluator<PaperCard>() {
@Override
protected String getItemValue(PaperCard input) {
return input.getRules().getManaCost().toString();
}
}),
CARD_RARITY("Rarity", PaperCard.class, FilterOperator.SINGLE_LIST_OPS, new CustomListEvaluator<PaperCard, CardRarity>(Arrays.asList(CardRarity.values())) {
@Override
protected CardRarity getItemValue(PaperCard input) {
return input.getRarity();
}
});
private final String name; private final String name;
private final Class<? extends InventoryItem> type; private final Class<? extends InventoryItem> type;
private final FilterOperator[] operatorOptions; private final FilterOperator[] operatorOptions;
private final FilterValueSelector valueSelector; private final FilterEvaluator<? extends InventoryItem, ?> evaluator;
private FilterOption(String name0, Class<? extends InventoryItem> type0, FilterOperator[] operatorOptions0, FilterValueSelector valueSelector0) { private FilterOption(String name0, Class<? extends InventoryItem> type0, FilterOperator[] operatorOptions0, FilterEvaluator<? extends InventoryItem, ?> evaluator0) {
name = name0; name = name0;
type = type0; type = type0;
operatorOptions = operatorOptions0; operatorOptions = operatorOptions0;
valueSelector = valueSelector0; evaluator = evaluator0;
} }
@Override @Override
@@ -54,29 +167,189 @@ public class AdvancedSearch {
private enum FilterOperator { private enum FilterOperator {
//Numeric operators //Numeric operators
EQUALS("is equal to", "%1$s=%2$d", FilterValueCount.ONE), EQUALS("is equal to", "%1$s=%2$d", FilterValueCount.ONE, new OperatorEvaluator<Integer>() {
NOT_EQUALS("is not equal to", "%1$s<>%2$d", FilterValueCount.ONE), @Override
GREATER_THAN("is greater than", "%1$s>%2$d", FilterValueCount.ONE), public boolean apply(Integer input, List<Integer> values) {
LESS_THAN("is less than", "%1$s<%2$d", FilterValueCount.ONE), if (input != null) {
GT_OR_EQUAL("is greater than or equal to", "%1$s>=%2$d", FilterValueCount.ONE), return input.intValue() == values.get(0).intValue();
LT_OR_EQUAL("is less than or equal to", "%1$s<=%2$d", FilterValueCount.ONE), }
BETWEEN_INCLUSIVE("is between (inclusive)", "%2$d<=%1$s<=%3$d", FilterValueCount.TWO), return false;
BETWEEN_EXCLUSIVE("is between (exclusive)", "%2$d<%1$s<%3$d", FilterValueCount.TWO), }
}),
NOT_EQUALS("is not equal to", "%1$s<>%2$d", FilterValueCount.ONE, new OperatorEvaluator<Integer>() {
@Override
public boolean apply(Integer input, List<Integer> values) {
if (input != null) {
return input.intValue() != values.get(0).intValue();
}
return true;
}
}),
GREATER_THAN("is greater than", "%1$s>%2$d", FilterValueCount.ONE, new OperatorEvaluator<Integer>() {
@Override
public boolean apply(Integer input, List<Integer> values) {
if (input != null) {
return input.intValue() > values.get(0).intValue();
}
return false;
}
}),
LESS_THAN("is less than", "%1$s<%2$d", FilterValueCount.ONE, new OperatorEvaluator<Integer>() {
@Override
public boolean apply(Integer input, List<Integer> values) {
if (input != null) {
return input.intValue() < values.get(0).intValue();
}
return false;
}
}),
GT_OR_EQUAL("is greater than or equal to", "%1$s>=%2$d", FilterValueCount.ONE, new OperatorEvaluator<Integer>() {
@Override
public boolean apply(Integer input, List<Integer> values) {
if (input != null) {
return input.intValue() >= values.get(0).intValue();
}
return false;
}
}),
LT_OR_EQUAL("is less than or equal to", "%1$s<=%2$d", FilterValueCount.ONE, new OperatorEvaluator<Integer>() {
@Override
public boolean apply(Integer input, List<Integer> values) {
if (input != null) {
return input.intValue() <= values.get(0).intValue();
}
return false;
}
}),
BETWEEN_INCLUSIVE("is between (inclusive)", "%2$d<=%1$s<=%3$d", FilterValueCount.TWO, new OperatorEvaluator<Integer>() {
@Override
public boolean apply(Integer input, List<Integer> values) {
if (input != null) {
int inputValue = input.intValue();
return values.get(0).intValue() <= inputValue && inputValue <= values.get(1).intValue();
}
return false;
}
}),
BETWEEN_EXCLUSIVE("is between (exclusive)", "%2$d<%1$s<%3$d", FilterValueCount.TWO, new OperatorEvaluator<Integer>() {
@Override
public boolean apply(Integer input, List<Integer> values) {
if (input != null) {
int inputValue = input.intValue();
return values.get(0).intValue() < inputValue && inputValue < values.get(1).intValue();
}
return false;
}
}),
//String operators //String operators
IS("is", "%1$s is '%2$s'", FilterValueCount.ONE), IS("is", "%1$s is '%2$s'", FilterValueCount.ONE, new OperatorEvaluator<String>() {
IS_NOT("is not", "%1$s is not '%2$s'", FilterValueCount.ONE), @Override
CONTAINS("contains", "%1$s contains '%2$s'", FilterValueCount.ONE), public boolean apply(String input, List<String> values) {
STARTS_WITH("starts with", "%1$s starts with '%2$s'", FilterValueCount.ONE), if (input != null) {
ENDS_WITH("ends with", "%1$s ends with '%2$s'", FilterValueCount.ONE), return input.toLowerCase().equals(values.get(0).toLowerCase());
}
return false;
}
}),
IS_NOT("is not", "%1$s is not '%2$s'", FilterValueCount.ONE, new OperatorEvaluator<String>() {
@Override
public boolean apply(String input, List<String> values) {
if (input != null) {
return !input.toLowerCase().equals(values.get(0).toLowerCase());
}
return true;
}
}),
CONTAINS("contains", "%1$s contains '%2$s'", FilterValueCount.ONE, new OperatorEvaluator<String>() {
@Override
public boolean apply(String input, List<String> values) {
if (input != null) {
return input.toLowerCase().indexOf(values.get(0).toLowerCase()) != -1;
}
return false;
}
}),
STARTS_WITH("starts with", "%1$s starts with '%2$s'", FilterValueCount.ONE, new OperatorEvaluator<String>() {
@Override
public boolean apply(String input, List<String> values) {
if (input != null) {
return input.toLowerCase().startsWith(values.get(0).toLowerCase());
}
return false;
}
}),
ENDS_WITH("ends with", "%1$s ends with '%2$s'", FilterValueCount.ONE, new OperatorEvaluator<String>() {
@Override
public boolean apply(String input, List<String> values) {
if (input != null) {
return input.toLowerCase().endsWith(values.get(0).toLowerCase());
}
return false;
}
}),
//Custom list operators //Custom list operators
IS_EXACTLY("is exactly", "%1$s is %2$s", FilterValueCount.MANY), IS_EXACTLY("is exactly", "%1$s is %2$s", FilterValueCount.MANY, new OperatorEvaluator<Object>() {
IS_ANY("is any of", "%1$s is %2$s", FilterValueCount.MANY_OR), @Override
IS_ALL("is all of", "%1$s is %2$s", FilterValueCount.MANY_AND), public boolean apply(Object input, List<Object> values) {
IS_NONE("is none of", "%1$s is not %2$s", FilterValueCount.MANY_OR), return false;
INCLUDES_ANY("includes any of", "%1$s includes %2$s", FilterValueCount.MANY_OR), }
INCLUDES_ALL("includes all of", "%1$s includes %2$s", FilterValueCount.MANY_AND); @Override
public boolean apply(Set<Object> inputs, List<Object> values) {
return false;
}
}),
IS_ANY("is any of", "%1$s is %2$s", FilterValueCount.MANY_OR, new OperatorEvaluator<Object>() {
@Override
public boolean apply(Object input, List<Object> values) {
return false;
}
@Override
public boolean apply(Set<Object> inputs, List<Object> values) {
return false;
}
}),
IS_ALL("is all of", "%1$s is %2$s", FilterValueCount.MANY_AND, new OperatorEvaluator<Object>() {
@Override
public boolean apply(Object input, List<Object> values) {
return false;
}
@Override
public boolean apply(Set<Object> inputs, List<Object> values) {
return false;
}
}),
IS_NONE("is none of", "%1$s is not %2$s", FilterValueCount.MANY_OR, new OperatorEvaluator<Object>() {
@Override
public boolean apply(Object input, List<Object> values) {
return false;
}
@Override
public boolean apply(Set<Object> inputs, List<Object> values) {
return false;
}
}),
INCLUDES_ANY("includes any of", "%1$s includes %2$s", FilterValueCount.MANY_OR, new OperatorEvaluator<Object>() {
@Override
public boolean apply(Object input, List<Object> values) {
return false;
}
@Override
public boolean apply(Set<Object> inputs, List<Object> values) {
return false;
}
}),
INCLUDES_ALL("includes all of", "%1$s includes %2$s", FilterValueCount.MANY_AND, new OperatorEvaluator<Object>() {
@Override
public boolean apply(Object input, List<Object> values) {
return false;
}
@Override
public boolean apply(Set<Object> inputs, List<Object> values) {
return false;
}
});
public static final FilterOperator[] NUMBER_OPS = new FilterOperator[] { public static final FilterOperator[] NUMBER_OPS = new FilterOperator[] {
EQUALS, NOT_EQUALS, GREATER_THAN, LESS_THAN, GT_OR_EQUAL, LT_OR_EQUAL, BETWEEN_INCLUSIVE, BETWEEN_EXCLUSIVE EQUALS, NOT_EQUALS, GREATER_THAN, LESS_THAN, GT_OR_EQUAL, LT_OR_EQUAL, BETWEEN_INCLUSIVE, BETWEEN_EXCLUSIVE
@@ -93,11 +366,13 @@ public class AdvancedSearch {
private final String caption, formatStr; private final String caption, formatStr;
private final FilterValueCount valueCount; private final FilterValueCount valueCount;
private final OperatorEvaluator<?> evaluator;
private FilterOperator(String caption0, String formatStr0, FilterValueCount valueCount0) { private FilterOperator(String caption0, String formatStr0, FilterValueCount valueCount0, OperatorEvaluator<?> evaluator0) {
caption = caption0; caption = caption0;
formatStr = formatStr0; formatStr = formatStr0;
valueCount = valueCount0; valueCount = valueCount0;
evaluator = evaluator0;
} }
@Override @Override
@@ -114,20 +389,62 @@ public class AdvancedSearch {
MANY_AND MANY_AND
} }
private static abstract class FilterValueSelector { private static abstract class OperatorEvaluator<V> {
public abstract <T extends InventoryItem> Filter<T> createFilter(String message, FilterOption option, FilterOperator operator); protected abstract boolean apply(V input, List<V> values);
protected boolean apply(Set<V> inputs, List<V> values) {
return false; //available for options that have multiple inputs
}
} }
private static class NumericValueSelector extends FilterValueSelector { private static abstract class FilterEvaluator<T extends InventoryItem, V> {
@SuppressWarnings("unchecked")
public final Filter<T> createFilter(String message, FilterOption option, FilterOperator operator) {
final List<V> values = getValues(message, option, operator);
if (values == null || values.isEmpty()) { return null; }
String caption = getCaption(values, option, operator);
final OperatorEvaluator<V> evaluator = (OperatorEvaluator<V>)operator.evaluator;
Predicate<T> predicate;
if (option.operatorOptions == FilterOperator.MULTI_LIST_OPS) {
predicate = new Predicate<T>() {
@Override
public boolean apply(T input) {
return evaluator.apply(getItemValues(input), values);
}
};
}
else {
predicate = new Predicate<T>() {
@Override
public boolean apply(T input) {
return evaluator.apply(getItemValue(input), values);
}
};
}
return new Filter<T>(option, operator, caption, predicate);
}
protected abstract List<V> getValues(String message, FilterOption option, FilterOperator operator);
protected abstract String getCaption(List<V> values, FilterOption option, FilterOperator operator);
protected abstract V getItemValue(T input);
protected Set<V> getItemValues(T input) { //available for options that have multiple inputs
return null;
}
}
private static abstract class NumericEvaluator<T extends InventoryItem> extends FilterEvaluator<T, Integer> {
private final int min, max; private final int min, max;
public NumericValueSelector(int min0, int max0) { public NumericEvaluator(int min0, int max0) {
min = min0; min = min0;
max = max0; max = max0;
} }
@Override @Override
public <T extends InventoryItem> Filter<T> createFilter(String message, FilterOption option, FilterOperator operator) { protected List<Integer> getValues(String message, FilterOption option, FilterOperator operator) {
String msg = message; String msg = message;
if (operator.valueCount == FilterValueCount.TWO) { if (operator.valueCount == FilterValueCount.TWO) {
msg += " (Lower Bound)"; msg += " (Lower Bound)";
@@ -135,64 +452,75 @@ public class AdvancedSearch {
Integer lowerBound = SGuiChoose.getInteger(msg, min, max); Integer lowerBound = SGuiChoose.getInteger(msg, min, max);
if (lowerBound == null) { return null; } if (lowerBound == null) { return null; }
final String caption; final List<Integer> values = new ArrayList<Integer>();
values.add(lowerBound);
if (operator.valueCount == FilterValueCount.TWO) { //prompt for upper bound if needed if (operator.valueCount == FilterValueCount.TWO) { //prompt for upper bound if needed
msg = message + " (Upper Bound)"; msg = message + " (Upper Bound)";
Integer upperBound = SGuiChoose.getInteger(msg, lowerBound, max); Integer upperBound = SGuiChoose.getInteger(msg, lowerBound, max);
if (upperBound == null) { return null; } if (upperBound == null) { return null; }
caption = String.format(operator.formatStr, option.name, lowerBound, upperBound); values.add(upperBound);
} }
else { return values;
caption = String.format(operator.formatStr, option.name, lowerBound);
}
return new Filter<T>(option, operator, caption, null);
}
}
private static class StringValueSelector extends FilterValueSelector {
public StringValueSelector() {
} }
@Override @Override
public <T extends InventoryItem> Filter<T> createFilter(String message, FilterOption option, FilterOperator operator) { protected String getCaption(List<Integer> values, FilterOption option, FilterOperator operator) {
String value = SOptionPane.showInputDialog("", message); if (operator.valueCount == FilterValueCount.TWO) {
if (value == null) { return null; } return String.format(operator.formatStr, option.name, values.get(0), values.get(1));
}
final String caption = String.format(operator.formatStr, option.name, value); return String.format(operator.formatStr, option.name, values.get(0));
return new Filter<T>(option, operator, caption, null);
} }
} }
private static class CustomListValueSelector<V> extends FilterValueSelector { private static abstract class StringEvaluator<T extends InventoryItem> extends FilterEvaluator<T, String> {
public StringEvaluator() {
}
@Override
protected List<String> getValues(String message, FilterOption option, FilterOperator operator) {
String value = SOptionPane.showInputDialog("", message);
if (value == null) { return null; }
List<String> values = new ArrayList<String>();
values.add(value);
return values;
}
@Override
protected String getCaption(List<String> values, FilterOption option, FilterOperator operator) {
return String.format(operator.formatStr, option.name, values.get(0));
}
}
private static abstract class CustomListEvaluator<T extends InventoryItem, V> extends FilterEvaluator<T, V> {
private final Collection<V> choices; private final Collection<V> choices;
private final Function<V, String> toShortString, toLongString; private final Function<V, String> toShortString, toLongString;
public CustomListValueSelector(Collection<V> choices0) { public CustomListEvaluator(Collection<V> choices0) {
this(choices0, null, null); this(choices0, null, null);
} }
public CustomListValueSelector(Collection<V> choices0, Function<V, String> toShortString0) { public CustomListEvaluator(Collection<V> choices0, Function<V, String> toShortString0) {
this(choices0, toShortString0, null); this(choices0, toShortString0, null);
} }
public CustomListValueSelector(Collection<V> choices0, Function<V, String> toShortString0, Function<V, String> toLongString0) { public CustomListEvaluator(Collection<V> choices0, Function<V, String> toShortString0, Function<V, String> toLongString0) {
choices = choices0; choices = choices0;
toShortString = toShortString0; toShortString = toShortString0;
toLongString = toLongString0; toLongString = toLongString0;
} }
@Override @Override
public <T extends InventoryItem> Filter<T> createFilter(String message, FilterOption option, FilterOperator operator) { protected List<V> getValues(String message, FilterOption option, FilterOperator operator) {
int max = choices.size(); int max = choices.size();
if (operator == FilterOperator.IS_EXACTLY && option.operatorOptions == FilterOperator.SINGLE_LIST_OPS) { if (operator == FilterOperator.IS_EXACTLY && option.operatorOptions == FilterOperator.SINGLE_LIST_OPS) {
max = 1; max = 1;
} }
List<V> values = SGuiChoose.getChoices(message, 0, max, choices); return SGuiChoose.getChoices(message, 0, max, choices, null, toLongString);
if (values == null || values.isEmpty()) { }
return null;
}
@Override
protected String getCaption(List<V> values, FilterOption option, FilterOperator operator) {
String valuesStr; String valuesStr;
switch (operator.valueCount) { switch (operator.valueCount) {
case MANY: case MANY:
@@ -206,11 +534,7 @@ public class AdvancedSearch {
valuesStr = formatValues(values, ", ", " and "); valuesStr = formatValues(values, ", ", " and ");
break; break;
} }
return String.format(operator.formatStr, option.name, valuesStr);
final String caption = String.format(operator.formatStr, option.name, valuesStr);
return new Filter<T>(option, operator, caption, null);
} }
private String formatValues(List<V> values, String delim, String finalDelim) { private String formatValues(List<V> values, String delim, String finalDelim) {
@@ -239,6 +563,7 @@ public class AdvancedSearch {
} }
} }
@SuppressWarnings("unchecked")
public static <T extends InventoryItem> Filter<T> getFilter(Class<? super T> type, Filter<T> editFilter) { public static <T extends InventoryItem> Filter<T> getFilter(Class<? super T> type, Filter<T> editFilter) {
//build list of filter options based on ItemManager type //build list of filter options based on ItemManager type
List<FilterOption> options = new ArrayList<FilterOption>(); List<FilterOption> options = new ArrayList<FilterOption>();
@@ -257,7 +582,7 @@ public class AdvancedSearch {
if (operator == null) { return null; } if (operator == null) { return null; }
final String message = option.name + " " + operator.caption + " ?"; final String message = option.name + " " + operator.caption + " ?";
return option.valueSelector.createFilter(message, option, operator); return (Filter<T>)option.evaluator.createFilter(message, option, operator);
} }
public static class Filter<T extends InventoryItem> { public static class Filter<T extends InventoryItem> {