Made facets deal with java.util.Collection rather than just Object[].
Documented the browsing.* packages. git-svn-id: http://google-refine.googlecode.com/svn/trunk@330 7d457c2a-affb-35e4-300a-418c747d4874
This commit is contained in:
parent
d90e75dff1
commit
7648126a5e
@ -7,6 +7,10 @@ import com.metaweb.gridworks.browsing.filters.RowFilter;
|
|||||||
import com.metaweb.gridworks.model.Project;
|
import com.metaweb.gridworks.model.Project;
|
||||||
import com.metaweb.gridworks.model.Row;
|
import com.metaweb.gridworks.model.Row;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Encapsulate logic for visiting rows that match all give row filters. Also visit
|
||||||
|
* context rows and dependent rows if configured so.
|
||||||
|
*/
|
||||||
public class ConjunctiveFilteredRows implements FilteredRows {
|
public class ConjunctiveFilteredRows implements FilteredRows {
|
||||||
final protected List<RowFilter> _rowFilters = new LinkedList<RowFilter>();
|
final protected List<RowFilter> _rowFilters = new LinkedList<RowFilter>();
|
||||||
final protected boolean _includeContextual;
|
final protected boolean _includeContextual;
|
||||||
@ -22,61 +26,67 @@ public class ConjunctiveFilteredRows implements FilteredRows {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void accept(Project project, RowVisitor visitor) {
|
public void accept(Project project, RowVisitor visitor) {
|
||||||
int lastVisitedRow = -1;
|
int lastVisitedRowRowIndex = -1;
|
||||||
int lastRecordRowAccepted = -1;
|
int lastRecordRowAcceptedRowIndex = -1;
|
||||||
|
|
||||||
int c = project.rows.size();
|
int c = project.rows.size();
|
||||||
for (int i = 0; i < c; i++) {
|
for (int rowIndex = 0; rowIndex < c; rowIndex++) {
|
||||||
Row row = project.rows.get(i);
|
Row row = project.rows.get(rowIndex);
|
||||||
|
|
||||||
if (checkRow(project, i, row)) {
|
if (matchRow(project, rowIndex, row)) {
|
||||||
if (row.recordIndex >= 0) {
|
if (row.recordIndex >= 0) {
|
||||||
// this is a record row itself
|
lastRecordRowAcceptedRowIndex = rowIndex; // this is a record row itself
|
||||||
|
|
||||||
lastRecordRowAccepted = i;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
visitRow(project, visitor, i, row, lastVisitedRow);
|
visitRow(project, visitor, rowIndex, row, lastVisitedRowRowIndex);
|
||||||
|
|
||||||
lastVisitedRow = i;
|
lastVisitedRowRowIndex = rowIndex;
|
||||||
} else if (
|
} else if (
|
||||||
|
// this row doesn't match by itself but ...
|
||||||
|
// we want to include dependent rows
|
||||||
|
|
||||||
_includeDependent &&
|
_includeDependent &&
|
||||||
|
// and this row is a dependent row since it's not a record row
|
||||||
row.recordIndex < 0 &&
|
row.recordIndex < 0 &&
|
||||||
row.contextRows != null &&
|
row.contextRows != null &&
|
||||||
row.contextRows.size() > 0) {
|
row.contextRows.size() > 0
|
||||||
|
) {
|
||||||
|
|
||||||
if (row.contextRows.get(0) == lastRecordRowAccepted) {
|
if (row.contextRows.get(0) == lastRecordRowAcceptedRowIndex) {
|
||||||
visitor.visit(project, i, row, false, true);
|
// this row depends on the last previously matched record row,
|
||||||
lastVisitedRow = i;
|
// so we visit it as well as a dependent row
|
||||||
|
|
||||||
|
visitor.visit(project, rowIndex, row, false, true);
|
||||||
|
lastVisitedRowRowIndex = rowIndex;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void visitRow(Project project, RowVisitor visitor, int rowIndex, Row row, int lastVisitedRow) {
|
protected void visitRow(Project project, RowVisitor visitor, int rowIndex, Row row, int lastVisitedRow) {
|
||||||
if (_includeContextual) {
|
if (_includeContextual && // we need to include any context row and
|
||||||
if (row.contextRows != null && lastVisitedRow < rowIndex - 1) {
|
row.contextRows != null && // this row itself isn't a context row and
|
||||||
for (int contextRowIndex : row.contextRows) {
|
lastVisitedRow < rowIndex - 1 // there is definitely some rows before this row
|
||||||
if (contextRowIndex > lastVisitedRow) {
|
// that we haven't visited yet
|
||||||
visitor.visit(
|
) {
|
||||||
project,
|
for (int contextRowIndex : row.contextRows) {
|
||||||
contextRowIndex,
|
if (contextRowIndex > lastVisitedRow) {
|
||||||
project.rows.get(contextRowIndex),
|
visitor.visit(
|
||||||
true,
|
project,
|
||||||
false
|
contextRowIndex,
|
||||||
);
|
project.rows.get(contextRowIndex),
|
||||||
lastVisitedRow = contextRowIndex;
|
true, // is visited as a context row
|
||||||
}
|
false // is not visited as a dependent row
|
||||||
|
);
|
||||||
|
lastVisitedRow = contextRowIndex;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
visitor.visit(project, rowIndex, row, false, false);
|
|
||||||
} else {
|
|
||||||
visitor.visit(project, rowIndex, row, false, false);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
visitor.visit(project, rowIndex, row, false, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected boolean checkRow(Project project, int rowIndex, Row row) {
|
protected boolean matchRow(Project project, int rowIndex, Row row) {
|
||||||
for (RowFilter rowFilter : _rowFilters) {
|
for (RowFilter rowFilter : _rowFilters) {
|
||||||
if (!rowFilter.filterRow(project, rowIndex, row)) {
|
if (!rowFilter.filterRow(project, rowIndex, row)) {
|
||||||
return false;
|
return false;
|
||||||
|
@ -7,9 +7,16 @@ import org.json.JSONWriter;
|
|||||||
|
|
||||||
import com.metaweb.gridworks.Jsonizable;
|
import com.metaweb.gridworks.Jsonizable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Store a value and its text label, in case the value is not a string itself.
|
||||||
|
* For instance, if a value is a date, then its label can be one particular
|
||||||
|
* rendering of that date.
|
||||||
|
*
|
||||||
|
* Facet choices that are presented to the user as text are stored as decorated values.
|
||||||
|
*/
|
||||||
public class DecoratedValue implements Jsonizable {
|
public class DecoratedValue implements Jsonizable {
|
||||||
final public Object value;
|
final public Object value;
|
||||||
final public String label;
|
final public String label;
|
||||||
|
|
||||||
public DecoratedValue(Object value, String label) {
|
public DecoratedValue(Object value, String label) {
|
||||||
this.value = value;
|
this.value = value;
|
||||||
|
@ -17,6 +17,9 @@ import com.metaweb.gridworks.browsing.facets.TextSearchFacet;
|
|||||||
import com.metaweb.gridworks.browsing.filters.RowFilter;
|
import com.metaweb.gridworks.browsing.filters.RowFilter;
|
||||||
import com.metaweb.gridworks.model.Project;
|
import com.metaweb.gridworks.model.Project;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Faceted browsing engine.
|
||||||
|
*/
|
||||||
public class Engine implements Jsonizable {
|
public class Engine implements Jsonizable {
|
||||||
protected Project _project;
|
protected Project _project;
|
||||||
protected List<Facet> _facets = new LinkedList<Facet>();
|
protected List<Facet> _facets = new LinkedList<Facet>();
|
||||||
|
@ -2,6 +2,18 @@ package com.metaweb.gridworks.browsing;
|
|||||||
|
|
||||||
import com.metaweb.gridworks.model.Project;
|
import com.metaweb.gridworks.model.Project;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Interface for anything that can decide which rows match and which rows don't match
|
||||||
|
* based on some particular criteria.
|
||||||
|
*/
|
||||||
public interface FilteredRows {
|
public interface FilteredRows {
|
||||||
|
/**
|
||||||
|
* Go through the rows of the given project, determine which match and which don't,
|
||||||
|
* and call visitor.visit() on those that match, and possibly their context and
|
||||||
|
* dependent rows.
|
||||||
|
*
|
||||||
|
* @param project
|
||||||
|
* @param visitor
|
||||||
|
*/
|
||||||
public void accept(Project project, RowVisitor visitor);
|
public void accept(Project project, RowVisitor visitor);
|
||||||
}
|
}
|
||||||
|
@ -3,12 +3,20 @@ package com.metaweb.gridworks.browsing;
|
|||||||
import com.metaweb.gridworks.model.Project;
|
import com.metaweb.gridworks.model.Project;
|
||||||
import com.metaweb.gridworks.model.Row;
|
import com.metaweb.gridworks.model.Row;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Interface for visiting rows one by one. The rows visited are only those that match some
|
||||||
|
* particular criteria, such as facets' constraints, or those that are related to the matched
|
||||||
|
* rows. The related rows can be those that the matched rows depend on, or those that depend
|
||||||
|
* on the matched rows.
|
||||||
|
*/
|
||||||
public interface RowVisitor {
|
public interface RowVisitor {
|
||||||
public boolean visit(
|
public boolean visit(
|
||||||
Project project,
|
Project project,
|
||||||
int rowIndex, // zero-based row index
|
int rowIndex, // zero-based row index
|
||||||
Row row,
|
Row row,
|
||||||
boolean contextual, // true if this row is included because it's the context row of an included row
|
boolean contextual, // true if this row is included because it's the context row
|
||||||
boolean dependent // true if this row is included because it depends on an included row
|
// of a matched row, that is, a matched row depends on it
|
||||||
|
boolean dependent // true if this row is included because it depends on a matched row,
|
||||||
|
// that is, it depends on a matched row
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
package com.metaweb.gridworks.browsing.facets;
|
package com.metaweb.gridworks.browsing.facets;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Properties;
|
import java.util.Properties;
|
||||||
@ -12,10 +13,20 @@ import com.metaweb.gridworks.model.Cell;
|
|||||||
import com.metaweb.gridworks.model.Project;
|
import com.metaweb.gridworks.model.Project;
|
||||||
import com.metaweb.gridworks.model.Row;
|
import com.metaweb.gridworks.model.Row;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Visit matched rows and group them into facet choices based on the values computed
|
||||||
|
* from a given expression.
|
||||||
|
*/
|
||||||
public class ExpressionNominalRowGrouper implements RowVisitor {
|
public class ExpressionNominalRowGrouper implements RowVisitor {
|
||||||
|
/*
|
||||||
|
* Configuration
|
||||||
|
*/
|
||||||
final protected Evaluable _evaluable;
|
final protected Evaluable _evaluable;
|
||||||
final protected int _cellIndex;
|
final protected int _cellIndex;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Computed results
|
||||||
|
*/
|
||||||
final public Map<Object, NominalFacetChoice> choices = new HashMap<Object, NominalFacetChoice>();
|
final public Map<Object, NominalFacetChoice> choices = new HashMap<Object, NominalFacetChoice>();
|
||||||
public int blankCount = 0;
|
public int blankCount = 0;
|
||||||
public int errorCount = 0;
|
public int errorCount = 0;
|
||||||
@ -32,14 +43,22 @@ public class ExpressionNominalRowGrouper implements RowVisitor {
|
|||||||
ExpressionUtils.bind(bindings, row, rowIndex, cell);
|
ExpressionUtils.bind(bindings, row, rowIndex, cell);
|
||||||
|
|
||||||
Object value = _evaluable.evaluate(bindings);
|
Object value = _evaluable.evaluate(bindings);
|
||||||
if (value != null && value.getClass().isArray()) {
|
if (value != null) {
|
||||||
Object[] a = (Object[]) value;
|
if (value.getClass().isArray()) {
|
||||||
for (Object v : a) {
|
Object[] a = (Object[]) value;
|
||||||
processValue(v);
|
for (Object v : a) {
|
||||||
}
|
processValue(v);
|
||||||
} else {
|
}
|
||||||
processValue(value);
|
return false;
|
||||||
|
} else if (value instanceof Collection<?>) {
|
||||||
|
for (Object v : ExpressionUtils.toObjectCollection(value)) {
|
||||||
|
processValue(v);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
} // else, fall through
|
||||||
}
|
}
|
||||||
|
|
||||||
|
processValue(value);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
package com.metaweb.gridworks.browsing.facets;
|
package com.metaweb.gridworks.browsing.facets;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
import java.util.Properties;
|
import java.util.Properties;
|
||||||
|
|
||||||
import com.metaweb.gridworks.browsing.RowVisitor;
|
import com.metaweb.gridworks.browsing.RowVisitor;
|
||||||
@ -9,13 +10,22 @@ import com.metaweb.gridworks.model.Cell;
|
|||||||
import com.metaweb.gridworks.model.Project;
|
import com.metaweb.gridworks.model.Project;
|
||||||
import com.metaweb.gridworks.model.Row;
|
import com.metaweb.gridworks.model.Row;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Visit matched rows and slot them into bins based on the numbers computed
|
||||||
|
* from a given expression.
|
||||||
|
*/
|
||||||
public class ExpressionNumericRowBinner implements RowVisitor {
|
public class ExpressionNumericRowBinner implements RowVisitor {
|
||||||
|
/*
|
||||||
|
* Configuration
|
||||||
|
*/
|
||||||
final protected Evaluable _evaluable;
|
final protected Evaluable _evaluable;
|
||||||
final protected int _cellIndex;
|
final protected int _cellIndex;
|
||||||
final protected NumericBinIndex _index;
|
final protected NumericBinIndex _index; // base bins
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Computed results
|
||||||
|
*/
|
||||||
final public int[] bins;
|
final public int[] bins;
|
||||||
|
|
||||||
public int numericCount;
|
public int numericCount;
|
||||||
public int nonNumericCount;
|
public int nonNumericCount;
|
||||||
public int blankCount;
|
public int blankCount;
|
||||||
@ -35,14 +45,22 @@ public class ExpressionNumericRowBinner implements RowVisitor {
|
|||||||
ExpressionUtils.bind(bindings, row, rowIndex, cell);
|
ExpressionUtils.bind(bindings, row, rowIndex, cell);
|
||||||
|
|
||||||
Object value = _evaluable.evaluate(bindings);
|
Object value = _evaluable.evaluate(bindings);
|
||||||
if (value != null && value.getClass().isArray()) {
|
if (value != null) {
|
||||||
Object[] a = (Object[]) value;
|
if (value.getClass().isArray()) {
|
||||||
for (Object v : a) {
|
Object[] a = (Object[]) value;
|
||||||
processValue(v);
|
for (Object v : a) {
|
||||||
}
|
processValue(v);
|
||||||
} else {
|
}
|
||||||
processValue(value);
|
return false;
|
||||||
|
} else if (value instanceof Collection<?>) {
|
||||||
|
for (Object v : ExpressionUtils.toObjectCollection(value)) {
|
||||||
|
processValue(v);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
} // else, fall through
|
||||||
}
|
}
|
||||||
|
|
||||||
|
processValue(value);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -7,6 +7,9 @@ import com.metaweb.gridworks.browsing.FilteredRows;
|
|||||||
import com.metaweb.gridworks.browsing.filters.RowFilter;
|
import com.metaweb.gridworks.browsing.filters.RowFilter;
|
||||||
import com.metaweb.gridworks.model.Project;
|
import com.metaweb.gridworks.model.Project;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Interface of facets.
|
||||||
|
*/
|
||||||
public interface Facet extends Jsonizable {
|
public interface Facet extends Jsonizable {
|
||||||
public RowFilter getRowFilter();
|
public RowFilter getRowFilter();
|
||||||
|
|
||||||
|
@ -21,24 +21,31 @@ import com.metaweb.gridworks.model.Project;
|
|||||||
import com.metaweb.gridworks.util.JSONUtilities;
|
import com.metaweb.gridworks.util.JSONUtilities;
|
||||||
|
|
||||||
public class ListFacet implements Facet {
|
public class ListFacet implements Facet {
|
||||||
protected List<NominalFacetChoice> _selection = new LinkedList<NominalFacetChoice>();
|
/*
|
||||||
|
* Configuration
|
||||||
|
*/
|
||||||
|
protected String _name;
|
||||||
|
protected String _expression;
|
||||||
|
protected String _columnName;
|
||||||
|
|
||||||
// If true, then facet won't show the blank and error choices
|
// If true, then facet won't show the blank and error choices
|
||||||
protected boolean _omitBlank;
|
protected boolean _omitBlank;
|
||||||
protected boolean _omitError;
|
protected boolean _omitError;
|
||||||
|
|
||||||
|
protected List<NominalFacetChoice> _selection = new LinkedList<NominalFacetChoice>();
|
||||||
protected boolean _selectBlank;
|
protected boolean _selectBlank;
|
||||||
protected boolean _selectError;
|
protected boolean _selectError;
|
||||||
|
|
||||||
protected String _name;
|
/*
|
||||||
protected String _expression;
|
* Derived configuration
|
||||||
protected String _columnName;
|
*/
|
||||||
|
|
||||||
protected int _cellIndex;
|
protected int _cellIndex;
|
||||||
protected Evaluable _eval;
|
protected Evaluable _eval;
|
||||||
protected String _errorMessage;
|
protected String _errorMessage;
|
||||||
|
|
||||||
// computed
|
/*
|
||||||
|
* Computed results
|
||||||
|
*/
|
||||||
protected List<NominalFacetChoice> _choices = new LinkedList<NominalFacetChoice>();
|
protected List<NominalFacetChoice> _choices = new LinkedList<NominalFacetChoice>();
|
||||||
protected int _blankCount;
|
protected int _blankCount;
|
||||||
protected int _errorCount;
|
protected int _errorCount;
|
||||||
@ -157,9 +164,20 @@ public class ListFacet implements Facet {
|
|||||||
|
|
||||||
for (NominalFacetChoice choice : _selection) {
|
for (NominalFacetChoice choice : _selection) {
|
||||||
String valueString = choice.decoratedValue.value.toString();
|
String valueString = choice.decoratedValue.value.toString();
|
||||||
|
|
||||||
if (grouper.choices.containsKey(valueString)) {
|
if (grouper.choices.containsKey(valueString)) {
|
||||||
grouper.choices.get(valueString).selected = true;
|
grouper.choices.get(valueString).selected = true;
|
||||||
} else {
|
} else {
|
||||||
|
/*
|
||||||
|
* A selected choice can have zero count if it is selected together
|
||||||
|
* with other choices, and some other facets' constraints eliminate
|
||||||
|
* all rows projected to this choice altogether. For example, if you
|
||||||
|
* select both "car" and "bicycle" in the "type of vehicle" facet, and
|
||||||
|
* then constrain the "wheels" facet to more than 2, then the "bicycle"
|
||||||
|
* choice now has zero count even if it's still selected. The grouper
|
||||||
|
* won't be able to detect the "bicycle" choice, so we need to inject
|
||||||
|
* that choice into the choice list ourselves.
|
||||||
|
*/
|
||||||
choice.count = 0;
|
choice.count = 0;
|
||||||
_choices.add(choice);
|
_choices.add(choice);
|
||||||
}
|
}
|
||||||
|
@ -8,6 +8,10 @@ import org.json.JSONWriter;
|
|||||||
import com.metaweb.gridworks.Jsonizable;
|
import com.metaweb.gridworks.Jsonizable;
|
||||||
import com.metaweb.gridworks.browsing.DecoratedValue;
|
import com.metaweb.gridworks.browsing.DecoratedValue;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Store a facet choice that has a decorated value, a count of matched rows,
|
||||||
|
* and a flag of whether it has been selected.
|
||||||
|
*/
|
||||||
public class NominalFacetChoice implements Jsonizable {
|
public class NominalFacetChoice implements Jsonizable {
|
||||||
final public DecoratedValue decoratedValue;
|
final public DecoratedValue decoratedValue;
|
||||||
public int count;
|
public int count;
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package com.metaweb.gridworks.browsing.facets;
|
package com.metaweb.gridworks.browsing.facets;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collection;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Properties;
|
import java.util.Properties;
|
||||||
|
|
||||||
@ -10,6 +11,16 @@ import com.metaweb.gridworks.model.Cell;
|
|||||||
import com.metaweb.gridworks.model.Project;
|
import com.metaweb.gridworks.model.Project;
|
||||||
import com.metaweb.gridworks.model.Row;
|
import com.metaweb.gridworks.model.Row;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A utility class for computing the base bins that form the base histograms of
|
||||||
|
* numeric range facets. It evaluates an expression on all the rows of a project to
|
||||||
|
* get numeric values, determines how many bins to distribute those values in, and
|
||||||
|
* bins the rows accordingly.
|
||||||
|
*
|
||||||
|
* This class processes all rows rather than just the filtered rows because it
|
||||||
|
* needs to compute the base bins of a numeric range facet, which remain unchanged
|
||||||
|
* as the user interacts with the facet.
|
||||||
|
*/
|
||||||
public class NumericBinIndex {
|
public class NumericBinIndex {
|
||||||
private double _min;
|
private double _min;
|
||||||
private double _max;
|
private double _max;
|
||||||
@ -38,6 +49,12 @@ public class NumericBinIndex {
|
|||||||
processValue(((Number) v).doubleValue(), allValues);
|
processValue(((Number) v).doubleValue(), allValues);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} else if (value instanceof Collection<?>) {
|
||||||
|
for (Object v : ExpressionUtils.toObjectCollection(value)) {
|
||||||
|
if (v instanceof Number) {
|
||||||
|
processValue(((Number) v).doubleValue(), allValues);
|
||||||
|
}
|
||||||
|
}
|
||||||
} else if (value instanceof Number) {
|
} else if (value instanceof Number) {
|
||||||
processValue(((Number) value).doubleValue(), allValues);
|
processValue(((Number) value).doubleValue(), allValues);
|
||||||
}
|
}
|
||||||
|
@ -17,33 +17,45 @@ import com.metaweb.gridworks.model.Project;
|
|||||||
import com.metaweb.gridworks.util.JSONUtilities;
|
import com.metaweb.gridworks.util.JSONUtilities;
|
||||||
|
|
||||||
public class RangeFacet implements Facet {
|
public class RangeFacet implements Facet {
|
||||||
protected String _name;
|
/*
|
||||||
protected String _expression;
|
* Configuration, from the client side
|
||||||
protected String _columnName;
|
*/
|
||||||
|
protected String _name; // name of facet
|
||||||
|
protected String _expression; // expression to compute numeric value(s) per row
|
||||||
|
protected String _columnName; // column to base expression on, if any
|
||||||
|
protected String _mode; // "range", "min", "max"
|
||||||
|
|
||||||
|
protected double _from; // the numeric selection
|
||||||
|
protected double _to;
|
||||||
|
|
||||||
|
protected boolean _selectNumeric; // whether the numeric selection applies, default true
|
||||||
|
protected boolean _selectNonNumeric;
|
||||||
|
protected boolean _selectBlank;
|
||||||
|
protected boolean _selectError;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Derived configuration data
|
||||||
|
*/
|
||||||
protected int _cellIndex;
|
protected int _cellIndex;
|
||||||
protected Evaluable _eval;
|
protected Evaluable _eval;
|
||||||
protected String _errorMessage;
|
protected String _errorMessage;
|
||||||
|
protected boolean _selected; // false if we're certain that all rows will match
|
||||||
|
// and there isn't any filtering to do
|
||||||
|
|
||||||
protected String _mode;
|
/*
|
||||||
|
* Computed data, to return to the client side
|
||||||
|
*/
|
||||||
protected double _min;
|
protected double _min;
|
||||||
protected double _max;
|
protected double _max;
|
||||||
protected double _step;
|
protected double _step;
|
||||||
protected int[] _baseBins;
|
protected int[] _baseBins;
|
||||||
protected int[] _bins;
|
protected int[] _bins;
|
||||||
|
|
||||||
protected int _numericCount;
|
protected int _numericCount;
|
||||||
protected int _nonNumericCount;
|
protected int _nonNumericCount;
|
||||||
protected int _blankCount;
|
protected int _blankCount;
|
||||||
protected int _errorCount;
|
protected int _errorCount;
|
||||||
|
|
||||||
protected double _from;
|
|
||||||
protected double _to;
|
|
||||||
protected boolean _selected;
|
|
||||||
protected boolean _selectNumeric;
|
|
||||||
protected boolean _selectNonNumeric;
|
|
||||||
protected boolean _selectBlank;
|
|
||||||
protected boolean _selectError;
|
|
||||||
|
|
||||||
public RangeFacet() {
|
public RangeFacet() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -15,15 +15,21 @@ import com.metaweb.gridworks.gel.ast.VariableExpr;
|
|||||||
import com.metaweb.gridworks.model.Project;
|
import com.metaweb.gridworks.model.Project;
|
||||||
|
|
||||||
public class TextSearchFacet implements Facet {
|
public class TextSearchFacet implements Facet {
|
||||||
|
/*
|
||||||
|
* Configuration
|
||||||
|
*/
|
||||||
protected String _name;
|
protected String _name;
|
||||||
protected String _columnName;
|
protected String _columnName;
|
||||||
protected int _cellIndex;
|
|
||||||
protected String _query;
|
protected String _query;
|
||||||
protected Pattern _pattern;
|
|
||||||
|
|
||||||
protected String _mode;
|
protected String _mode;
|
||||||
protected boolean _caseSensitive;
|
protected boolean _caseSensitive;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Derived configuration
|
||||||
|
*/
|
||||||
|
protected int _cellIndex;
|
||||||
|
protected Pattern _pattern;
|
||||||
|
|
||||||
public TextSearchFacet() {
|
public TextSearchFacet() {
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -42,6 +48,7 @@ public class TextSearchFacet implements Facet {
|
|||||||
public void initializeFromJSON(Project project, JSONObject o) throws Exception {
|
public void initializeFromJSON(Project project, JSONObject o) throws Exception {
|
||||||
_name = o.getString("name");
|
_name = o.getString("name");
|
||||||
_columnName = o.getString("columnName");
|
_columnName = o.getString("columnName");
|
||||||
|
|
||||||
_cellIndex = project.columnModel.getColumnByName(_columnName).getCellIndex();
|
_cellIndex = project.columnModel.getColumnByName(_columnName).getCellIndex();
|
||||||
|
|
||||||
if (!o.isNull("query")) {
|
if (!o.isNull("query")) {
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
package com.metaweb.gridworks.browsing.filters;
|
package com.metaweb.gridworks.browsing.filters;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
import java.util.Properties;
|
import java.util.Properties;
|
||||||
|
|
||||||
import com.metaweb.gridworks.expr.Evaluable;
|
import com.metaweb.gridworks.expr.Evaluable;
|
||||||
@ -8,14 +9,28 @@ import com.metaweb.gridworks.model.Cell;
|
|||||||
import com.metaweb.gridworks.model.Project;
|
import com.metaweb.gridworks.model.Project;
|
||||||
import com.metaweb.gridworks.model.Row;
|
import com.metaweb.gridworks.model.Row;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Judge if a row matches by evaluating a given expression on the row, based on a particular
|
||||||
|
* column, and checking the result. It's a match if the result is any one of a given list of
|
||||||
|
* values, or if the result is blank or error and we want blank or error values.
|
||||||
|
*/
|
||||||
public class ExpressionEqualRowFilter implements RowFilter {
|
public class ExpressionEqualRowFilter implements RowFilter {
|
||||||
final protected Evaluable _evaluable;
|
final protected Evaluable _evaluable; // the expression to evaluate
|
||||||
final protected int _cellIndex;
|
final protected int _cellIndex; // the expression is based on this column;
|
||||||
|
// -1 if based on no column in particular,
|
||||||
|
// for expression such as "row.starred".
|
||||||
|
|
||||||
final protected Object[] _matches;
|
final protected Object[] _matches;
|
||||||
final protected boolean _selectBlank;
|
final protected boolean _selectBlank;
|
||||||
final protected boolean _selectError;
|
final protected boolean _selectError;
|
||||||
|
|
||||||
public ExpressionEqualRowFilter(Evaluable evaluable, int cellIndex, Object[] matches, boolean selectBlank, boolean selectError) {
|
public ExpressionEqualRowFilter(
|
||||||
|
Evaluable evaluable,
|
||||||
|
int cellIndex,
|
||||||
|
Object[] matches,
|
||||||
|
boolean selectBlank,
|
||||||
|
boolean selectError
|
||||||
|
) {
|
||||||
_evaluable = evaluable;
|
_evaluable = evaluable;
|
||||||
_cellIndex = cellIndex;
|
_cellIndex = cellIndex;
|
||||||
_matches = matches;
|
_matches = matches;
|
||||||
@ -30,17 +45,26 @@ public class ExpressionEqualRowFilter implements RowFilter {
|
|||||||
ExpressionUtils.bind(bindings, row, rowIndex, cell);
|
ExpressionUtils.bind(bindings, row, rowIndex, cell);
|
||||||
|
|
||||||
Object value = _evaluable.evaluate(bindings);
|
Object value = _evaluable.evaluate(bindings);
|
||||||
if (value != null && value.getClass().isArray()) {
|
if (value != null) {
|
||||||
Object[] a = (Object[]) value;
|
if (value.getClass().isArray()) {
|
||||||
for (Object v : a) {
|
Object[] a = (Object[]) value;
|
||||||
if (testValue(v)) {
|
for (Object v : a) {
|
||||||
return true;
|
if (testValue(v)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
return false;
|
||||||
} else {
|
} else if (value instanceof Collection<?>) {
|
||||||
return testValue(value);
|
for (Object v : ExpressionUtils.toObjectCollection(value)) {
|
||||||
|
if (testValue(v)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
} // else, fall through
|
||||||
}
|
}
|
||||||
return false;
|
|
||||||
|
return testValue(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected boolean testValue(Object v) {
|
protected boolean testValue(Object v) {
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
package com.metaweb.gridworks.browsing.filters;
|
package com.metaweb.gridworks.browsing.filters;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
import java.util.Properties;
|
import java.util.Properties;
|
||||||
|
|
||||||
import com.metaweb.gridworks.expr.Evaluable;
|
import com.metaweb.gridworks.expr.Evaluable;
|
||||||
@ -8,6 +9,12 @@ import com.metaweb.gridworks.model.Cell;
|
|||||||
import com.metaweb.gridworks.model.Project;
|
import com.metaweb.gridworks.model.Project;
|
||||||
import com.metaweb.gridworks.model.Row;
|
import com.metaweb.gridworks.model.Row;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Judge if a row matches by evaluating a given expression on the row, based on a particular
|
||||||
|
* column, and checking the result. It's a match if the result satisfies some numeric comparisons,
|
||||||
|
* or if the result is non-numeric or blank or error and we want non-numeric or blank or error
|
||||||
|
* values.
|
||||||
|
*/
|
||||||
abstract public class ExpressionNumberComparisonRowFilter implements RowFilter {
|
abstract public class ExpressionNumberComparisonRowFilter implements RowFilter {
|
||||||
final protected Evaluable _evaluable;
|
final protected Evaluable _evaluable;
|
||||||
final protected int _cellIndex;
|
final protected int _cellIndex;
|
||||||
@ -33,25 +40,32 @@ abstract public class ExpressionNumberComparisonRowFilter implements RowFilter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public boolean filterRow(Project project, int rowIndex, Row row) {
|
public boolean filterRow(Project project, int rowIndex, Row row) {
|
||||||
Cell cell = row.getCell(_cellIndex);
|
Cell cell = _cellIndex < 0 ? null : row.getCell(_cellIndex);
|
||||||
|
|
||||||
Properties bindings = ExpressionUtils.createBindings(project);
|
Properties bindings = ExpressionUtils.createBindings(project);
|
||||||
ExpressionUtils.bind(bindings, row, rowIndex, cell);
|
ExpressionUtils.bind(bindings, row, rowIndex, cell);
|
||||||
|
|
||||||
Object value = _evaluable.evaluate(bindings);
|
Object value = _evaluable.evaluate(bindings);
|
||||||
if (value != null && value.getClass().isArray()) {
|
if (value != null) {
|
||||||
Object[] a = (Object[]) value;
|
if (value.getClass().isArray()) {
|
||||||
for (Object v : a) {
|
Object[] a = (Object[]) value;
|
||||||
if (checkValue(v)) {
|
for (Object v : a) {
|
||||||
return true;
|
if (checkValue(v)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
return false;
|
||||||
} else {
|
} else if (value instanceof Collection<?>) {
|
||||||
if (checkValue(value)) {
|
for (Object v : ExpressionUtils.toObjectCollection(value)) {
|
||||||
return true;
|
if (checkValue(v)) {
|
||||||
}
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
} // else, fall through
|
||||||
}
|
}
|
||||||
return false;
|
|
||||||
|
return checkValue(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected boolean checkValue(Object v) {
|
protected boolean checkValue(Object v) {
|
||||||
|
@ -8,9 +8,13 @@ import com.metaweb.gridworks.model.Cell;
|
|||||||
import com.metaweb.gridworks.model.Project;
|
import com.metaweb.gridworks.model.Project;
|
||||||
import com.metaweb.gridworks.model.Row;
|
import com.metaweb.gridworks.model.Row;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Judge if a row matches by evaluating a given expression on the row, based on a particular
|
||||||
|
* column, and checking the result. It's a match if the result satisfies some string comparisons.
|
||||||
|
*/
|
||||||
abstract public class ExpressionStringComparisonRowFilter implements RowFilter {
|
abstract public class ExpressionStringComparisonRowFilter implements RowFilter {
|
||||||
final protected Evaluable _evaluable;
|
final protected Evaluable _evaluable;
|
||||||
final protected int _cellIndex;
|
final protected int _cellIndex;
|
||||||
|
|
||||||
public ExpressionStringComparisonRowFilter(Evaluable evaluable, int cellIndex) {
|
public ExpressionStringComparisonRowFilter(Evaluable evaluable, int cellIndex) {
|
||||||
_evaluable = evaluable;
|
_evaluable = evaluable;
|
||||||
@ -18,7 +22,8 @@ abstract public class ExpressionStringComparisonRowFilter implements RowFilter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public boolean filterRow(Project project, int rowIndex, Row row) {
|
public boolean filterRow(Project project, int rowIndex, Row row) {
|
||||||
Cell cell = row.getCell(_cellIndex);
|
Cell cell = _cellIndex < 0 ? null : row.getCell(_cellIndex);
|
||||||
|
|
||||||
Properties bindings = ExpressionUtils.createBindings(project);
|
Properties bindings = ExpressionUtils.createBindings(project);
|
||||||
ExpressionUtils.bind(bindings, row, rowIndex, cell);
|
ExpressionUtils.bind(bindings, row, rowIndex, cell);
|
||||||
|
|
||||||
|
@ -3,6 +3,10 @@ package com.metaweb.gridworks.browsing.filters;
|
|||||||
import com.metaweb.gridworks.model.Project;
|
import com.metaweb.gridworks.model.Project;
|
||||||
import com.metaweb.gridworks.model.Row;
|
import com.metaweb.gridworks.model.Row;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Interface for judging if a particular row matches or doesn't match some
|
||||||
|
* particular criterion, such as a facet constraint.
|
||||||
|
*/
|
||||||
public interface RowFilter {
|
public interface RowFilter {
|
||||||
public boolean filterRow(Project project, int rowIndex, Row row);
|
public boolean filterRow(Project project, int rowIndex, Row row);
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user