Make it faster to edit existing filters

This commit is contained in:
drdev
2015-09-05 20:40:42 +00:00
parent c2fd7790f7
commit 703fecdefd
3 changed files with 105 additions and 71 deletions

View File

@@ -253,7 +253,7 @@ public class AdvancedSearchFilter<T extends InventoryItem> extends ItemFilter<T>
FThreads.invokeInBackgroundThread(new Runnable() { FThreads.invokeInBackgroundThread(new Runnable() {
@Override @Override
public void run() { public void run() {
final AdvancedSearch.Filter<T> newFilter = AdvancedSearch.getFilter(itemManager.getGenericType()); final AdvancedSearch.Filter<T> newFilter = AdvancedSearch.getFilter(itemManager.getGenericType(), filter);
if (newFilter != null) { if (newFilter != null) {
FThreads.invokeInEdtLater(new Runnable() { FThreads.invokeInEdtLater(new Runnable() {
@Override @Override

View File

@@ -4,8 +4,8 @@ import java.util.Arrays;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
import java.util.List; import java.util.List;
import com.google.common.base.Function;
import org.apache.commons.lang3.StringUtils; import com.google.common.base.Predicate;
import forge.card.CardEdition; import forge.card.CardEdition;
import forge.card.CardRarity; import forge.card.CardRarity;
@@ -22,7 +22,7 @@ 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 StringValueSelector()),
CARD_RULES_TEXT("Rules Text", PaperCard.class, FilterOperator.STRING_OPS, new StringValueSelector()), CARD_RULES_TEXT("Rules Text", PaperCard.class, FilterOperator.STRING_OPS, new StringValueSelector()),
CARD_EXPANSION("Expansion", PaperCard.class, FilterOperator.SINGLE_LIST_OPS, new CustomListValueSelector<CardEdition>(FModel.getMagicDb().getSortedEditions())), CARD_SET("Set", PaperCard.class, FilterOperator.SINGLE_LIST_OPS, new CustomListValueSelector<CardEdition>(FModel.getMagicDb().getSortedEditions(), CardEdition.FN_GET_CODE)),
CARD_FORMAT("Format", PaperCard.class, FilterOperator.SINGLE_LIST_OPS, new CustomListValueSelector<GameFormat>((List<GameFormat>)FModel.getFormats().getOrderedList())), CARD_FORMAT("Format", PaperCard.class, FilterOperator.SINGLE_LIST_OPS, new CustomListValueSelector<GameFormat>((List<GameFormat>)FModel.getFormats().getOrderedList())),
CARD_COLOR("Color", PaperCard.class, FilterOperator.MULTI_LIST_OPS, new CustomListValueSelector<String>(MagicColor.Constant.COLORS_AND_COLORLESS)), 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_TYPE("Type", PaperCard.class, FilterOperator.MULTI_LIST_OPS, new CustomListValueSelector<String>(CardType.getSortedCoreAndSuperTypes())),
@@ -37,9 +37,9 @@ public class AdvancedSearch {
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 FilterValueSelector valueSelector;
private FilterOption(String name0, Class<? extends InventoryItem> type0, FilterOperator[] operatorOptions0, FilterValueSelector<?> valueSelector0) { private FilterOption(String name0, Class<? extends InventoryItem> type0, FilterOperator[] operatorOptions0, FilterValueSelector valueSelector0) {
name = name0; name = name0;
type = type0; type = type0;
operatorOptions = operatorOptions0; operatorOptions = operatorOptions0;
@@ -114,11 +114,11 @@ public class AdvancedSearch {
MANY_AND MANY_AND
} }
private static abstract class FilterValueSelector<T> { private static abstract class FilterValueSelector {
public abstract List<T> getValues(String message, FilterOption option, FilterOperator operator); public abstract <T extends InventoryItem> Filter<T> createFilter(String message, FilterOption option, FilterOperator operator);
} }
private static class NumericValueSelector extends FilterValueSelector<Integer> { private static class NumericValueSelector extends FilterValueSelector {
private final int min, max; private final int min, max;
public NumericValueSelector(int min0, int max0) { public NumericValueSelector(int min0, int max0) {
@@ -127,7 +127,7 @@ public class AdvancedSearch {
} }
@Override @Override
public List<Integer> getValues(String message, FilterOption option, FilterOperator operator) { public <T extends InventoryItem> Filter<T> createFilter(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,55 +135,111 @@ 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; }
List<Integer> values = new ArrayList<Integer>(); final String caption;
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; }
values.add(upperBound);
caption = String.format(operator.formatStr, option.name, lowerBound, upperBound);
} }
return values; else {
caption = String.format(operator.formatStr, option.name, lowerBound);
}
return new Filter<T>(option, operator, caption, null);
} }
} }
private static class StringValueSelector extends FilterValueSelector<String> { private static class StringValueSelector extends FilterValueSelector {
public StringValueSelector() { public StringValueSelector() {
} }
@Override @Override
public List<String> getValues(String message, FilterOption option, FilterOperator operator) { public <T extends InventoryItem> Filter<T> createFilter(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; }
List<String> values = new ArrayList<String>(); final String caption = String.format(operator.formatStr, option.name, value);
values.add(value);
return values; return new Filter<T>(option, operator, caption, null);
} }
} }
private static class CustomListValueSelector<T> extends FilterValueSelector<T> { private static class CustomListValueSelector<V> extends FilterValueSelector {
private final Collection<T> choices; private final Collection<V> choices;
private final Function<V, String> toShortString, toLongString;
public CustomListValueSelector(Collection<T> choices0) { public CustomListValueSelector(Collection<V> choices0) {
this(choices0, null, null);
}
public CustomListValueSelector(Collection<V> choices0, Function<V, String> toShortString0) {
this(choices0, toShortString0, null);
}
public CustomListValueSelector(Collection<V> choices0, Function<V, String> toShortString0, Function<V, String> toLongString0) {
choices = choices0; choices = choices0;
toShortString = toShortString0;
toLongString = toLongString0;
} }
@Override @Override
public List<T> getValues(String message, FilterOption option, FilterOperator operator) { public <T extends InventoryItem> Filter<T> createFilter(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<T> values = SGuiChoose.getChoices(message, 0, max, choices); List<V> values = SGuiChoose.getChoices(message, 0, max, choices);
if (values == null || values.isEmpty()) { if (values == null || values.isEmpty()) {
return null; return null;
} }
return values;
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;
}
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) {
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;
String result = formatValue(values.get(0));
for (int i = 1; i < lastValueIdx; i++) {
result += delim + formatValue(values.get(i));
}
result += delim.trim() + finalDelim + formatValue(values.get(lastValueIdx));
return result;
}
}
private String formatValue(V value) {
if (toShortString == null) {
return value.toString();
}
return toShortString.apply(value);
} }
} }
public static <T extends InventoryItem> Filter<T> getFilter(Class<? super T> type) { 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>();
for (FilterOption opt : FilterOption.values()) { for (FilterOption opt : FilterOption.values()) {
@@ -192,66 +248,38 @@ public class AdvancedSearch {
} }
} }
final FilterOption option = SGuiChoose.oneOrNone("Select a filter type", options); final FilterOption defaultOption = editFilter == null ? null : editFilter.option;
final FilterOption option = SGuiChoose.oneOrNone("Select a filter type", options, defaultOption, null);
if (option == null) { return null; } if (option == null) { return null; }
final FilterOperator operator = SGuiChoose.oneOrNone("Select an operator for " + option.name, option.operatorOptions); final FilterOperator defaultOperator = option == defaultOption ? editFilter.operator : null;
final FilterOperator operator = SGuiChoose.oneOrNone("Select an operator for " + option.name, option.operatorOptions, defaultOperator, null);
if (operator == null) { return null; } if (operator == null) { return null; }
final String message = option.name + " " + operator.caption + " ?"; final String message = option.name + " " + operator.caption + " ?";
final List<?> values = option.valueSelector.getValues(message, option, operator); return option.valueSelector.createFilter(message, option, operator);
if (values == null) { return null; }
return new Filter<T>(option, operator, values);
} }
public static class Filter<T extends InventoryItem> { public static class Filter<T extends InventoryItem> {
private final FilterOption option; private final FilterOption option;
private final FilterOperator operator; private final FilterOperator operator;
private final List<?> values;
private final String caption; private final String caption;
private final Predicate<T> predicate;
private Filter(FilterOption option0, FilterOperator operator0, List<?> values0) { private Filter(FilterOption option0, FilterOperator operator0, String caption0, Predicate<T> predicate0) {
option = option0; option = option0;
operator = operator0; operator = operator0;
values = values0; caption = caption0;
predicate = predicate0;
}
switch (operator.valueCount) { public Predicate<T> getPredicate() {
case ONE: return predicate;
caption = String.format(operator.formatStr, option.name, values.get(0));
break;
case TWO:
caption = String.format(operator.formatStr, option.name, values.get(0), values.get(1));
break;
case MANY:
caption = String.format(operator.formatStr, option.name, StringUtils.join(values, ", "));
break;
case MANY_OR:
caption = String.format(operator.formatStr, option.name, formatValues(", ", "or"));
break;
case MANY_AND:
default:
caption = String.format(operator.formatStr, option.name, formatValues(", ", "and"));
break;
}
} }
@Override @Override
public String toString() { public String toString() {
return caption; return caption;
} }
private String formatValues(String delim, String finalDelim) {
switch (values.size()) {
case 1:
return values.get(0).toString();
case 2:
return values.get(0) + " " + finalDelim + " " + values.get(1);
default:
String result = StringUtils.join(values, delim);
int index = result.lastIndexOf(delim) + delim.length();
return result.substring(0, index) + finalDelim + " " + result.substring(index);
}
}
} }
} }

View File

@@ -29,18 +29,23 @@ public class SGuiChoose {
* @see #getChoices(String, int, int, Object...) * @see #getChoices(String, int, int, Object...)
*/ */
public static <T> T oneOrNone(final String message, final T[] choices) { public static <T> T oneOrNone(final String message, final T[] choices) {
return oneOrNone(message, choices, null, null);
}
public static <T> T oneOrNone(final String message, final T[] choices, T selected, Function<T, String> display) {
if ((choices == null) || (choices.length == 0)) { if ((choices == null) || (choices.length == 0)) {
return null; return null;
} }
final List<T> choice = SGuiChoose.getChoices(message, 0, 1, choices); final List<T> choice = SGuiChoose.getChoices(message, 0, 1, choices, selected, display);
return choice.isEmpty() ? null : choice.get(0); return choice.isEmpty() ? null : choice.get(0);
} }
public static <T> T oneOrNone(final String message, final Collection<T> choices) { public static <T> T oneOrNone(final String message, final Collection<T> choices) {
return oneOrNone(message, choices, null, null);
}
public static <T> T oneOrNone(final String message, final Collection<T> choices, T selected, Function<T, String> display) {
if ((choices == null) || choices.isEmpty()) { if ((choices == null) || choices.isEmpty()) {
return null; return null;
} }
final List<T> choice = SGuiChoose.getChoices(message, 0, 1, choices); final List<T> choice = SGuiChoose.getChoices(message, 0, 1, choices, selected, display);
return choice.isEmpty() ? null : choice.get(0); return choice.isEmpty() ? null : choice.get(0);
} }
@@ -143,11 +148,12 @@ public class SGuiChoose {
public static <T> List<T> getChoices(final String message, final int min, final int max, final T[] choices) { public static <T> List<T> getChoices(final String message, final int min, final int max, final T[] choices) {
return getChoices(message, min, max, Arrays.asList(choices), null, null); return getChoices(message, min, max, Arrays.asList(choices), null, null);
} }
public static <T> List<T> getChoices(final String message, final int min, final int max, final T[] choices, final T selected, final Function<T, String> display) {
return getChoices(message, min, max, Arrays.asList(choices), selected, display);
}
public static <T> List<T> getChoices(final String message, final int min, final int max, final Collection<T> choices) { public static <T> List<T> getChoices(final String message, final int min, final int max, final Collection<T> choices) {
return getChoices(message, min, max, choices, null, null); return getChoices(message, min, max, choices, null, null);
} }
public static <T> List<T> getChoices(final String message, final int min, final int max, final Collection<T> choices, final T selected, final Function<T, String> display) { public static <T> List<T> getChoices(final String message, final int min, final int max, final Collection<T> choices, final T selected, final Function<T, String> display) {
return GuiBase.getInterface().getChoices(message, min, max, choices, selected, display); return GuiBase.getInterface().getChoices(message, min, max, choices, selected, display);
} }