mirror of
https://github.com/Card-Forge/forge.git
synced 2025-11-19 12:18:00 +00:00
Flesh out predicate building for advanced search filters
This commit is contained in:
@@ -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();
|
||||||
|
|||||||
@@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -294,7 +297,17 @@ 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) {
|
||||||
|
|||||||
@@ -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) {
|
||||||
|
if (operator.valueCount == FilterValueCount.TWO) {
|
||||||
|
return String.format(operator.formatStr, option.name, values.get(0), values.get(1));
|
||||||
|
}
|
||||||
|
return String.format(operator.formatStr, option.name, values.get(0));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
String value = SOptionPane.showInputDialog("", message);
|
||||||
if (value == null) { return null; }
|
if (value == null) { return null; }
|
||||||
|
|
||||||
final String caption = String.format(operator.formatStr, option.name, value);
|
List<String> values = new ArrayList<String>();
|
||||||
|
values.add(value);
|
||||||
|
return values;
|
||||||
|
}
|
||||||
|
|
||||||
return new Filter<T>(option, operator, caption, null);
|
@Override
|
||||||
|
protected String getCaption(List<String> values, FilterOption option, FilterOperator operator) {
|
||||||
|
return String.format(operator.formatStr, option.name, values.get(0));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static class CustomListValueSelector<V> extends FilterValueSelector {
|
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> {
|
||||||
|
|||||||
Reference in New Issue
Block a user