From bc3faa88c4d565b6e01e91820da171cfba1689ad Mon Sep 17 00:00:00 2001 From: Anthony Calosa Date: Thu, 11 Sep 2025 18:55:44 +0800 Subject: [PATCH 1/2] fix Keyword Advanced Search --- .../main/java/forge/game/keyword/Keyword.java | 6 + .../forge/itemmanager/AdvancedSearch.java | 329 +++++++++++------- 2 files changed, 200 insertions(+), 135 deletions(-) diff --git a/forge-game/src/main/java/forge/game/keyword/Keyword.java b/forge-game/src/main/java/forge/game/keyword/Keyword.java index d4b698b4ddb..c6f08b0130f 100644 --- a/forge-game/src/main/java/forge/game/keyword/Keyword.java +++ b/forge-game/src/main/java/forge/game/keyword/Keyword.java @@ -278,6 +278,12 @@ public enum Keyword { return keywords; } + public static Keyword get(String key) { + if (key.isEmpty()) + return null; + return Arrays.stream(values()).filter(k -> key.equalsIgnoreCase(k.displayName)).findFirst().orElse(null); + } + private static final Map> cardKeywordSetLookup = new HashMap<>(); public static Set getKeywordSet(PaperCard card) { diff --git a/forge-gui/src/main/java/forge/itemmanager/AdvancedSearch.java b/forge-gui/src/main/java/forge/itemmanager/AdvancedSearch.java index 81b9d1771da..37ed9f18eed 100644 --- a/forge-gui/src/main/java/forge/itemmanager/AdvancedSearch.java +++ b/forge-gui/src/main/java/forge/itemmanager/AdvancedSearch.java @@ -57,6 +57,7 @@ public class AdvancedSearch { protected String getItemValue(PaperCard input) { throw new RuntimeException("getItemValues should be called instead"); } + @Override protected Set getItemValues(PaperCard input) { Set names = new HashSet<>(); @@ -77,6 +78,7 @@ public class AdvancedSearch { protected String getItemValue(PaperCard input) { throw new RuntimeException("getItemValues should be called instead"); } + @Override protected Set getItemValues(PaperCard input) { Set names = new HashSet<>(); @@ -98,21 +100,31 @@ public class AdvancedSearch { protected Keyword getItemValue(PaperCard input) { throw new RuntimeException("getItemValues should be called instead"); } + @Override protected Set getItemValues(PaperCard input) { CardSplitType cardSplitType = input.getRules().getSplitType(); + Set keywords = new HashSet<>(); if (cardSplitType != CardSplitType.None && cardSplitType != CardSplitType.Split) { - Set keywords = new HashSet<>(); if (input.getRules().getOtherPart() != null) { - PaperCard otherPart = FModel.getMagicDb().getCommonCards().getCard(input.getRules().getOtherPart().getName()); - if (otherPart != null) { - keywords.addAll(Keyword.getKeywordSet(otherPart)); - keywords.addAll(Keyword.getKeywordSet(input)); + if (input.getRules().getOtherPart().getKeywords() != null) { + for (String key : input.getRules().getOtherPart().getKeywords()) { + Keyword keyword = Keyword.get(key); + if (keyword != null) + keywords.add(keyword); + } } } return keywords; } - return Keyword.getKeywordSet(input); + if (input.getRules().getMainPart().getKeywords() != null) { + for (String key : input.getRules().getMainPart().getKeywords()) { + Keyword keyword = Keyword.get(key); + if (keyword != null) + keywords.add(keyword); + } + } + return keywords; } }), CARD_SET("lblSet", PaperCard.class, FilterOperator.SINGLE_LIST_OPS, new CustomListEvaluator(FModel.getMagicDb().getSortedEditions(), CardEdition::getCode) { @@ -121,11 +133,12 @@ public class AdvancedSearch { return FModel.getMagicDb().getCardEdition(input.getEdition()); } }), - CARD_FORMAT("lblFormat", PaperCard.class, FilterOperator.MULTI_LIST_OPS, new CustomListEvaluator((List)FModel.getFormats().getFilterList()) { + CARD_FORMAT("lblFormat", PaperCard.class, FilterOperator.MULTI_LIST_OPS, new CustomListEvaluator((List) FModel.getFormats().getFilterList()) { @Override protected GameFormat getItemValue(PaperCard input) { throw new RuntimeException("getItemValues should be called instead"); } + @Override protected Set getItemValues(PaperCard input) { return FModel.getFormats().getAllFormatsOfCard(input); @@ -136,6 +149,7 @@ public class AdvancedSearch { protected ConquestPlane getItemValue(PaperCard input) { throw new RuntimeException("getItemValues should be called instead"); } + @Override protected Set getItemValues(PaperCard input) { return ConquestPlane.getAllPlanesOfCard(input); @@ -146,6 +160,7 @@ public class AdvancedSearch { protected ConquestRegion getItemValue(PaperCard input) { throw new RuntimeException("getItemValues should be called instead"); } + @Override protected Set getItemValues(PaperCard input) { return ConquestRegion.getAllRegionsOfCard(input); @@ -156,6 +171,7 @@ public class AdvancedSearch { protected QuestWorld getItemValue(PaperCard input) { throw new RuntimeException("getItemValues should be called instead"); } + @Override protected Set getItemValues(PaperCard input) { return QuestWorld.getAllQuestWorldsOfCard(input); @@ -166,6 +182,7 @@ public class AdvancedSearch { protected MagicColor.Color getItemValue(PaperCard input) { throw new RuntimeException("getItemValues should be called instead"); } + @Override protected Set getItemValues(PaperCard input) { return input.getRules().getColor().toEnumSet(); @@ -176,6 +193,7 @@ public class AdvancedSearch { protected MagicColor.Color getItemValue(PaperCard input) { throw new RuntimeException("getItemValues should be called instead"); } + @Override protected Set getItemValues(PaperCard input) { return input.getRules().getColorIdentity().toEnumSet(); @@ -192,6 +210,7 @@ public class AdvancedSearch { protected String getItemValue(PaperCard input) { throw new RuntimeException("getItemValues should be called instead"); } + @Override protected Set getItemValues(PaperCard input) { final CardType type = input.getRules().getType(); @@ -228,6 +247,7 @@ public class AdvancedSearch { protected String getItemValue(PaperCard input) { throw new RuntimeException("getItemValues should be called instead"); } + @Override protected Set getItemValues(PaperCard input) { CardSplitType cardSplitType = input.getRules().getSplitType(); @@ -243,7 +263,7 @@ public class AdvancedSearch { return subtypes; } } - return (Set)input.getRules().getType().getSubtypes(); + return (Set) input.getRules().getType().getSubtypes(); } }), CARD_CMC("lblCMC", PaperCard.class, FilterOperator.NUMBER_OPS, new NumericEvaluator(0, 20) { @@ -294,7 +314,9 @@ public class AdvancedSearch { @Override protected Boolean getItemValue(PaperCard input) { List cards = FModel.getMagicDb().getCommonCards().getAllCards(input.getName()); - if (cards.size() <= 1) { return true; } + if (cards.size() <= 1) { + return true; + } cards.sort(FModel.getMagicDb().getEditions().CARD_EDITION_COMPARATOR); return cards.get(0) == input; @@ -318,7 +340,7 @@ public class AdvancedSearch { if (!(input instanceof PaperCard)) { return ""; } - return ((PaperCard)input).getRules().getOracleText(); + return ((PaperCard) input).getRules().getOracleText(); } }), INVITEM_KEYWORDS("lblKeywords", InventoryItem.class, FilterOperator.COLLECTION_OPS, new CustomListEvaluator(Keyword.getAllKeywords()) { @@ -326,38 +348,40 @@ public class AdvancedSearch { protected Keyword getItemValue(InventoryItem input) { throw new RuntimeException("getItemValues should be called instead"); } + @Override protected Set getItemValues(InventoryItem input) { if (!(input instanceof PaperCard)) { return new HashSet<>(); } - return Keyword.getKeywordSet((PaperCard)input); + return Keyword.getKeywordSet((PaperCard) input); } }), INVITEM_SET("lblSet", InventoryItem.class, FilterOperator.SINGLE_LIST_OPS, new CustomListEvaluator(FModel.getMagicDb().getSortedEditions(), CardEdition::getCode) { @Override protected CardEdition getItemValue(InventoryItem input) { if (input instanceof PaperCard) { - CardEdition set = FModel.getMagicDb().getEditions().get(((PaperCard)input).getEdition()); + CardEdition set = FModel.getMagicDb().getEditions().get(((PaperCard) input).getEdition()); return set; } else if (input instanceof SealedProduct) { - return FModel.getMagicDb().getEditions().get(((SealedProduct)input).getEdition()); + return FModel.getMagicDb().getEditions().get(((SealedProduct) input).getEdition()); } else { return CardEdition.UNKNOWN; } } }), - INVITEM_FORMAT("lblFormat", InventoryItem.class, FilterOperator.MULTI_LIST_OPS, new CustomListEvaluator((List)FModel.getFormats().getFilterList()) { + INVITEM_FORMAT("lblFormat", InventoryItem.class, FilterOperator.MULTI_LIST_OPS, new CustomListEvaluator((List) FModel.getFormats().getFilterList()) { @Override protected GameFormat getItemValue(InventoryItem input) { throw new RuntimeException("getItemValues should be called instead"); } + @Override protected Set getItemValues(InventoryItem input) { if (!(input instanceof PaperCard)) { return new HashSet<>(); } - return FModel.getFormats().getAllFormatsOfCard((PaperCard)input); + return FModel.getFormats().getAllFormatsOfCard((PaperCard) input); } }), INVITEM_PLANE("lblPlane", InventoryItem.class, FilterOperator.MULTI_LIST_OPS, new CustomListEvaluator(ImmutableList.copyOf(FModel.getPlanes())) { @@ -365,12 +389,13 @@ public class AdvancedSearch { protected ConquestPlane getItemValue(InventoryItem input) { throw new RuntimeException("getItemValues should be called instead"); } + @Override protected Set getItemValues(InventoryItem input) { if (!(input instanceof PaperCard)) { return new HashSet<>(); } - return ConquestPlane.getAllPlanesOfCard((PaperCard)input); + return ConquestPlane.getAllPlanesOfCard((PaperCard) input); } }), INVITEM_REGION("lblRegion", InventoryItem.class, FilterOperator.MULTI_LIST_OPS, new CustomListEvaluator(ConquestRegion.getAllRegions()) { @@ -378,12 +403,13 @@ public class AdvancedSearch { protected ConquestRegion getItemValue(InventoryItem input) { throw new RuntimeException("getItemValues should be called instead"); } + @Override protected Set getItemValues(InventoryItem input) { if (!(input instanceof PaperCard)) { return new HashSet<>(); } - return ConquestRegion.getAllRegionsOfCard((PaperCard)input); + return ConquestRegion.getAllRegionsOfCard((PaperCard) input); } }), INVITEM_QUEST_WORLD("lblQuestWorld", InventoryItem.class, FilterOperator.MULTI_LIST_OPS, new CustomListEvaluator(ImmutableList.copyOf(FModel.getWorlds())) { @@ -391,12 +417,13 @@ public class AdvancedSearch { protected QuestWorld getItemValue(InventoryItem input) { throw new RuntimeException("getItemValues should be called instead"); } + @Override protected Set getItemValues(InventoryItem input) { if (!(input instanceof PaperCard)) { return new HashSet<>(); } - return QuestWorld.getAllQuestWorldsOfCard(((PaperCard)input)); + return QuestWorld.getAllQuestWorldsOfCard(((PaperCard) input)); } }), INVITEM_COLOR("lblColor", InventoryItem.class, FilterOperator.COMBINATION_OPS, new ColorEvaluator() { @@ -404,12 +431,13 @@ public class AdvancedSearch { protected MagicColor.Color getItemValue(InventoryItem input) { throw new RuntimeException("getItemValues should be called instead"); } + @Override protected Set getItemValues(InventoryItem input) { if (!(input instanceof PaperCard)) { return new HashSet<>(); } - return ((PaperCard)input).getRules().getColor().toEnumSet(); + return ((PaperCard) input).getRules().getColor().toEnumSet(); } }), INVITEM_COLOR_IDENTITY("lblColorIdentity", InventoryItem.class, FilterOperator.COMBINATION_OPS, new ColorEvaluator() { @@ -417,12 +445,13 @@ public class AdvancedSearch { protected MagicColor.Color getItemValue(InventoryItem input) { throw new RuntimeException("getItemValues should be called instead"); } + @Override protected Set getItemValues(InventoryItem input) { if (!(input instanceof PaperCard)) { return new HashSet<>(); } - return ((PaperCard)input).getRules().getColorIdentity().toEnumSet(); + return ((PaperCard) input).getRules().getColorIdentity().toEnumSet(); } }), INVITEM_COLOR_COUNT("lblColorCount", InventoryItem.class, FilterOperator.NUMBER_OPS, new NumericEvaluator(0, 5) { @@ -431,7 +460,7 @@ public class AdvancedSearch { if (!(input instanceof PaperCard)) { return 0; } - return ((PaperCard)input).getRules().getColor().countColors(); + return ((PaperCard) input).getRules().getColor().countColors(); } }), INVITEM_TYPE("lblType", InventoryItem.class, FilterOperator.COMBINATION_OPS, new CustomListEvaluator(CardType.getCombinedSuperAndCoreTypes()) { @@ -439,12 +468,13 @@ public class AdvancedSearch { protected String getItemValue(InventoryItem input) { throw new RuntimeException("getItemValues should be called instead"); } + @Override protected Set getItemValues(InventoryItem input) { if (!(input instanceof PaperCard)) { return new HashSet<>(); } - final CardType type = ((PaperCard)input).getRules().getType(); + final CardType type = ((PaperCard) input).getRules().getType(); final Set types = new HashSet<>(); for (Supertype t : type.getSupertypes()) { types.add(t.name()); @@ -460,12 +490,13 @@ public class AdvancedSearch { protected String getItemValue(InventoryItem input) { throw new RuntimeException("getItemValues should be called instead"); } + @Override protected Set getItemValues(InventoryItem input) { if (!(input instanceof PaperCard)) { return new HashSet<>(); } - return (Set)((PaperCard)input).getRules().getType().getSubtypes(); + return (Set) ((PaperCard) input).getRules().getType().getSubtypes(); } }), INVITEM_CMC("lblCMC", InventoryItem.class, FilterOperator.NUMBER_OPS, new NumericEvaluator(0, 20) { @@ -474,7 +505,7 @@ public class AdvancedSearch { if (!(input instanceof PaperCard)) { return 0; } - return ((PaperCard)input).getRules().getManaCost().getCMC(); + return ((PaperCard) input).getRules().getManaCost().getCMC(); } }), INVITEM_GENERIC_COST("lblGenericCost", InventoryItem.class, FilterOperator.NUMBER_OPS, new NumericEvaluator(0, 20) { @@ -483,7 +514,7 @@ public class AdvancedSearch { if (!(input instanceof PaperCard)) { return 0; } - return ((PaperCard)input).getRules().getManaCost().getGenericCost(); + return ((PaperCard) input).getRules().getManaCost().getGenericCost(); } }), INVITEM_POWER("lblPower", InventoryItem.class, FilterOperator.NUMBER_OPS, new NumericEvaluator(0, 20) { @@ -492,7 +523,7 @@ public class AdvancedSearch { if (!(input instanceof PaperCard)) { return null; } - CardRules rules = ((PaperCard)input).getRules(); + CardRules rules = ((PaperCard) input).getRules(); if (rules.getType().isCreature()) { return rules.getIntPower(); } @@ -505,7 +536,7 @@ public class AdvancedSearch { if (!(input instanceof PaperCard)) { return null; } - CardRules rules = ((PaperCard)input).getRules(); + CardRules rules = ((PaperCard) input).getRules(); if (rules.getType().isCreature()) { return rules.getIntToughness(); } @@ -518,14 +549,16 @@ public class AdvancedSearch { if (!(input instanceof PaperCard)) { return ""; } - return ((PaperCard)input).getRules().getManaCost().toString(); + return ((PaperCard) input).getRules().getManaCost().toString(); } }), INVITEM_FIRST_PRINTING("lblFirstPrinting", InventoryItem.class, FilterOperator.BOOLEAN_OPS, new BooleanEvaluator() { @Override protected Boolean getItemValue(InventoryItem input) { List cards = FModel.getMagicDb().getCommonCards().getAllCards(input.getName()); - if (cards.size() <= 1) { return true; } + if (cards.size() <= 1) { + return true; + } cards.sort(FModel.getMagicDb().getEditions().CARD_EDITION_COMPARATOR); return cards.get(0) == input; @@ -537,7 +570,7 @@ public class AdvancedSearch { if (!(input instanceof PaperCard)) { return CardRarity.Special; } - return ((PaperCard)input).getRarity(); + return ((PaperCard) input).getRarity(); } }), INVITEM_BUY_PRICE("lblBuyPrice", InventoryItem.class, FilterOperator.NUMBER_OPS, new NumericEvaluator(0, 10000000) { @@ -576,11 +609,12 @@ public class AdvancedSearch { return input.isFavoriteDeck(); } }), - DECK_FORMAT("lblFormat", DeckProxy.class, FilterOperator.MULTI_LIST_OPS, new CustomListEvaluator((List)FModel.getFormats().getFilterList()) { + DECK_FORMAT("lblFormat", DeckProxy.class, FilterOperator.MULTI_LIST_OPS, new CustomListEvaluator((List) FModel.getFormats().getFilterList()) { @Override protected GameFormat getItemValue(DeckProxy input) { throw new RuntimeException("getItemValues should be called instead"); } + @Override protected Set getItemValues(DeckProxy input) { return input.getExhaustiveFormats(); @@ -591,6 +625,7 @@ public class AdvancedSearch { protected QuestWorld getItemValue(DeckProxy input) { throw new RuntimeException("getItemValues should be called instead"); } + @Override protected Set getItemValues(DeckProxy input) { return QuestWorld.getAllQuestWorldsOfDeck(input.getDeck()); @@ -601,6 +636,7 @@ public class AdvancedSearch { protected MagicColor.Color getItemValue(DeckProxy input) { throw new RuntimeException("getItemValues should be called instead"); } + @Override protected Set getItemValues(DeckProxy input) { return input.getColor().toEnumSet(); @@ -611,6 +647,7 @@ public class AdvancedSearch { protected MagicColor.Color getItemValue(DeckProxy input) { throw new RuntimeException("getItemValues should be called instead"); } + @Override protected Set getItemValues(DeckProxy input) { return input.getColorIdentity().toEnumSet(); @@ -673,6 +710,7 @@ public class AdvancedSearch { protected MagicColor.Color getItemValue(ConquestCommander input) { throw new RuntimeException("getItemValues should be called instead"); } + @Override protected Set getItemValues(ConquestCommander input) { return input.getCard().getRules().getColorIdentity().toEnumSet(); @@ -825,6 +863,7 @@ public class AdvancedSearch { } return false; } + @Override public boolean apply(Set inputs, List values) { if (inputs != null && !inputs.isEmpty() && !values.isEmpty()) { @@ -846,6 +885,7 @@ public class AdvancedSearch { } return false; } + @Override public boolean apply(Set inputs, List values) { if (inputs != null && !inputs.isEmpty() && !values.isEmpty()) { @@ -867,6 +907,7 @@ public class AdvancedSearch { } return false; } + @Override public boolean apply(Set inputs, List values) { if (inputs != null && !inputs.isEmpty() && !values.isEmpty()) { @@ -890,6 +931,7 @@ public class AdvancedSearch { } return false; } + @Override public boolean apply(Set inputs, List values) { if (inputs != null && inputs.size() == values.size()) { @@ -915,6 +957,7 @@ public class AdvancedSearch { } return false; } + @Override public boolean apply(Set inputs, List values) { if (inputs != null) { @@ -939,6 +982,7 @@ public class AdvancedSearch { } return false; } + @Override public boolean apply(Set inputs, List values) { if (inputs != null) { @@ -959,6 +1003,7 @@ public class AdvancedSearch { } return false; } + @Override public boolean apply(Set inputs, List values) { if (inputs != null) { @@ -977,6 +1022,7 @@ public class AdvancedSearch { public boolean apply(Object input, List values) { throw new RuntimeException("shouldn't be called with a single input"); } + @Override public boolean apply(Set inputs, List values) { if (inputs != null) { @@ -994,6 +1040,7 @@ public class AdvancedSearch { public boolean apply(Object input, List values) { throw new RuntimeException("shouldn't be called with a single input"); } + @Override public boolean apply(Set inputs, List values) { if (inputs != null) { @@ -1030,32 +1077,32 @@ public class AdvancedSearch { } }); - public static final FilterOperator[] BOOLEAN_OPS = new FilterOperator[] { - IS_TRUE, IS_FALSE + public static final FilterOperator[] BOOLEAN_OPS = new FilterOperator[]{ + IS_TRUE, IS_FALSE }; - 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 + 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 }; - public static final FilterOperator[] STRING_OPS = new FilterOperator[] { - CONTAINS, STARTS_WITH, ENDS_WITH + public static final FilterOperator[] STRING_OPS = new FilterOperator[]{ + CONTAINS, STARTS_WITH, ENDS_WITH }; - public static final FilterOperator[] STRINGS_OPS = new FilterOperator[] { - CONTAINS, STARTS_WITH, ENDS_WITH + public static final FilterOperator[] STRINGS_OPS = new FilterOperator[]{ + CONTAINS, STARTS_WITH, ENDS_WITH }; - public static final FilterOperator[] SINGLE_LIST_OPS = new FilterOperator[] { - IS_ANY + public static final FilterOperator[] SINGLE_LIST_OPS = new FilterOperator[]{ + IS_ANY }; - public static final FilterOperator[] MULTI_LIST_OPS = new FilterOperator[] { - IS_ANY + public static final FilterOperator[] MULTI_LIST_OPS = new FilterOperator[]{ + IS_ANY }; - public static final FilterOperator[] COMBINATION_OPS = new FilterOperator[] { - IS_EXACTLY, CONTAINS_ANY, CONTAINS_ALL + public static final FilterOperator[] COMBINATION_OPS = new FilterOperator[]{ + IS_EXACTLY, CONTAINS_ANY, CONTAINS_ALL }; - public static final FilterOperator[] COLLECTION_OPS = new FilterOperator[] { - CONTAIN_ANY, CONTAIN_ALL + public static final FilterOperator[] COLLECTION_OPS = new FilterOperator[]{ + CONTAIN_ANY, CONTAIN_ALL }; - public static final FilterOperator[] DECK_CONTENT_OPS = new FilterOperator[] { - CONTAINS_CARD, CONTAINS_X_COPIES_OF_CARD + public static final FilterOperator[] DECK_CONTENT_OPS = new FilterOperator[]{ + CONTAINS_CARD, CONTAINS_X_COPIES_OF_CARD }; private final String caption, formatStr; @@ -1104,8 +1151,8 @@ public class AdvancedSearch { final OperatorEvaluator evaluator = (OperatorEvaluator) operator.evaluator; Predicate predicate = input -> evaluator.apply(getItemValue(input), values); - final FilterOperator[][] manyValueOperators = { FilterOperator.MULTI_LIST_OPS, - FilterOperator.COMBINATION_OPS, FilterOperator.COLLECTION_OPS, FilterOperator.STRINGS_OPS }; + final FilterOperator[][] manyValueOperators = {FilterOperator.MULTI_LIST_OPS, + FilterOperator.COMBINATION_OPS, FilterOperator.COLLECTION_OPS, FilterOperator.STRINGS_OPS}; for (FilterOperator[] oper : manyValueOperators) { if (option.operatorOptions == oper) { predicate = input -> evaluator.apply(getItemValues(input), values); @@ -1125,8 +1172,7 @@ public class AdvancedSearch { final List values; try { values = getValuesFromString(initialValueText, option, operator); - } - catch(Exception e) { + } catch (Exception e) { e.printStackTrace(); return null; } @@ -1134,8 +1180,11 @@ public class AdvancedSearch { } protected abstract List getValues(FilterOption option, FilterOperator operator); + protected abstract List getValuesFromString(String valueText, FilterOption option, FilterOperator operator); + protected abstract String getCaption(List values, FilterOption option, FilterOperator operator); + protected abstract V getItemValue(T input); protected Set getItemValues(T input) { //available for options that have multiple inputs @@ -1178,12 +1227,13 @@ public class AdvancedSearch { String message; if (operator.valueCount == FilterValueCount.ONE) { message = option.name + " " + operator.caption + " ?"; - } - else { + } else { message = "? " + operator.caption.replace("|", " " + option.name + " "); } Integer lowerBound = SGuiChoose.getInteger(message, min, max); - if (lowerBound == null) { return null; } + if (lowerBound == null) { + return null; + } final List values = new ArrayList<>(); values.add(lowerBound); @@ -1195,7 +1245,9 @@ public class AdvancedSearch { upperBoundMin += 2; //if exclusive, ensure it's possible to have numbers in between } Integer upperBound = SGuiChoose.getInteger(message, upperBoundMin, max); - if (upperBound == null) { return null; } + if (upperBound == null) { + return null; + } values.add(upperBound); } @@ -1226,7 +1278,9 @@ public class AdvancedSearch { protected List getValues(FilterOption option, FilterOperator operator) { String message = option.name + " " + operator.caption + " ?"; String value = SOptionPane.showInputDialog("", message, null, initialInput); - if (value == null) { return null; } + if (value == null) { + return null; + } initialInput = value; //store value as initial input for next time @@ -1253,9 +1307,11 @@ public class AdvancedSearch { public CustomListEvaluator(Collection choices0) { this(choices0, null, null); } + public CustomListEvaluator(Collection choices0, Function toShortString0) { this(choices0, toShortString0, null); } + public CustomListEvaluator(Collection choices0, Function toShortString0, Function toLongString0) { choices = choices0; toShortString = toShortString0; @@ -1276,9 +1332,9 @@ public class AdvancedSearch { } private boolean eitherStringMatches(V choice, String name) { - if(toLongString != null && name.equals(toLongString.apply(choice))) + if (toLongString != null && name.equals(toLongString.apply(choice))) return true; - if(toShortString != null) + if (toShortString != null) return name.equals(toShortString.apply(choice)); return name.equals(choice.toString()); } @@ -1287,16 +1343,16 @@ public class AdvancedSearch { protected String getCaption(List values, FilterOption option, FilterOperator operator) { String valuesStr; switch (operator.valueCount) { - case MANY: - valuesStr = formatValues(values, " ", " "); - break; - case MANY_OR: - valuesStr = formatValues(values, ", ", " or "); - break; - case MANY_AND: - default: - valuesStr = formatValues(values, ", ", " and "); - break; + case MANY: + valuesStr = formatValues(values, " ", " "); + break; + case MANY_OR: + valuesStr = formatValues(values, ", ", " or "); + break; + case MANY_AND: + default: + valuesStr = formatValues(values, ", ", " and "); + break; } return String.format(operator.formatStr, option.name, valuesStr); } @@ -1304,18 +1360,18 @@ public class AdvancedSearch { protected String formatValues(List values, String delim, String finalDelim) { int valueCount = values.size(); switch (valueCount) { - case 1: - return formatValue(values.get(0)); - case 2: - return formatValue(values.get(0)) + finalDelim + formatValue(values.get(1)); - default: - int lastValueIdx = valueCount - 1; - StringBuilder result = new StringBuilder(formatValue(values.get(0))); - for (int i = 1; i < lastValueIdx; i++) { - result.append(delim).append(formatValue(values.get(i))); - } - result.append(delim.trim()).append(finalDelim).append(formatValue(values.get(lastValueIdx))); - return result.toString(); + case 1: + return formatValue(values.get(0)); + case 2: + return formatValue(values.get(0)) + finalDelim + formatValue(values.get(1)); + default: + int lastValueIdx = valueCount - 1; + StringBuilder result = new StringBuilder(formatValue(values.get(0))); + for (int i = 1; i < lastValueIdx; i++) { + result.append(delim).append(formatValue(values.get(i))); + } + result.append(delim.trim()).append(finalDelim).append(formatValue(values.get(lastValueIdx))); + return result.toString(); } } @@ -1350,12 +1406,16 @@ public class AdvancedSearch { protected List> getValues(FilterOption option, FilterOperator operator) { String message = option.name + " " + operator.caption + " ?"; PaperCard card = SGuiChoose.oneOrNone(message, FModel.getMagicDb().getCommonCards().getUniqueCards()); - if (card == null) { return null; } + if (card == null) { + return null; + } Integer amount = -1; if (operator == FilterOperator.CONTAINS_X_COPIES_OF_CARD) { //prompt for quantity if needed amount = SGuiChoose.getInteger(Localizer.getInstance().getMessage("lblHowManyCopiesOfN", CardTranslation.getTranslatedName(card.getName())), 0, 4); - if (amount == null) { return null; } + if (amount == null) { + return null; + } } Map map = new HashMap<>(); @@ -1370,13 +1430,12 @@ public class AdvancedSearch { protected List> getValuesFromString(String valueText, FilterOption option, FilterOperator operator) { int amount = -1; String cardName; - if(operator == FilterOperator.CONTAINS_X_COPIES_OF_CARD) { + if (operator == FilterOperator.CONTAINS_X_COPIES_OF_CARD) { //Take the format "2 Mountain" String[] split = valueText.split(" ", 2); amount = Integer.parseInt(split[0]); cardName = split[1]; - } - else + } else cardName = valueText; Map map = new HashMap<>(); map.put(cardName, amount); @@ -1412,25 +1471,29 @@ public class AdvancedSearch { } } option = SGuiChoose.oneOrNone(Localizer.getInstance().getMessage("lblSelectAFilterType"), options, defaultOption, null); - if (option == null) { return editFilter; } - } - else { + if (option == null) { + return editFilter; + } + } else { option = defaultOption; } - if (option == FilterOption.NONE) { return null; } //allow user to clear filter by selecting "(none)" + if (option == FilterOption.NONE) { + return null; + } //allow user to clear filter by selecting "(none)" final FilterOperator operator; if (option.operatorOptions.length > 1) { final FilterOperator defaultOperator = option == defaultOption ? editFilter.operator : null; operator = SGuiChoose.oneOrNone(Localizer.getInstance().getMessage("lblSelectOperatorFor", option.name), option.operatorOptions, defaultOperator, null); - if (operator == null) { return editFilter; } - } - else { + if (operator == null) { + return editFilter; + } + } else { operator = option.operatorOptions[0]; } - Filter filter = (Filter)option.evaluator.createFilter(option, operator); + Filter filter = (Filter) option.evaluator.createFilter(option, operator); if (filter == null) { filter = editFilter; } @@ -1440,8 +1503,7 @@ public class AdvancedSearch { @SuppressWarnings("unchecked") public static Filter getFilter(Class type, String filterText) { String[] words = filterText.split(" ", 3); - if(words.length < 2) - { + if (words.length < 2) { System.out.printf("Unable to generate filter from expression '%s'%n", filterText); return null; } @@ -1454,8 +1516,7 @@ public class AdvancedSearch { System.out.printf("Unable to generate filter from FilterOption '%s'%n", words[0]); return null; } - if(option.type != type) - { + if (option.type != type) { System.out.printf("Unable to generate filter from FilterOption '%s' - filter type '%s' != option type '%s' %n", words[0], type, option.type); return null; } @@ -1515,14 +1576,23 @@ public class AdvancedSearch { public interface IFilterControl { IButton getBtnNotBeforeParen(); + IButton getBtnOpenParen(); + IButton getBtnNotAfterParen(); + IButton getBtnFilter(); + IButton getBtnCloseParen(); + IButton getBtnAnd(); + IButton getBtnOr(); + Filter getFilter(); + void setFilter(Filter filter0); + Class getGenericType(); } @@ -1554,23 +1624,18 @@ public class AdvancedSearch { Object piece = iterator.get(); if (piece.equals(Operator.OPEN_PAREN)) { predPiece = getPredicatePiece(iterator.next()); - } - else if (piece.equals(Operator.CLOSE_PAREN)) { + } else if (piece.equals(Operator.CLOSE_PAREN)) { return pred; - } - else if (piece.equals(Operator.AND)) { + } else if (piece.equals(Operator.AND)) { operator = Operator.AND; continue; - } - else if (piece.equals(Operator.OR)) { + } else if (piece.equals(Operator.OR)) { operator = Operator.OR; continue; - } - else if (piece.equals(Operator.NOT)) { + } else if (piece.equals(Operator.NOT)) { applyNot = !applyNot; continue; - } - else { + } else { predPiece = ((AdvancedSearch.Filter) piece).getPredicate(); } if (applyNot) { @@ -1579,11 +1644,9 @@ public class AdvancedSearch { } if (pred == null) { pred = predPiece; - } - else if (operator == Operator.AND) { + } else if (operator == Operator.AND) { pred = pred.and(predPiece); - } - else if (operator == Operator.OR) { + } else if (operator == Operator.OR) { pred = pred.or(predPiece); } operator = null; @@ -1626,16 +1689,7 @@ public class AdvancedSearch { control.setFilter(filter); if (filter != null) { control.getBtnFilter().setText(GuiBase.getInterface().encodeSymbols(filter.toString(), false)); - - if (filter.getOption() == FilterOption.CARD_KEYWORDS) { - //the first time the user selects keywords, preload keywords for all cards - Runnable preloadTask = Keyword.getPreloadTask(); - if (preloadTask != null) { - GuiBase.getInterface().runBackgroundTask(Localizer.getInstance().getMessage("lblLoadingKeywords"), preloadTask); - } - } - } - else { + } else { control.getBtnFilter().setText(EMPTY_FILTER_TEXT); } if (onChange != null) { @@ -1657,32 +1711,31 @@ public class AdvancedSearch { @SuppressWarnings("unchecked") public void updateLabel() { - if (label == null) { return; } + if (label == null) { + return; + } StringBuilder builder = new StringBuilder(); builder.append("Filter: "); if (expression.isEmpty()) { builder.append("(none)"); - } - else { + } else { int prevFilterEndIdx = -1; AdvancedSearch.Filter filter, prevFilter = null; for (Object piece : expression) { if (piece instanceof AdvancedSearch.Filter) { - filter = (AdvancedSearch.Filter)piece; + filter = (AdvancedSearch.Filter) piece; if (filter.canMergeCaptionWith(prevFilter)) { //convert boolean operators between filters to lowercase builder.replace(prevFilterEndIdx, builder.length(), builder.substring(prevFilterEndIdx).toLowerCase()); //append only values for filter builder.append(filter.extractValuesFromCaption()); - } - else { + } else { builder.append(filter); } prevFilter = filter; prevFilterEndIdx = builder.length(); - } - else { + } else { if (piece.equals(Operator.OPEN_PAREN) || piece.equals(Operator.CLOSE_PAREN)) { prevFilter = null; //prevent merging filters with parentheses in between } @@ -1695,7 +1748,9 @@ public class AdvancedSearch { } public String getTooltip() { - if (expression.isEmpty()) { return ""; } + if (expression.isEmpty()) { + return ""; + } StringBuilder builder = new StringBuilder(); builder.append("Filter:\n"); @@ -1718,7 +1773,9 @@ public class AdvancedSearch { expression.clear(); for (IFilterControl control : controls) { - if (control.getFilter() == null) { continue; } //skip any blank filters + if (control.getFilter() == null) { + continue; + } //skip any blank filters if (control.getBtnNotBeforeParen().isSelected()) { expression.add(Operator.NOT); @@ -1737,8 +1794,7 @@ public class AdvancedSearch { } if (control.getBtnAnd().isSelected()) { expression.add(Operator.AND); - } - else if (control.getBtnOr().isSelected()) { + } else if (control.getBtnOr().isSelected()) { expression.add(Operator.OR); } } @@ -1748,13 +1804,16 @@ public class AdvancedSearch { private class ExpressionIterator { private int index; + private boolean hasNext() { return index < expression.size(); } + private ExpressionIterator next() { index++; return this; } + private Object get() { return expression.get(index); } From 1dbd358c1944a3d732186e3d6a2cf204b5da4ff7 Mon Sep 17 00:00:00 2001 From: Anthony Calosa Date: Thu, 11 Sep 2025 19:01:59 +0800 Subject: [PATCH 2/2] fix to include main face --- forge-gui/src/main/java/forge/itemmanager/AdvancedSearch.java | 1 - 1 file changed, 1 deletion(-) diff --git a/forge-gui/src/main/java/forge/itemmanager/AdvancedSearch.java b/forge-gui/src/main/java/forge/itemmanager/AdvancedSearch.java index 37ed9f18eed..da523205006 100644 --- a/forge-gui/src/main/java/forge/itemmanager/AdvancedSearch.java +++ b/forge-gui/src/main/java/forge/itemmanager/AdvancedSearch.java @@ -115,7 +115,6 @@ public class AdvancedSearch { } } } - return keywords; } if (input.getRules().getMainPart().getKeywords() != null) { for (String key : input.getRules().getMainPart().getKeywords()) {