ca.odell.glazedlists.matchers.ThresholdMatcherEditor Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of glazedlists_java15 Show documentation
Show all versions of glazedlists_java15 Show documentation
Event-driven lists for dynamically filtered and sorted tables
The newest version!
/* Glazed Lists (c) 2003-2006 */
/* http://publicobject.com/glazedlists/ publicobject.com,*/
/* O'Dell Engineering Ltd.*/
/* StarLight Systems */
package ca.odell.glazedlists.matchers;
import ca.odell.glazedlists.FunctionList;
import ca.odell.glazedlists.GlazedLists;
import ca.odell.glazedlists.impl.GlazedListsImpl;
import java.util.Comparator;
/**
* A {@link MatcherEditor} that filters elements based on whether they are
* greater than or less than a threshold. The implementation is based on
* elements implementing {@link Comparable} unless the constructor specifies
* a {@link Comparator}.
*
* By default the elements themselves are compared with the threshold value,
* however, an optional Function can be provided which can be used to extract
* a value that is appropriate for comparison with the threshold. In this way,
* ThreshholdMatcherEditor provides a level of indirection when locating the
* exact value to compare for a given element.
*
* @author Rob Eden
*/
public class ThresholdMatcherEditor extends AbstractMatcherEditor {
public static final MatchOperation GREATER_THAN = new MatchOperation(1, false);
public static final MatchOperation GREATER_THAN_OR_EQUAL = new MatchOperation(1, true);
public static final MatchOperation LESS_THAN = new MatchOperation(-1, false);
public static final MatchOperation LESS_THAN_OR_EQUAL = new MatchOperation(-1, true);
public static final MatchOperation EQUAL = new MatchOperation(0, true);
public static final MatchOperation NOT_EQUAL = new MatchOperation(0, false);
private MatchOperation currentMatcher;
private Comparator comparator;
private MatchOperation operation;
private T threshold;
private FunctionList.Function function;
/**
* Construct an instance that will require elements to be greater than the
* threshold (which is not initially set) and relies on the threshold
* object and elements in the list implementing {@link Comparable}.
*/
public ThresholdMatcherEditor() {
this(null);
}
/**
* Construct an instance that will require elements to be greater than the
* given threshold and relies on the threshold object and elements in the
* list implementing {@link Comparable}.
*
* @param threshold the initial threshold, or null if none.
*/
public ThresholdMatcherEditor(T threshold) {
this(threshold, null);
}
/**
* Construct an instance that will require elements to be greater than the
* given threshold and relies on the threshold object and elements in the
* list implementing {@link Comparable}.
*
* @param threshold the initial threshold, or null if none.
* @param operation the operation to determine what relation list elements
* should have to the threshold in order to match (i.e., be visible).
* Specifying null will use {@link #GREATER_THAN}.
*/
public ThresholdMatcherEditor(T threshold, MatchOperation operation) {
this(threshold, operation, null);
}
/**
* Construct an instance.
*
* @param threshold rhe initial threshold, or null if none.
* @param operation rhe operation to determine what relation list elements
* should have to the threshold in order to match (i.e., be visible).
* Specifying null will use {@link #GREATER_THAN}.
* @param comparator determines how objects compare. If null, the threshold
* object and list elements must implement {@link Comparable}.
*/
public ThresholdMatcherEditor(T threshold, MatchOperation operation, Comparator comparator) {
this(threshold, operation, comparator, null);
}
/**
* Construct an instance.
*
* @param threshold the initial threshold, or null if none.
* @param operation the operation to determine what relation list elements
* should have to the threshold in order to match (i.e., be visible).
* Specifying null will use {@link #GREATER_THAN}.
* @param comparator determines how objects compare with the threshold value.
* If null, the threshold object and list elements must implement
* {@link Comparable}.
* @param function an optional Function which produces a value fit to be
* compared against the threshold. This argument is optional, and if
* it is null, the raw values will compared against the
* threshold.
*/
public ThresholdMatcherEditor(T threshold, MatchOperation operation, Comparator comparator, FunctionList.Function function) {
if (operation == null) operation = GREATER_THAN;
if (comparator == null) comparator = (Comparator) GlazedLists.comparableComparator();
if (function == null) function = (FunctionList.Function) GlazedListsImpl.identityFunction();
this.operation = operation;
this.comparator = comparator;
this.threshold = threshold;
this.function = function;
// if this is our first matcher, it's automatically a constrain
currentMatcher = operation.instance(comparator, threshold, function);
fireChanged(currentMatcher);
}
/**
* Update the threshold used to determine what is matched by the list. This coupled
* with the {@link #setMatchOperation match operation} determines what's matched.
*
* @param threshold The threshold, or null to match everything.
*/
public void setThreshold(T threshold) {
this.threshold = threshold;
rebuildMatcher();
}
/**
* See {@link #getThreshold()}.
*/
public T getThreshold() {
return threshold;
}
/**
* Update the operation used to determine what relation list elements should
* have to the threshold in order to match (i.e. be visible). Must be non-null.
*
* @see #GREATER_THAN
* @see #GREATER_THAN_OR_EQUAL
* @see #LESS_THAN
* @see #LESS_THAN_OR_EQUAL
* @see #EQUAL
* @see #NOT_EQUAL
*/
public void setMatchOperation(MatchOperation operation) {
if (operation == null)
throw new IllegalArgumentException("Operation cannot be null");
this.operation = operation;
rebuildMatcher();
}
/**
* See {@link #setMatchOperation}.
*/
public MatchOperation getMatchOperation() {
return operation;
}
/**
* Update the comparator. Setting to null will require that thresholds and elements in
* the list implement {@link Comparable}.
*/
public void setComparator(Comparator comparator) {
if (comparator == null) comparator = (Comparator) GlazedLists.comparableComparator();
this.comparator = comparator;
rebuildMatcher();
}
public Comparator getComparator() { return comparator; }
/** {@inheritDoc} */
private void rebuildMatcher() {
final MatchOperation newMatcher = operation.instance(comparator, threshold, function);
// otherwise test how the matchers relate
final boolean moreStrict = newMatcher.isMoreStrict(currentMatcher);
final boolean lessStrict = currentMatcher.isMoreStrict(newMatcher);
// if they're equal we're done and we won't change the matcher
if (!moreStrict && !lessStrict)
return;
// otherwise, fire the appropriate event
currentMatcher = newMatcher;
if (moreStrict && lessStrict)
fireChanged(currentMatcher);
else if (moreStrict)
fireConstrained(currentMatcher);
else
fireRelaxed(currentMatcher);
}
/**
* A {@link MatchOperation} serves as both a {@link Matcher} in and of itself
* and as an enumerated type representing its type as an operation.
*/
private static class MatchOperation implements Matcher {
/** the comparator to compare values against */
protected final Comparator comparator;
/** the pivot value to compare with */
protected final T threshold;
/** either 1 for greater, 0 for equal, or -1 for less than */
private final int polarity;
/** either true for equal or false for not equal */
private final boolean inclusive;
/** a function which produces a comparable value for a given element */
private final FunctionList.Function function;
private MatchOperation(Comparator comparator, T threshold, int polarity, boolean inclusive, FunctionList.Function function) {
this.comparator = comparator;
this.threshold = threshold;
this.polarity = polarity;
this.inclusive = inclusive;
this.function = function;
}
private MatchOperation(int polarity, boolean inclusive) {
this(null, null, polarity, inclusive, (FunctionList.Function) GlazedListsImpl.identityFunction());
}
/**
* Factory method to create a {@link MatchOperation} of the same type
* as this {@link MatchOperation}.
*/
private MatchOperation instance(Comparator comparator, T threshold, FunctionList.Function function) {
return new MatchOperation(comparator, threshold, polarity, inclusive, function);
}
/**
* Compare this to another {@link MatchOperation}.
*
* @return true if there exists some Object i such that this.matches(i)
* is false
when other.matches(i) is
* true
. Two MatcherOperations can be mutually more
* strict than each other.
*/
boolean isMoreStrict(MatchOperation other) {
if(other.polarity != polarity) return true;
if(other.comparator != comparator) return true;
if(other.threshold == threshold) {
if(polarity == 0) return other.inclusive != inclusive;
else return (other.inclusive && !inclusive);
} else {
if(polarity == 0) return true;
else if(!matchesThreshold(other.threshold)) return true;
}
return false;
}
/** {@inheritDoc} */
public boolean matches(E item) {
return matchesThreshold(function.evaluate(item));
}
public boolean matchesThreshold(T t) {
// compare the extracted value with the threshold
final int compareResult = comparator.compare(t, threshold);
// item equals threshold, match <=, == and >=
if(compareResult == 0) return inclusive;
// for == and !=, handle the case when the item is not equal to threshold
if(polarity == 0) return !inclusive;
// item is below threshold and match <, <= or item is above and match >, >=
return ((compareResult < 0) == (polarity < 0));
}
}
}