More row/record model refactoring work. Everything should still be working almost as before, except contextual rows are not shown in row-based mode.
git-svn-id: http://google-refine.googlecode.com/svn/trunk@823 7d457c2a-affb-35e4-300a-418c747d4874
This commit is contained in:
parent
ec7ac81246
commit
28ca652dea
@ -0,0 +1,41 @@
|
|||||||
|
package com.metaweb.gridworks.browsing;
|
||||||
|
|
||||||
|
import java.util.LinkedList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import com.metaweb.gridworks.browsing.filters.RecordFilter;
|
||||||
|
import com.metaweb.gridworks.model.Project;
|
||||||
|
import com.metaweb.gridworks.model.Record;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Encapsulate logic for visiting records that match all given record filters.
|
||||||
|
*/
|
||||||
|
public class ConjunctiveFilteredRecords implements FilteredRecords {
|
||||||
|
final protected List<RecordFilter> _recordFilters = new LinkedList<RecordFilter>();
|
||||||
|
|
||||||
|
public void add(RecordFilter recordFilter) {
|
||||||
|
_recordFilters.add(recordFilter);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void accept(Project project, RecordVisitor visitor) {
|
||||||
|
int c = project.recordModel.getRecordCount();
|
||||||
|
for (int r = 0; r < c; r++) {
|
||||||
|
Record record = project.recordModel.getRecord(r);
|
||||||
|
if (matchRecord(project, record)) {
|
||||||
|
if (visitor.visit(project, record)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected boolean matchRecord(Project project, Record record) {
|
||||||
|
for (RecordFilter recordFilter : _recordFilters) {
|
||||||
|
if (!recordFilter.filterRecord(project, record)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
@ -6,7 +6,6 @@ import java.util.List;
|
|||||||
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;
|
||||||
import com.metaweb.gridworks.model.Row;
|
import com.metaweb.gridworks.model.Row;
|
||||||
import com.metaweb.gridworks.model.RecordModel.RowDependency;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Encapsulate logic for visiting rows that match all give row filters. Also visit
|
* Encapsulate logic for visiting rows that match all give row filters. Also visit
|
||||||
@ -14,77 +13,23 @@ import com.metaweb.gridworks.model.RecordModel.RowDependency;
|
|||||||
*/
|
*/
|
||||||
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 _includeDependent;
|
|
||||||
|
|
||||||
public ConjunctiveFilteredRows(boolean includeContextual, boolean includeDependent) {
|
|
||||||
_includeContextual = includeContextual;
|
|
||||||
_includeDependent = includeDependent;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void add(RowFilter rowFilter) {
|
public void add(RowFilter rowFilter) {
|
||||||
_rowFilters.add(rowFilter);
|
_rowFilters.add(rowFilter);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void accept(Project project, RowVisitor visitor) {
|
public void accept(Project project, RowVisitor visitor) {
|
||||||
int lastVisitedRowRowIndex = -1;
|
|
||||||
int lastRecordRowAcceptedRowIndex = -1;
|
|
||||||
|
|
||||||
int c = project.rows.size();
|
int c = project.rows.size();
|
||||||
for (int rowIndex = 0; rowIndex < c; rowIndex++) {
|
for (int rowIndex = 0; rowIndex < c; rowIndex++) {
|
||||||
Row row = project.rows.get(rowIndex);
|
Row row = project.rows.get(rowIndex);
|
||||||
RowDependency rd = project.recordModel.getRowDependency(rowIndex);
|
|
||||||
|
|
||||||
if (matchRow(project, rowIndex, row)) {
|
if (matchRow(project, rowIndex, row)) {
|
||||||
if (rd.recordIndex >= 0) {
|
visitRow(project, visitor, rowIndex, row);
|
||||||
lastRecordRowAcceptedRowIndex = rowIndex; // this is a record row itself
|
|
||||||
}
|
|
||||||
|
|
||||||
visitRow(project, visitor, rowIndex, row, rd, lastVisitedRowRowIndex);
|
|
||||||
|
|
||||||
lastVisitedRowRowIndex = rowIndex;
|
|
||||||
} else if (
|
|
||||||
// this row doesn't match by itself but ...
|
|
||||||
// we want to include dependent rows
|
|
||||||
|
|
||||||
_includeDependent &&
|
|
||||||
// and this row is a dependent row since it's not a record row
|
|
||||||
rd.recordIndex < 0 &&
|
|
||||||
rd.contextRows != null &&
|
|
||||||
rd.contextRows.size() > 0 &&
|
|
||||||
|
|
||||||
rd.contextRows.get(0) == lastRecordRowAcceptedRowIndex
|
|
||||||
) {
|
|
||||||
// this row depends on the last previously matched record row,
|
|
||||||
// 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, RowDependency rd, int lastVisitedRow) {
|
protected void visitRow(Project project, RowVisitor visitor, int rowIndex, Row row) {
|
||||||
if (_includeContextual && // we need to include any context row and
|
visitor.visit(project, rowIndex, row);
|
||||||
rd.contextRows != null && // this row itself isn't a context row and
|
|
||||||
lastVisitedRow < rowIndex - 1 // there is definitely some rows before this row
|
|
||||||
// that we haven't visited yet
|
|
||||||
) {
|
|
||||||
for (int contextRowIndex : rd.contextRows) {
|
|
||||||
if (contextRowIndex > lastVisitedRow) {
|
|
||||||
visitor.visit(
|
|
||||||
project,
|
|
||||||
contextRowIndex,
|
|
||||||
project.rows.get(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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected boolean matchRow(Project project, int rowIndex, Row row) {
|
protected boolean matchRow(Project project, int rowIndex, Row row) {
|
||||||
|
@ -15,42 +15,102 @@ import com.metaweb.gridworks.browsing.facets.ListFacet;
|
|||||||
import com.metaweb.gridworks.browsing.facets.RangeFacet;
|
import com.metaweb.gridworks.browsing.facets.RangeFacet;
|
||||||
import com.metaweb.gridworks.browsing.facets.ScatterplotFacet;
|
import com.metaweb.gridworks.browsing.facets.ScatterplotFacet;
|
||||||
import com.metaweb.gridworks.browsing.facets.TextSearchFacet;
|
import com.metaweb.gridworks.browsing.facets.TextSearchFacet;
|
||||||
|
import com.metaweb.gridworks.browsing.filters.RecordFilter;
|
||||||
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;
|
||||||
|
import com.metaweb.gridworks.model.Row;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Faceted browsing engine.
|
* Faceted browsing engine.
|
||||||
*/
|
*/
|
||||||
public class Engine implements Jsonizable {
|
public class Engine implements Jsonizable {
|
||||||
|
static public enum Mode {
|
||||||
|
RowBased,
|
||||||
|
RecordBased
|
||||||
|
}
|
||||||
|
|
||||||
|
public final static String INCLUDE_DEPENDENT = "includeDependent";
|
||||||
|
public final static String MODE = "mode";
|
||||||
|
public final static String MODE_ROW_BASED = "row-based";
|
||||||
|
public final static String MODE_RECORD_BASED = "record-based";
|
||||||
|
|
||||||
protected Project _project;
|
protected Project _project;
|
||||||
protected List<Facet> _facets = new LinkedList<Facet>();
|
protected List<Facet> _facets = new LinkedList<Facet>();
|
||||||
protected boolean _includeDependent;
|
protected Mode _mode = Mode.RowBased;
|
||||||
|
|
||||||
public final static String INCLUDE_DEPENDENT = "includeDependent";
|
|
||||||
|
|
||||||
public Engine(Project project) {
|
public Engine(Project project) {
|
||||||
_project = project;
|
_project = project;
|
||||||
}
|
}
|
||||||
|
|
||||||
public FilteredRows getAllRows() {
|
public Mode getMode() {
|
||||||
return new ConjunctiveFilteredRows(false, false);
|
return _mode;
|
||||||
}
|
}
|
||||||
|
|
||||||
public FilteredRows getAllFilteredRows(boolean includeContextual) {
|
public FilteredRows getAllRows() {
|
||||||
return getFilteredRows(null, includeContextual);
|
return new FilteredRows() {
|
||||||
|
@Override
|
||||||
|
public void accept(Project project, RowVisitor visitor) {
|
||||||
|
int c = project.rows.size();
|
||||||
|
for (int rowIndex = 0; rowIndex < c; rowIndex++) {
|
||||||
|
Row row = project.rows.get(rowIndex);
|
||||||
|
visitor.visit(project, rowIndex, row);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public FilteredRows getAllFilteredRows() {
|
||||||
|
return getFilteredRows(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
public FilteredRows getFilteredRows(Facet except, boolean includeContextual) {
|
public FilteredRows getFilteredRows(Facet except) {
|
||||||
ConjunctiveFilteredRows cfr = new ConjunctiveFilteredRows(includeContextual, _includeDependent);
|
if (_mode == Mode.RecordBased) {
|
||||||
for (Facet facet : _facets) {
|
return new FilteredRecordsAsFilteredRows(getFilteredRecords(except));
|
||||||
if (facet != except) {
|
} else if (_mode == Mode.RowBased) {
|
||||||
RowFilter rowFilter = facet.getRowFilter();
|
ConjunctiveFilteredRows cfr = new ConjunctiveFilteredRows();
|
||||||
if (rowFilter != null) {
|
for (Facet facet : _facets) {
|
||||||
cfr.add(rowFilter);
|
if (facet != except) {
|
||||||
|
RowFilter rowFilter = facet.getRowFilter();
|
||||||
|
if (rowFilter != null) {
|
||||||
|
cfr.add(rowFilter);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return cfr;
|
||||||
|
}
|
||||||
|
throw new InternalError("Unknown mode.");
|
||||||
|
}
|
||||||
|
|
||||||
|
public FilteredRecords getAllRecords() {
|
||||||
|
return new FilteredRecords() {
|
||||||
|
@Override
|
||||||
|
public void accept(Project project, RecordVisitor visitor) {
|
||||||
|
int c = project.recordModel.getRecordCount();
|
||||||
|
for (int r = 0; r < c; r++) {
|
||||||
|
visitor.visit(project, project.recordModel.getRecord(r));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public FilteredRecords getFilteredRecords() {
|
||||||
|
return getFilteredRecords(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public FilteredRecords getFilteredRecords(Facet except) {
|
||||||
|
if (_mode == Mode.RecordBased) {
|
||||||
|
ConjunctiveFilteredRecords cfr = new ConjunctiveFilteredRecords();
|
||||||
|
for (Facet facet : _facets) {
|
||||||
|
if (facet != except) {
|
||||||
|
RecordFilter recordFilter = facet.getRecordFilter();
|
||||||
|
if (recordFilter != null) {
|
||||||
|
cfr.add(recordFilter);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
return cfr;
|
||||||
return cfr;
|
}
|
||||||
|
throw new InternalError("This method should not be called when the engine is not in record mode.");
|
||||||
}
|
}
|
||||||
|
|
||||||
public void initializeFromJSON(JSONObject o) throws Exception {
|
public void initializeFromJSON(JSONObject o) throws Exception {
|
||||||
@ -84,17 +144,32 @@ public class Engine implements Jsonizable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// for backward compatibility
|
||||||
if (o.has(INCLUDE_DEPENDENT) && !o.isNull(INCLUDE_DEPENDENT)) {
|
if (o.has(INCLUDE_DEPENDENT) && !o.isNull(INCLUDE_DEPENDENT)) {
|
||||||
_includeDependent = o.getBoolean(INCLUDE_DEPENDENT);
|
_mode = o.getBoolean(INCLUDE_DEPENDENT) ? Mode.RecordBased : Mode.RowBased;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (o.has(MODE) && !o.isNull(MODE)) {
|
||||||
|
_mode = MODE_ROW_BASED.equals(o.getString(MODE)) ? Mode.RowBased : Mode.RecordBased;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void computeFacets() throws JSONException {
|
public void computeFacets() throws JSONException {
|
||||||
for (Facet facet : _facets) {
|
if (_mode == Mode.RowBased) {
|
||||||
FilteredRows filteredRows = getFilteredRows(facet, false);
|
for (Facet facet : _facets) {
|
||||||
|
FilteredRows filteredRows = getFilteredRows(facet);
|
||||||
facet.computeChoices(_project, filteredRows);
|
|
||||||
}
|
facet.computeChoices(_project, filteredRows);
|
||||||
|
}
|
||||||
|
} else if (_mode == Mode.RecordBased) {
|
||||||
|
for (Facet facet : _facets) {
|
||||||
|
FilteredRecords filteredRecords = getFilteredRecords(facet);
|
||||||
|
|
||||||
|
facet.computeChoices(_project, filteredRecords);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
throw new InternalError("Unknown mode.");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void write(JSONWriter writer, Properties options)
|
public void write(JSONWriter writer, Properties options)
|
||||||
@ -107,7 +182,7 @@ public class Engine implements Jsonizable {
|
|||||||
facet.write(writer, options);
|
facet.write(writer, options);
|
||||||
}
|
}
|
||||||
writer.endArray();
|
writer.endArray();
|
||||||
writer.key(INCLUDE_DEPENDENT); writer.value(_includeDependent);
|
writer.key(MODE); writer.value(_mode == Mode.RowBased ? MODE_ROW_BASED : MODE_RECORD_BASED);
|
||||||
writer.endObject();
|
writer.endObject();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,18 @@
|
|||||||
|
package com.metaweb.gridworks.browsing;
|
||||||
|
|
||||||
|
import com.metaweb.gridworks.model.Project;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Interface for anything that can decide which records match and which don't
|
||||||
|
* based on some particular criteria.
|
||||||
|
*/
|
||||||
|
public interface FilteredRecords {
|
||||||
|
/**
|
||||||
|
* Go through the records of the given project, determine which match and which don't,
|
||||||
|
* and call visitor.visit() on those that match
|
||||||
|
*
|
||||||
|
* @param project
|
||||||
|
* @param visitor
|
||||||
|
*/
|
||||||
|
public void accept(Project project, RecordVisitor visitor);
|
||||||
|
}
|
@ -0,0 +1,17 @@
|
|||||||
|
package com.metaweb.gridworks.browsing;
|
||||||
|
|
||||||
|
import com.metaweb.gridworks.model.Project;
|
||||||
|
|
||||||
|
public class FilteredRecordsAsFilteredRows implements FilteredRows {
|
||||||
|
final protected FilteredRecords _filteredRecords;
|
||||||
|
|
||||||
|
public FilteredRecordsAsFilteredRows(FilteredRecords filteredRecords) {
|
||||||
|
_filteredRecords = filteredRecords;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void accept(Project project, RowVisitor visitor) {
|
||||||
|
_filteredRecords.accept(project, new RowVisitorAsRecordVisitor(visitor));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,15 @@
|
|||||||
|
package com.metaweb.gridworks.browsing;
|
||||||
|
|
||||||
|
import com.metaweb.gridworks.model.Project;
|
||||||
|
import com.metaweb.gridworks.model.Record;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Interface for visiting records one by one. The records visited are only those that match some
|
||||||
|
* particular criteria, such as facets' constraints.
|
||||||
|
*/
|
||||||
|
public interface RecordVisitor {
|
||||||
|
public boolean visit(
|
||||||
|
Project project,
|
||||||
|
Record record
|
||||||
|
);
|
||||||
|
}
|
@ -5,18 +5,12 @@ import com.metaweb.gridworks.model.Row;
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Interface for visiting rows one by one. The rows visited are only those that match some
|
* 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
|
* particular criteria, such as facets' constraints.
|
||||||
* 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 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
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,22 @@
|
|||||||
|
package com.metaweb.gridworks.browsing;
|
||||||
|
|
||||||
|
import com.metaweb.gridworks.model.Project;
|
||||||
|
import com.metaweb.gridworks.model.Record;
|
||||||
|
|
||||||
|
public class RowVisitorAsRecordVisitor implements RecordVisitor {
|
||||||
|
final protected RowVisitor _rowVisitor;
|
||||||
|
|
||||||
|
public RowVisitorAsRecordVisitor(RowVisitor rowVisitor) {
|
||||||
|
_rowVisitor = rowVisitor;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean visit(Project project, Record record) {
|
||||||
|
for (int r = record.fromRowIndex; r < record.toRowIndex; r++) {
|
||||||
|
if (_rowVisitor.visit(project, r, project.rows.get(r))) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
@ -6,18 +6,29 @@ import java.util.Map;
|
|||||||
import java.util.Properties;
|
import java.util.Properties;
|
||||||
|
|
||||||
import com.metaweb.gridworks.browsing.DecoratedValue;
|
import com.metaweb.gridworks.browsing.DecoratedValue;
|
||||||
|
import com.metaweb.gridworks.browsing.RecordVisitor;
|
||||||
import com.metaweb.gridworks.browsing.RowVisitor;
|
import com.metaweb.gridworks.browsing.RowVisitor;
|
||||||
import com.metaweb.gridworks.expr.Evaluable;
|
import com.metaweb.gridworks.expr.Evaluable;
|
||||||
import com.metaweb.gridworks.expr.ExpressionUtils;
|
import com.metaweb.gridworks.expr.ExpressionUtils;
|
||||||
import com.metaweb.gridworks.model.Cell;
|
import com.metaweb.gridworks.model.Cell;
|
||||||
import com.metaweb.gridworks.model.Project;
|
import com.metaweb.gridworks.model.Project;
|
||||||
|
import com.metaweb.gridworks.model.Record;
|
||||||
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
|
* Visit matched rows and group them into facet choices based on the values computed
|
||||||
* from a given expression.
|
* from a given expression.
|
||||||
*/
|
*/
|
||||||
public class ExpressionNominalRowGrouper implements RowVisitor {
|
public class ExpressionNominalRowGrouper implements RowVisitor, RecordVisitor {
|
||||||
|
static public class IndexedNominalFacetChoice extends NominalFacetChoice {
|
||||||
|
int _latestIndex;
|
||||||
|
|
||||||
|
public IndexedNominalFacetChoice(DecoratedValue decoratedValue, int latestIndex) {
|
||||||
|
super(decoratedValue);
|
||||||
|
_latestIndex = latestIndex;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Configuration
|
* Configuration
|
||||||
*/
|
*/
|
||||||
@ -28,9 +39,11 @@ public class ExpressionNominalRowGrouper implements RowVisitor {
|
|||||||
/*
|
/*
|
||||||
* Computed results
|
* Computed results
|
||||||
*/
|
*/
|
||||||
final public Map<Object, NominalFacetChoice> choices = new HashMap<Object, NominalFacetChoice>();
|
final public Map<Object, IndexedNominalFacetChoice> choices = new HashMap<Object, IndexedNominalFacetChoice>();
|
||||||
public int blankCount = 0;
|
public int blankCount = 0;
|
||||||
public int errorCount = 0;
|
public int errorCount = 0;
|
||||||
|
protected boolean hasBlank;
|
||||||
|
protected boolean hasError;
|
||||||
|
|
||||||
public ExpressionNominalRowGrouper(Evaluable evaluable, String columnName, int cellIndex) {
|
public ExpressionNominalRowGrouper(Evaluable evaluable, String columnName, int cellIndex) {
|
||||||
_evaluable = evaluable;
|
_evaluable = evaluable;
|
||||||
@ -38,10 +51,49 @@ public class ExpressionNominalRowGrouper implements RowVisitor {
|
|||||||
_cellIndex = cellIndex;
|
_cellIndex = cellIndex;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean visit(Project project, int rowIndex, Row row, boolean includeContextual, boolean includeDependent) {
|
public boolean visit(Project project, int rowIndex, Row row) {
|
||||||
|
hasError = false;
|
||||||
|
hasBlank = false;
|
||||||
|
|
||||||
|
Properties bindings = ExpressionUtils.createBindings(project);
|
||||||
|
|
||||||
|
visitRow(project, rowIndex, row, bindings, rowIndex);
|
||||||
|
|
||||||
|
if (hasError) {
|
||||||
|
errorCount++;
|
||||||
|
}
|
||||||
|
if (hasBlank) {
|
||||||
|
blankCount++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean visit(Project project, Record record) {
|
||||||
|
hasError = false;
|
||||||
|
hasBlank = false;
|
||||||
|
|
||||||
|
Properties bindings = ExpressionUtils.createBindings(project);
|
||||||
|
|
||||||
|
for (int r = record.fromRowIndex; r < record.toRowIndex; r++) {
|
||||||
|
Row row = project.rows.get(r);
|
||||||
|
visitRow(project, r, row, bindings, record.recordIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hasError) {
|
||||||
|
errorCount++;
|
||||||
|
}
|
||||||
|
if (hasBlank) {
|
||||||
|
blankCount++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void visitRow(Project project, int rowIndex, Row row, Properties bindings, int index) {
|
||||||
Cell cell = _cellIndex < 0 ? null : row.getCell(_cellIndex);
|
Cell cell = _cellIndex < 0 ? null : row.getCell(_cellIndex);
|
||||||
|
|
||||||
Properties bindings = ExpressionUtils.createBindings(project);
|
|
||||||
ExpressionUtils.bind(bindings, row, rowIndex, _columnName, cell);
|
ExpressionUtils.bind(bindings, row, rowIndex, _columnName, cell);
|
||||||
|
|
||||||
Object value = _evaluable.evaluate(bindings);
|
Object value = _evaluable.evaluate(bindings);
|
||||||
@ -49,40 +101,43 @@ public class ExpressionNominalRowGrouper implements RowVisitor {
|
|||||||
if (value.getClass().isArray()) {
|
if (value.getClass().isArray()) {
|
||||||
Object[] a = (Object[]) value;
|
Object[] a = (Object[]) value;
|
||||||
for (Object v : a) {
|
for (Object v : a) {
|
||||||
processValue(v);
|
processValue(v, rowIndex);
|
||||||
}
|
}
|
||||||
return false;
|
|
||||||
} else if (value instanceof Collection<?>) {
|
} else if (value instanceof Collection<?>) {
|
||||||
for (Object v : ExpressionUtils.toObjectCollection(value)) {
|
for (Object v : ExpressionUtils.toObjectCollection(value)) {
|
||||||
processValue(v);
|
processValue(v, rowIndex);
|
||||||
}
|
}
|
||||||
return false;
|
} else {
|
||||||
} // else, fall through
|
processValue(value, rowIndex);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
processValue(value, rowIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
processValue(value);
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void processValue(Object value) {
|
protected void processValue(Object value, int index) {
|
||||||
if (ExpressionUtils.isError(value)) {
|
if (ExpressionUtils.isError(value)) {
|
||||||
errorCount++;
|
hasError = true;
|
||||||
} else if (ExpressionUtils.isNonBlankData(value)) {
|
} else if (ExpressionUtils.isNonBlankData(value)) {
|
||||||
String valueString = value.toString();
|
String valueString = value.toString();
|
||||||
String label = value.toString();
|
IndexedNominalFacetChoice facetChoice = choices.get(valueString);
|
||||||
|
|
||||||
DecoratedValue dValue = new DecoratedValue(value, label);
|
if (facetChoice != null) {
|
||||||
|
if (facetChoice._latestIndex < index) {
|
||||||
if (choices.containsKey(valueString)) {
|
facetChoice._latestIndex = index;
|
||||||
choices.get(valueString).count++;
|
facetChoice.count++;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
NominalFacetChoice choice = new NominalFacetChoice(dValue);
|
String label = value.toString();
|
||||||
|
DecoratedValue dValue = new DecoratedValue(value, label);
|
||||||
|
IndexedNominalFacetChoice choice =
|
||||||
|
new IndexedNominalFacetChoice(dValue, index);
|
||||||
|
|
||||||
choice.count = 1;
|
choice.count = 1;
|
||||||
|
|
||||||
choices.put(valueString, choice);
|
choices.put(valueString, choice);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
blankCount++;
|
hasBlank = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,18 +3,20 @@ package com.metaweb.gridworks.browsing.facets;
|
|||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Properties;
|
import java.util.Properties;
|
||||||
|
|
||||||
|
import com.metaweb.gridworks.browsing.RecordVisitor;
|
||||||
import com.metaweb.gridworks.browsing.RowVisitor;
|
import com.metaweb.gridworks.browsing.RowVisitor;
|
||||||
import com.metaweb.gridworks.expr.Evaluable;
|
import com.metaweb.gridworks.expr.Evaluable;
|
||||||
import com.metaweb.gridworks.expr.ExpressionUtils;
|
import com.metaweb.gridworks.expr.ExpressionUtils;
|
||||||
import com.metaweb.gridworks.model.Cell;
|
import com.metaweb.gridworks.model.Cell;
|
||||||
import com.metaweb.gridworks.model.Project;
|
import com.metaweb.gridworks.model.Project;
|
||||||
|
import com.metaweb.gridworks.model.Record;
|
||||||
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
|
* Visit matched rows and slot them into bins based on the numbers computed
|
||||||
* from a given expression.
|
* from a given expression.
|
||||||
*/
|
*/
|
||||||
public class ExpressionNumericRowBinner implements RowVisitor {
|
public class ExpressionNumericRowBinner implements RowVisitor, RecordVisitor {
|
||||||
/*
|
/*
|
||||||
* Configuration
|
* Configuration
|
||||||
*/
|
*/
|
||||||
@ -35,10 +37,10 @@ public class ExpressionNumericRowBinner implements RowVisitor {
|
|||||||
/*
|
/*
|
||||||
* Scratchpad variables
|
* Scratchpad variables
|
||||||
*/
|
*/
|
||||||
private boolean rowHasError;
|
protected boolean hasError;
|
||||||
private boolean rowHasBlank;
|
protected boolean hasBlank;
|
||||||
private boolean rowHasNumeric;
|
protected boolean hasNumeric;
|
||||||
private boolean rowHasNonNumeric;
|
protected boolean hasNonNumeric;
|
||||||
|
|
||||||
public ExpressionNumericRowBinner(Evaluable evaluable, String columnName, int cellIndex, NumericBinIndex index) {
|
public ExpressionNumericRowBinner(Evaluable evaluable, String columnName, int cellIndex, NumericBinIndex index) {
|
||||||
_evaluable = evaluable;
|
_evaluable = evaluable;
|
||||||
@ -48,78 +50,100 @@ public class ExpressionNumericRowBinner implements RowVisitor {
|
|||||||
bins = new int[_index.getBins().length];
|
bins = new int[_index.getBins().length];
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean visit(Project project, int rowIndex, Row row, boolean includeContextual, boolean includeDependent) {
|
@Override
|
||||||
Cell cell = row.getCell(_cellIndex);
|
public boolean visit(Project project, int rowIndex, Row row) {
|
||||||
|
resetFlags();
|
||||||
|
|
||||||
Properties bindings = ExpressionUtils.createBindings(project);
|
Properties bindings = ExpressionUtils.createBindings(project);
|
||||||
|
processRow(project, rowIndex, row, bindings);
|
||||||
|
|
||||||
|
updateCounts();
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean visit(Project project, Record record) {
|
||||||
|
resetFlags();
|
||||||
|
|
||||||
|
Properties bindings = ExpressionUtils.createBindings(project);
|
||||||
|
for (int r = record.fromRowIndex; r < record.toRowIndex; r++) {
|
||||||
|
processRow(project, r, project.rows.get(r), bindings);
|
||||||
|
}
|
||||||
|
|
||||||
|
updateCounts();
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void resetFlags() {
|
||||||
|
hasError = false;
|
||||||
|
hasBlank = false;
|
||||||
|
hasNumeric = false;
|
||||||
|
hasNonNumeric = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void updateCounts() {
|
||||||
|
if (hasError) {
|
||||||
|
errorCount++;
|
||||||
|
}
|
||||||
|
if (hasBlank) {
|
||||||
|
blankCount++;
|
||||||
|
}
|
||||||
|
if (hasNumeric) {
|
||||||
|
numericCount++;
|
||||||
|
}
|
||||||
|
if (hasNonNumeric) {
|
||||||
|
nonNumericCount++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void processRow(Project project, int rowIndex, Row row, Properties bindings) {
|
||||||
|
Cell cell = row.getCell(_cellIndex);
|
||||||
|
|
||||||
ExpressionUtils.bind(bindings, row, rowIndex, _columnName, cell);
|
ExpressionUtils.bind(bindings, row, rowIndex, _columnName, cell);
|
||||||
|
|
||||||
Object value = _evaluable.evaluate(bindings);
|
Object value = _evaluable.evaluate(bindings);
|
||||||
|
|
||||||
rowHasError = false;
|
|
||||||
rowHasBlank = false;
|
|
||||||
rowHasNumeric = false;
|
|
||||||
rowHasNonNumeric = false;
|
|
||||||
|
|
||||||
if (value != null) {
|
if (value != null) {
|
||||||
if (value.getClass().isArray()) {
|
if (value.getClass().isArray()) {
|
||||||
Object[] a = (Object[]) value;
|
Object[] a = (Object[]) value;
|
||||||
for (Object v : a) {
|
for (Object v : a) {
|
||||||
processValue(v);
|
processValue(v);
|
||||||
}
|
}
|
||||||
updateCounts();
|
return;
|
||||||
return false;
|
|
||||||
} else if (value instanceof Collection<?>) {
|
} else if (value instanceof Collection<?>) {
|
||||||
for (Object v : ExpressionUtils.toObjectCollection(value)) {
|
for (Object v : ExpressionUtils.toObjectCollection(value)) {
|
||||||
processValue(v);
|
processValue(v);
|
||||||
}
|
}
|
||||||
updateCounts();
|
return;
|
||||||
return false;
|
|
||||||
} // else, fall through
|
} // else, fall through
|
||||||
}
|
}
|
||||||
|
|
||||||
processValue(value);
|
processValue(value);
|
||||||
updateCounts();
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void updateCounts() {
|
|
||||||
if (rowHasError) {
|
|
||||||
errorCount++;
|
|
||||||
}
|
|
||||||
if (rowHasBlank) {
|
|
||||||
blankCount++;
|
|
||||||
}
|
|
||||||
if (rowHasNumeric) {
|
|
||||||
numericCount++;
|
|
||||||
}
|
|
||||||
if (rowHasNonNumeric) {
|
|
||||||
nonNumericCount++;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void processValue(Object value) {
|
protected void processValue(Object value) {
|
||||||
if (ExpressionUtils.isError(value)) {
|
if (ExpressionUtils.isError(value)) {
|
||||||
rowHasError = true;
|
hasError = true;
|
||||||
} else if (ExpressionUtils.isNonBlankData(value)) {
|
} else if (ExpressionUtils.isNonBlankData(value)) {
|
||||||
if (value instanceof Number) {
|
if (value instanceof Number) {
|
||||||
double d = ((Number) value).doubleValue();
|
double d = ((Number) value).doubleValue();
|
||||||
if (!Double.isInfinite(d) && !Double.isNaN(d)) {
|
if (!Double.isInfinite(d) && !Double.isNaN(d)) {
|
||||||
rowHasNumeric = true;
|
hasNumeric = true;
|
||||||
|
|
||||||
int bin = (int) Math.floor((d - _index.getMin()) / _index.getStep());
|
int bin = (int) Math.floor((d - _index.getMin()) / _index.getStep());
|
||||||
if (bin >= 0 && bin < bins.length) { // as a precaution
|
if (bin >= 0 && bin < bins.length) { // as a precaution
|
||||||
bins[bin]++;
|
bins[bin]++;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
rowHasError = true;
|
hasError = true;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
rowHasNonNumeric = true;
|
hasNonNumeric = true;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
rowHasBlank = true;
|
hasBlank = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,7 +3,9 @@ package com.metaweb.gridworks.browsing.facets;
|
|||||||
import org.json.JSONObject;
|
import org.json.JSONObject;
|
||||||
|
|
||||||
import com.metaweb.gridworks.Jsonizable;
|
import com.metaweb.gridworks.Jsonizable;
|
||||||
|
import com.metaweb.gridworks.browsing.FilteredRecords;
|
||||||
import com.metaweb.gridworks.browsing.FilteredRows;
|
import com.metaweb.gridworks.browsing.FilteredRows;
|
||||||
|
import com.metaweb.gridworks.browsing.filters.RecordFilter;
|
||||||
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;
|
||||||
|
|
||||||
@ -13,7 +15,11 @@ import com.metaweb.gridworks.model.Project;
|
|||||||
public interface Facet extends Jsonizable {
|
public interface Facet extends Jsonizable {
|
||||||
public RowFilter getRowFilter();
|
public RowFilter getRowFilter();
|
||||||
|
|
||||||
|
public RecordFilter getRecordFilter();
|
||||||
|
|
||||||
public void computeChoices(Project project, FilteredRows filteredRows);
|
public void computeChoices(Project project, FilteredRows filteredRows);
|
||||||
|
|
||||||
|
public void computeChoices(Project project, FilteredRecords filteredRecords);
|
||||||
|
|
||||||
public void initializeFromJSON(Project project, JSONObject o) throws Exception;
|
public void initializeFromJSON(Project project, JSONObject o) throws Exception;
|
||||||
}
|
}
|
||||||
|
@ -10,8 +10,11 @@ import org.json.JSONObject;
|
|||||||
import org.json.JSONWriter;
|
import org.json.JSONWriter;
|
||||||
|
|
||||||
import com.metaweb.gridworks.browsing.DecoratedValue;
|
import com.metaweb.gridworks.browsing.DecoratedValue;
|
||||||
|
import com.metaweb.gridworks.browsing.FilteredRecords;
|
||||||
import com.metaweb.gridworks.browsing.FilteredRows;
|
import com.metaweb.gridworks.browsing.FilteredRows;
|
||||||
|
import com.metaweb.gridworks.browsing.filters.AnyRowRecordFilter;
|
||||||
import com.metaweb.gridworks.browsing.filters.ExpressionEqualRowFilter;
|
import com.metaweb.gridworks.browsing.filters.ExpressionEqualRowFilter;
|
||||||
|
import com.metaweb.gridworks.browsing.filters.RecordFilter;
|
||||||
import com.metaweb.gridworks.browsing.filters.RowFilter;
|
import com.metaweb.gridworks.browsing.filters.RowFilter;
|
||||||
import com.metaweb.gridworks.expr.Evaluable;
|
import com.metaweb.gridworks.expr.Evaluable;
|
||||||
import com.metaweb.gridworks.expr.MetaParser;
|
import com.metaweb.gridworks.expr.MetaParser;
|
||||||
@ -54,6 +57,7 @@ public class ListFacet implements Facet {
|
|||||||
public ListFacet() {
|
public ListFacet() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public void write(JSONWriter writer, Properties options)
|
public void write(JSONWriter writer, Properties options)
|
||||||
throws JSONException {
|
throws JSONException {
|
||||||
|
|
||||||
@ -93,6 +97,7 @@ public class ListFacet implements Facet {
|
|||||||
writer.endObject();
|
writer.endObject();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
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");
|
||||||
_expression = o.getString("expression");
|
_expression = o.getString("expression");
|
||||||
@ -141,6 +146,7 @@ public class ListFacet implements Facet {
|
|||||||
_selectError = JSONUtilities.getBoolean(o, "selectError", false);
|
_selectError = JSONUtilities.getBoolean(o, "selectError", false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public RowFilter getRowFilter() {
|
public RowFilter getRowFilter() {
|
||||||
return
|
return
|
||||||
_eval == null ||
|
_eval == null ||
|
||||||
@ -156,7 +162,14 @@ public class ListFacet implements Facet {
|
|||||||
_selectError,
|
_selectError,
|
||||||
_invert);
|
_invert);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public RecordFilter getRecordFilter() {
|
||||||
|
RowFilter rowFilter = getRowFilter();
|
||||||
|
return rowFilter == null ? null : new AnyRowRecordFilter(rowFilter);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public void computeChoices(Project project, FilteredRows filteredRows) {
|
public void computeChoices(Project project, FilteredRows filteredRows) {
|
||||||
if (_eval != null && _errorMessage == null) {
|
if (_eval != null && _errorMessage == null) {
|
||||||
ExpressionNominalRowGrouper grouper =
|
ExpressionNominalRowGrouper grouper =
|
||||||
@ -164,35 +177,51 @@ public class ListFacet implements Facet {
|
|||||||
|
|
||||||
filteredRows.accept(project, grouper);
|
filteredRows.accept(project, grouper);
|
||||||
|
|
||||||
_choices.clear();
|
postProcessGrouper(grouper);
|
||||||
_choices.addAll(grouper.choices.values());
|
|
||||||
|
|
||||||
for (NominalFacetChoice choice : _selection) {
|
|
||||||
String valueString = choice.decoratedValue.value.toString();
|
|
||||||
|
|
||||||
if (grouper.choices.containsKey(valueString)) {
|
|
||||||
grouper.choices.get(valueString).selected = true;
|
|
||||||
} 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;
|
|
||||||
_choices.add(choice);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
_blankCount = grouper.blankCount;
|
|
||||||
_errorCount = grouper.errorCount;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void computeChoices(Project project, FilteredRecords filteredRecords) {
|
||||||
|
if (_eval != null && _errorMessage == null) {
|
||||||
|
ExpressionNominalRowGrouper grouper =
|
||||||
|
new ExpressionNominalRowGrouper(_eval, _columnName, _cellIndex);
|
||||||
|
|
||||||
|
filteredRecords.accept(project, grouper);
|
||||||
|
|
||||||
|
postProcessGrouper(grouper);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void postProcessGrouper(ExpressionNominalRowGrouper grouper) {
|
||||||
|
_choices.clear();
|
||||||
|
_choices.addAll(grouper.choices.values());
|
||||||
|
|
||||||
|
for (NominalFacetChoice choice : _selection) {
|
||||||
|
String valueString = choice.decoratedValue.value.toString();
|
||||||
|
|
||||||
|
if (grouper.choices.containsKey(valueString)) {
|
||||||
|
grouper.choices.get(valueString).selected = true;
|
||||||
|
} 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;
|
||||||
|
_choices.add(choice);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_blankCount = grouper.blankCount;
|
||||||
|
_errorCount = grouper.errorCount;
|
||||||
|
}
|
||||||
|
|
||||||
protected Object[] createMatches() {
|
protected Object[] createMatches() {
|
||||||
Object[] a = new Object[_selection.size()];
|
Object[] a = new Object[_selection.size()];
|
||||||
for (int i = 0; i < a.length; i++) {
|
for (int i = 0; i < a.length; i++) {
|
||||||
|
@ -21,105 +21,34 @@ import com.metaweb.gridworks.model.Row;
|
|||||||
* needs to compute the base bins of a numeric range facet, which remain unchanged
|
* needs to compute the base bins of a numeric range facet, which remain unchanged
|
||||||
* as the user interacts with the facet.
|
* as the user interacts with the facet.
|
||||||
*/
|
*/
|
||||||
public class NumericBinIndex {
|
abstract public class NumericBinIndex {
|
||||||
|
|
||||||
private int _totalValueCount;
|
protected int _totalValueCount;
|
||||||
private int _numbericValueCount;
|
protected int _numbericValueCount;
|
||||||
private double _min;
|
protected double _min;
|
||||||
private double _max;
|
protected double _max;
|
||||||
private double _step;
|
protected double _step;
|
||||||
private int[] _bins;
|
protected int[] _bins;
|
||||||
|
|
||||||
private int _numericRowCount;
|
protected int _numericRowCount;
|
||||||
private int _nonNumericRowCount;
|
protected int _nonNumericRowCount;
|
||||||
private int _blankRowCount;
|
protected int _blankRowCount;
|
||||||
private int _errorRowCount;
|
protected int _errorRowCount;
|
||||||
|
|
||||||
|
protected boolean _hasError = false;
|
||||||
|
protected boolean _hasNonNumeric = false;
|
||||||
|
protected boolean _hasNumeric = false;
|
||||||
|
protected boolean _hasBlank = false;
|
||||||
|
|
||||||
|
abstract protected void iterate(Project project, String columnName, int cellIndex, Evaluable eval, List<Double> allValues);
|
||||||
|
|
||||||
public NumericBinIndex(Project project, String columnName, int cellIndex, Evaluable eval) {
|
public NumericBinIndex(Project project, String columnName, int cellIndex, Evaluable eval) {
|
||||||
Properties bindings = ExpressionUtils.createBindings(project);
|
|
||||||
|
|
||||||
_min = Double.POSITIVE_INFINITY;
|
_min = Double.POSITIVE_INFINITY;
|
||||||
_max = Double.NEGATIVE_INFINITY;
|
_max = Double.NEGATIVE_INFINITY;
|
||||||
|
|
||||||
List<Double> allValues = new ArrayList<Double>();
|
List<Double> allValues = new ArrayList<Double>();
|
||||||
for (int i = 0; i < project.rows.size(); i++) {
|
|
||||||
Row row = project.rows.get(i);
|
iterate(project, columnName, cellIndex, eval, allValues);
|
||||||
Cell cell = row.getCell(cellIndex);
|
|
||||||
|
|
||||||
ExpressionUtils.bind(bindings, row, i, columnName, cell);
|
|
||||||
|
|
||||||
Object value = eval.evaluate(bindings);
|
|
||||||
|
|
||||||
boolean rowHasError = false;
|
|
||||||
boolean rowHasNonNumeric = false;
|
|
||||||
boolean rowHasNumeric = false;
|
|
||||||
boolean rowHasBlank = false;
|
|
||||||
|
|
||||||
if (ExpressionUtils.isError(value)) {
|
|
||||||
rowHasError = true;
|
|
||||||
} else if (ExpressionUtils.isNonBlankData(value)) {
|
|
||||||
if (value.getClass().isArray()) {
|
|
||||||
Object[] a = (Object[]) value;
|
|
||||||
for (Object v : a) {
|
|
||||||
_totalValueCount++;
|
|
||||||
|
|
||||||
if (ExpressionUtils.isError(v)) {
|
|
||||||
rowHasError = true;
|
|
||||||
} else if (ExpressionUtils.isNonBlankData(v)) {
|
|
||||||
if (v instanceof Number) {
|
|
||||||
rowHasNumeric = true;
|
|
||||||
processValue(((Number) v).doubleValue(), allValues);
|
|
||||||
} else {
|
|
||||||
rowHasNonNumeric = true;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
rowHasBlank = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else if (value instanceof Collection<?>) {
|
|
||||||
for (Object v : ExpressionUtils.toObjectCollection(value)) {
|
|
||||||
_totalValueCount++;
|
|
||||||
|
|
||||||
if (ExpressionUtils.isError(v)) {
|
|
||||||
rowHasError = true;
|
|
||||||
} else if (ExpressionUtils.isNonBlankData(v)) {
|
|
||||||
if (v instanceof Number) {
|
|
||||||
rowHasNumeric = true;
|
|
||||||
processValue(((Number) v).doubleValue(), allValues);
|
|
||||||
} else {
|
|
||||||
rowHasNonNumeric = true;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
rowHasBlank = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
_totalValueCount++;
|
|
||||||
|
|
||||||
if (value instanceof Number) {
|
|
||||||
rowHasNumeric = true;
|
|
||||||
processValue(((Number) value).doubleValue(), allValues);
|
|
||||||
} else {
|
|
||||||
rowHasNonNumeric = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
rowHasBlank = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (rowHasError) {
|
|
||||||
_errorRowCount++;
|
|
||||||
}
|
|
||||||
if (rowHasBlank) {
|
|
||||||
_blankRowCount++;
|
|
||||||
}
|
|
||||||
if (rowHasNumeric) {
|
|
||||||
_numericRowCount++;
|
|
||||||
}
|
|
||||||
if (rowHasNonNumeric) {
|
|
||||||
_nonNumericRowCount++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
_numbericValueCount = allValues.size();
|
_numbericValueCount = allValues.size();
|
||||||
|
|
||||||
@ -203,6 +132,97 @@ public class NumericBinIndex {
|
|||||||
return _errorRowCount;
|
return _errorRowCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected void processRow(
|
||||||
|
Project project,
|
||||||
|
String columnName,
|
||||||
|
int cellIndex,
|
||||||
|
Evaluable eval,
|
||||||
|
List<Double> allValues,
|
||||||
|
int rowIndex,
|
||||||
|
Row row,
|
||||||
|
Properties bindings
|
||||||
|
) {
|
||||||
|
Cell cell = row.getCell(cellIndex);
|
||||||
|
|
||||||
|
ExpressionUtils.bind(bindings, row, rowIndex, columnName, cell);
|
||||||
|
|
||||||
|
Object value = eval.evaluate(bindings);
|
||||||
|
|
||||||
|
if (ExpressionUtils.isError(value)) {
|
||||||
|
_hasError = true;
|
||||||
|
} else if (ExpressionUtils.isNonBlankData(value)) {
|
||||||
|
if (value.getClass().isArray()) {
|
||||||
|
Object[] a = (Object[]) value;
|
||||||
|
for (Object v : a) {
|
||||||
|
_totalValueCount++;
|
||||||
|
|
||||||
|
if (ExpressionUtils.isError(v)) {
|
||||||
|
_hasError = true;
|
||||||
|
} else if (ExpressionUtils.isNonBlankData(v)) {
|
||||||
|
if (v instanceof Number) {
|
||||||
|
_hasNumeric = true;
|
||||||
|
processValue(((Number) v).doubleValue(), allValues);
|
||||||
|
} else {
|
||||||
|
_hasNonNumeric = true;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
_hasBlank = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (value instanceof Collection<?>) {
|
||||||
|
for (Object v : ExpressionUtils.toObjectCollection(value)) {
|
||||||
|
_totalValueCount++;
|
||||||
|
|
||||||
|
if (ExpressionUtils.isError(v)) {
|
||||||
|
_hasError = true;
|
||||||
|
} else if (ExpressionUtils.isNonBlankData(v)) {
|
||||||
|
if (v instanceof Number) {
|
||||||
|
_hasNumeric = true;
|
||||||
|
processValue(((Number) v).doubleValue(), allValues);
|
||||||
|
} else {
|
||||||
|
_hasNonNumeric = true;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
_hasBlank = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
_totalValueCount++;
|
||||||
|
|
||||||
|
if (value instanceof Number) {
|
||||||
|
_hasNumeric = true;
|
||||||
|
processValue(((Number) value).doubleValue(), allValues);
|
||||||
|
} else {
|
||||||
|
_hasNonNumeric = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
_hasBlank = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void preprocessing() {
|
||||||
|
_hasBlank = false;
|
||||||
|
_hasError = false;
|
||||||
|
_hasNonNumeric = false;
|
||||||
|
_hasNumeric = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void postprocessing() {
|
||||||
|
if (_hasError) {
|
||||||
|
_errorRowCount++;
|
||||||
|
}
|
||||||
|
if (_hasBlank) {
|
||||||
|
_blankRowCount++;
|
||||||
|
}
|
||||||
|
if (_hasNumeric) {
|
||||||
|
_numericRowCount++;
|
||||||
|
}
|
||||||
|
if (_hasNonNumeric) {
|
||||||
|
_nonNumericRowCount++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
protected void processValue(double v, List<Double> allValues) {
|
protected void processValue(double v, List<Double> allValues) {
|
||||||
if (!Double.isInfinite(v) && !Double.isNaN(v)) {
|
if (!Double.isInfinite(v) && !Double.isNaN(v)) {
|
||||||
_min = Math.min(_min, v);
|
_min = Math.min(_min, v);
|
||||||
|
@ -0,0 +1,42 @@
|
|||||||
|
package com.metaweb.gridworks.browsing.facets;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Properties;
|
||||||
|
|
||||||
|
import com.metaweb.gridworks.expr.Evaluable;
|
||||||
|
import com.metaweb.gridworks.expr.ExpressionUtils;
|
||||||
|
import com.metaweb.gridworks.model.Project;
|
||||||
|
import com.metaweb.gridworks.model.Record;
|
||||||
|
import com.metaweb.gridworks.model.Row;
|
||||||
|
|
||||||
|
public class NumericBinRecordIndex extends NumericBinIndex {
|
||||||
|
public NumericBinRecordIndex(Project project, String columnName,
|
||||||
|
int cellIndex, Evaluable eval) {
|
||||||
|
|
||||||
|
super(project, columnName, cellIndex, eval);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void iterate(
|
||||||
|
Project project, String columnName, int cellIndex,
|
||||||
|
Evaluable eval, List<Double> allValues) {
|
||||||
|
|
||||||
|
Properties bindings = ExpressionUtils.createBindings(project);
|
||||||
|
int count = project.recordModel.getRecordCount();
|
||||||
|
|
||||||
|
for (int r = 0; r < count; r++) {
|
||||||
|
Record record = project.recordModel.getRecord(r);
|
||||||
|
|
||||||
|
preprocessing();
|
||||||
|
|
||||||
|
for (int i = record.fromRowIndex; i < record.toRowIndex; i++) {
|
||||||
|
Row row = project.rows.get(i);
|
||||||
|
|
||||||
|
processRow(project, columnName, cellIndex, eval, allValues, i, row, bindings);
|
||||||
|
}
|
||||||
|
|
||||||
|
postprocessing();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,36 @@
|
|||||||
|
package com.metaweb.gridworks.browsing.facets;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Properties;
|
||||||
|
|
||||||
|
import com.metaweb.gridworks.expr.Evaluable;
|
||||||
|
import com.metaweb.gridworks.expr.ExpressionUtils;
|
||||||
|
import com.metaweb.gridworks.model.Project;
|
||||||
|
import com.metaweb.gridworks.model.Row;
|
||||||
|
|
||||||
|
public class NumericBinRowIndex extends NumericBinIndex {
|
||||||
|
public NumericBinRowIndex(Project project, String columnName,
|
||||||
|
int cellIndex, Evaluable eval) {
|
||||||
|
|
||||||
|
super(project, columnName, cellIndex, eval);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void iterate(
|
||||||
|
Project project, String columnName, int cellIndex,
|
||||||
|
Evaluable eval, List<Double> allValues) {
|
||||||
|
|
||||||
|
Properties bindings = ExpressionUtils.createBindings(project);
|
||||||
|
|
||||||
|
for (int i = 0; i < project.rows.size(); i++) {
|
||||||
|
Row row = project.rows.get(i);
|
||||||
|
|
||||||
|
preprocessing();
|
||||||
|
|
||||||
|
processRow(project, columnName, cellIndex, eval, allValues, i, row, bindings);
|
||||||
|
|
||||||
|
postprocessing();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -6,8 +6,11 @@ import org.json.JSONException;
|
|||||||
import org.json.JSONObject;
|
import org.json.JSONObject;
|
||||||
import org.json.JSONWriter;
|
import org.json.JSONWriter;
|
||||||
|
|
||||||
|
import com.metaweb.gridworks.browsing.FilteredRecords;
|
||||||
import com.metaweb.gridworks.browsing.FilteredRows;
|
import com.metaweb.gridworks.browsing.FilteredRows;
|
||||||
|
import com.metaweb.gridworks.browsing.filters.AnyRowRecordFilter;
|
||||||
import com.metaweb.gridworks.browsing.filters.ExpressionNumberComparisonRowFilter;
|
import com.metaweb.gridworks.browsing.filters.ExpressionNumberComparisonRowFilter;
|
||||||
|
import com.metaweb.gridworks.browsing.filters.RecordFilter;
|
||||||
import com.metaweb.gridworks.browsing.filters.RowFilter;
|
import com.metaweb.gridworks.browsing.filters.RowFilter;
|
||||||
import com.metaweb.gridworks.expr.Evaluable;
|
import com.metaweb.gridworks.expr.Evaluable;
|
||||||
import com.metaweb.gridworks.expr.MetaParser;
|
import com.metaweb.gridworks.expr.MetaParser;
|
||||||
@ -165,45 +168,80 @@ public class RangeFacet implements Facet {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public RecordFilter getRecordFilter() {
|
||||||
|
RowFilter rowFilter = getRowFilter();
|
||||||
|
return rowFilter == null ? null : new AnyRowRecordFilter(rowFilter);
|
||||||
|
}
|
||||||
|
|
||||||
public void computeChoices(Project project, FilteredRows filteredRows) {
|
public void computeChoices(Project project, FilteredRows filteredRows) {
|
||||||
if (_eval != null && _errorMessage == null) {
|
if (_eval != null && _errorMessage == null) {
|
||||||
Column column = project.columnModel.getColumnByCellIndex(_cellIndex);
|
Column column = project.columnModel.getColumnByCellIndex(_cellIndex);
|
||||||
|
|
||||||
String key = "numeric-bin:" + _expression;
|
String key = "numeric-bin:row-based:" + _expression;
|
||||||
NumericBinIndex index = (NumericBinIndex) column.getPrecompute(key);
|
NumericBinIndex index = (NumericBinIndex) column.getPrecompute(key);
|
||||||
if (index == null) {
|
if (index == null) {
|
||||||
index = new NumericBinIndex(project, _columnName, _cellIndex, _eval);
|
index = new NumericBinRowIndex(project, _columnName, _cellIndex, _eval);
|
||||||
column.setPrecompute(key, index);
|
column.setPrecompute(key, index);
|
||||||
}
|
}
|
||||||
|
|
||||||
_min = index.getMin();
|
retrieveDataFromBaseBinIndex(index);
|
||||||
_max = index.getMax();
|
|
||||||
_step = index.getStep();
|
|
||||||
_baseBins = index.getBins();
|
|
||||||
|
|
||||||
_baseNumericCount = index.getNumericRowCount();
|
|
||||||
_baseNonNumericCount = index.getNonNumericRowCount();
|
|
||||||
_baseBlankCount = index.getBlankRowCount();
|
|
||||||
_baseErrorCount = index.getErrorRowCount();
|
|
||||||
|
|
||||||
if (_selected) {
|
|
||||||
_from = Math.max(_from, _min);
|
|
||||||
_to = Math.min(_to, _max);
|
|
||||||
} else {
|
|
||||||
_from = _min;
|
|
||||||
_to = _max;
|
|
||||||
}
|
|
||||||
|
|
||||||
ExpressionNumericRowBinner binner =
|
ExpressionNumericRowBinner binner =
|
||||||
new ExpressionNumericRowBinner(_eval, _columnName, _cellIndex, index);
|
new ExpressionNumericRowBinner(_eval, _columnName, _cellIndex, index);
|
||||||
|
|
||||||
filteredRows.accept(project, binner);
|
filteredRows.accept(project, binner);
|
||||||
|
retrieveDataFromBinner(binner);
|
||||||
_bins = binner.bins;
|
|
||||||
_numericCount = binner.numericCount;
|
|
||||||
_nonNumericCount = binner.nonNumericCount;
|
|
||||||
_blankCount = binner.blankCount;
|
|
||||||
_errorCount = binner.errorCount;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void computeChoices(Project project, FilteredRecords filteredRecords) {
|
||||||
|
if (_eval != null && _errorMessage == null) {
|
||||||
|
Column column = project.columnModel.getColumnByCellIndex(_cellIndex);
|
||||||
|
|
||||||
|
String key = "numeric-bin:record-based:" + _expression;
|
||||||
|
NumericBinIndex index = (NumericBinIndex) column.getPrecompute(key);
|
||||||
|
if (index == null) {
|
||||||
|
index = new NumericBinRecordIndex(project, _columnName, _cellIndex, _eval);
|
||||||
|
column.setPrecompute(key, index);
|
||||||
|
}
|
||||||
|
|
||||||
|
retrieveDataFromBaseBinIndex(index);
|
||||||
|
|
||||||
|
ExpressionNumericRowBinner binner =
|
||||||
|
new ExpressionNumericRowBinner(_eval, _columnName, _cellIndex, index);
|
||||||
|
|
||||||
|
filteredRecords.accept(project, binner);
|
||||||
|
|
||||||
|
retrieveDataFromBinner(binner);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void retrieveDataFromBaseBinIndex(NumericBinIndex index) {
|
||||||
|
_min = index.getMin();
|
||||||
|
_max = index.getMax();
|
||||||
|
_step = index.getStep();
|
||||||
|
_baseBins = index.getBins();
|
||||||
|
|
||||||
|
_baseNumericCount = index.getNumericRowCount();
|
||||||
|
_baseNonNumericCount = index.getNonNumericRowCount();
|
||||||
|
_baseBlankCount = index.getBlankRowCount();
|
||||||
|
_baseErrorCount = index.getErrorRowCount();
|
||||||
|
|
||||||
|
if (_selected) {
|
||||||
|
_from = Math.max(_from, _min);
|
||||||
|
_to = Math.min(_to, _max);
|
||||||
|
} else {
|
||||||
|
_from = _min;
|
||||||
|
_to = _max;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void retrieveDataFromBinner(ExpressionNumericRowBinner binner) {
|
||||||
|
_bins = binner.bins;
|
||||||
|
_numericCount = binner.numericCount;
|
||||||
|
_nonNumericCount = binner.nonNumericCount;
|
||||||
|
_blankCount = binner.blankCount;
|
||||||
|
_errorCount = binner.errorCount;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -10,12 +10,14 @@ import java.awt.geom.Rectangle2D;
|
|||||||
import java.awt.image.BufferedImage;
|
import java.awt.image.BufferedImage;
|
||||||
import java.awt.image.RenderedImage;
|
import java.awt.image.RenderedImage;
|
||||||
|
|
||||||
|
import com.metaweb.gridworks.browsing.RecordVisitor;
|
||||||
import com.metaweb.gridworks.browsing.RowVisitor;
|
import com.metaweb.gridworks.browsing.RowVisitor;
|
||||||
import com.metaweb.gridworks.model.Cell;
|
import com.metaweb.gridworks.model.Cell;
|
||||||
import com.metaweb.gridworks.model.Project;
|
import com.metaweb.gridworks.model.Project;
|
||||||
|
import com.metaweb.gridworks.model.Record;
|
||||||
import com.metaweb.gridworks.model.Row;
|
import com.metaweb.gridworks.model.Row;
|
||||||
|
|
||||||
public class ScatterplotDrawingRowVisitor implements RowVisitor {
|
public class ScatterplotDrawingRowVisitor implements RowVisitor, RecordVisitor {
|
||||||
|
|
||||||
int col_x;
|
int col_x;
|
||||||
int col_y;
|
int col_y;
|
||||||
@ -85,7 +87,8 @@ public class ScatterplotDrawingRowVisitor implements RowVisitor {
|
|||||||
g2.setPaint(color);
|
g2.setPaint(color);
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean visit(Project project, int rowIndex, Row row, boolean includeContextual, boolean includeDependent) {
|
@Override
|
||||||
|
public boolean visit(Project project, int rowIndex, Row row) {
|
||||||
Cell cellx = row.getCell(col_x);
|
Cell cellx = row.getCell(col_x);
|
||||||
Cell celly = row.getCell(col_y);
|
Cell celly = row.getCell(col_y);
|
||||||
if ((cellx != null && cellx.value != null && cellx.value instanceof Number) &&
|
if ((cellx != null && cellx.value != null && cellx.value instanceof Number) &&
|
||||||
@ -105,6 +108,14 @@ public class ScatterplotDrawingRowVisitor implements RowVisitor {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean visit(Project project, Record record) {
|
||||||
|
for (int r = record.fromRowIndex; r < record.toRowIndex; r++) {
|
||||||
|
visit(project, r, project.rows.get(r));
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
public RenderedImage getImage() {
|
public RenderedImage getImage() {
|
||||||
return image;
|
return image;
|
||||||
}
|
}
|
||||||
|
@ -18,8 +18,11 @@ import org.json.JSONWriter;
|
|||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import com.metaweb.gridworks.browsing.FilteredRecords;
|
||||||
import com.metaweb.gridworks.browsing.FilteredRows;
|
import com.metaweb.gridworks.browsing.FilteredRows;
|
||||||
|
import com.metaweb.gridworks.browsing.filters.AnyRowRecordFilter;
|
||||||
import com.metaweb.gridworks.browsing.filters.DualExpressionsNumberComparisonRowFilter;
|
import com.metaweb.gridworks.browsing.filters.DualExpressionsNumberComparisonRowFilter;
|
||||||
|
import com.metaweb.gridworks.browsing.filters.RecordFilter;
|
||||||
import com.metaweb.gridworks.browsing.filters.RowFilter;
|
import com.metaweb.gridworks.browsing.filters.RowFilter;
|
||||||
import com.metaweb.gridworks.expr.Evaluable;
|
import com.metaweb.gridworks.expr.Evaluable;
|
||||||
import com.metaweb.gridworks.expr.MetaParser;
|
import com.metaweb.gridworks.expr.MetaParser;
|
||||||
@ -269,19 +272,21 @@ public class ScatterplotFacet implements Facet {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public RecordFilter getRecordFilter() {
|
||||||
|
RowFilter rowFilter = getRowFilter();
|
||||||
|
return rowFilter == null ? null : new AnyRowRecordFilter(rowFilter);
|
||||||
|
}
|
||||||
|
|
||||||
public void computeChoices(Project project, FilteredRows filteredRows) {
|
public void computeChoices(Project project, FilteredRows filteredRows) {
|
||||||
if (eval_x != null && eval_y != null && errorMessage_x == null && errorMessage_y == null) {
|
if (eval_x != null && eval_y != null && errorMessage_x == null && errorMessage_y == null) {
|
||||||
Column column_x = project.columnModel.getColumnByCellIndex(columnIndex_x);
|
Column column_x = project.columnModel.getColumnByCellIndex(columnIndex_x);
|
||||||
NumericBinIndex index_x = getBinIndex(project, column_x, eval_x, expression_x);
|
NumericBinIndex index_x = getBinIndex(project, column_x, eval_x, expression_x, "row-based");
|
||||||
|
|
||||||
min_x = index_x.getMin();
|
|
||||||
max_x = index_x.getMax();
|
|
||||||
|
|
||||||
Column column_y = project.columnModel.getColumnByCellIndex(columnIndex_y);
|
Column column_y = project.columnModel.getColumnByCellIndex(columnIndex_y);
|
||||||
NumericBinIndex index_y = getBinIndex(project, column_y, eval_y, expression_y);
|
NumericBinIndex index_y = getBinIndex(project, column_y, eval_y, expression_y, "row-based");
|
||||||
|
|
||||||
min_y = index_y.getMin();
|
retrieveDataFromBinIndices(index_x, index_y);
|
||||||
max_y = index_y.getMax();
|
|
||||||
|
|
||||||
if (IMAGE_URI) {
|
if (IMAGE_URI) {
|
||||||
if (index_x.isNumeric() && index_y.isNumeric()) {
|
if (index_x.isNumeric() && index_y.isNumeric()) {
|
||||||
@ -302,7 +307,45 @@ public class ScatterplotFacet implements Facet {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void computeChoices(Project project, FilteredRecords filteredRecords) {
|
||||||
|
if (eval_x != null && eval_y != null && errorMessage_x == null && errorMessage_y == null) {
|
||||||
|
Column column_x = project.columnModel.getColumnByCellIndex(columnIndex_x);
|
||||||
|
NumericBinIndex index_x = getBinIndex(project, column_x, eval_x, expression_x, "record-based");
|
||||||
|
|
||||||
|
Column column_y = project.columnModel.getColumnByCellIndex(columnIndex_y);
|
||||||
|
NumericBinIndex index_y = getBinIndex(project, column_y, eval_y, expression_y, "record-based");
|
||||||
|
|
||||||
|
retrieveDataFromBinIndices(index_x, index_y);
|
||||||
|
|
||||||
|
if (IMAGE_URI) {
|
||||||
|
if (index_x.isNumeric() && index_y.isNumeric()) {
|
||||||
|
ScatterplotDrawingRowVisitor drawer = new ScatterplotDrawingRowVisitor(
|
||||||
|
columnIndex_x, columnIndex_y, min_x, max_x, min_y, max_y,
|
||||||
|
size, dim_x, dim_y, rotation, dot, color
|
||||||
|
);
|
||||||
|
filteredRecords.accept(project, drawer);
|
||||||
|
|
||||||
|
try {
|
||||||
|
image = serializeImage(drawer.getImage());
|
||||||
|
} catch (IOException e) {
|
||||||
|
logger.warn("Exception caught while generating the image", e);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
image = EMPTY_IMAGE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void retrieveDataFromBinIndices(NumericBinIndex index_x, NumericBinIndex index_y) {
|
||||||
|
min_x = index_x.getMin();
|
||||||
|
max_x = index_x.getMax();
|
||||||
|
|
||||||
|
min_y = index_y.getMin();
|
||||||
|
max_y = index_y.getMax();
|
||||||
|
}
|
||||||
|
|
||||||
public static String serializeImage(RenderedImage image) throws IOException {
|
public static String serializeImage(RenderedImage image) throws IOException {
|
||||||
ByteArrayOutputStream output = new ByteArrayOutputStream(4096);
|
ByteArrayOutputStream output = new ByteArrayOutputStream(4096);
|
||||||
ImageIO.write(image, "png", output);
|
ImageIO.write(image, "png", output);
|
||||||
@ -328,7 +371,11 @@ public class ScatterplotFacet implements Facet {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static NumericBinIndex getBinIndex(Project project, Column column, Evaluable eval, String expression) {
|
public static NumericBinIndex getBinIndex(Project project, Column column, Evaluable eval, String expression) {
|
||||||
String key = "numeric-bin:" + expression;
|
return getBinIndex(project, column, eval, expression, "row-based");
|
||||||
|
}
|
||||||
|
|
||||||
|
public static NumericBinIndex getBinIndex(Project project, Column column, Evaluable eval, String expression, String mode) {
|
||||||
|
String key = "numeric-bin:" + mode + ":" + expression;
|
||||||
if (eval == null) {
|
if (eval == null) {
|
||||||
try {
|
try {
|
||||||
eval = MetaParser.parse(expression);
|
eval = MetaParser.parse(expression);
|
||||||
@ -338,7 +385,10 @@ public class ScatterplotFacet implements Facet {
|
|||||||
}
|
}
|
||||||
NumericBinIndex index = (NumericBinIndex) column.getPrecompute(key);
|
NumericBinIndex index = (NumericBinIndex) column.getPrecompute(key);
|
||||||
if (index == null) {
|
if (index == null) {
|
||||||
index = new NumericBinIndex(project, column.getName(), column.getCellIndex(), eval);
|
index = "row-based".equals(mode) ?
|
||||||
|
new NumericBinRowIndex(project, column.getName(), column.getCellIndex(), eval) :
|
||||||
|
new NumericBinRecordIndex(project, column.getName(), column.getCellIndex(), eval);
|
||||||
|
|
||||||
column.setPrecompute(key, index);
|
column.setPrecompute(key, index);
|
||||||
}
|
}
|
||||||
return index;
|
return index;
|
||||||
|
@ -7,8 +7,11 @@ import org.json.JSONException;
|
|||||||
import org.json.JSONObject;
|
import org.json.JSONObject;
|
||||||
import org.json.JSONWriter;
|
import org.json.JSONWriter;
|
||||||
|
|
||||||
|
import com.metaweb.gridworks.browsing.FilteredRecords;
|
||||||
import com.metaweb.gridworks.browsing.FilteredRows;
|
import com.metaweb.gridworks.browsing.FilteredRows;
|
||||||
|
import com.metaweb.gridworks.browsing.filters.AnyRowRecordFilter;
|
||||||
import com.metaweb.gridworks.browsing.filters.ExpressionStringComparisonRowFilter;
|
import com.metaweb.gridworks.browsing.filters.ExpressionStringComparisonRowFilter;
|
||||||
|
import com.metaweb.gridworks.browsing.filters.RecordFilter;
|
||||||
import com.metaweb.gridworks.browsing.filters.RowFilter;
|
import com.metaweb.gridworks.browsing.filters.RowFilter;
|
||||||
import com.metaweb.gridworks.expr.Evaluable;
|
import com.metaweb.gridworks.expr.Evaluable;
|
||||||
import com.metaweb.gridworks.gel.ast.VariableExpr;
|
import com.metaweb.gridworks.gel.ast.VariableExpr;
|
||||||
@ -33,6 +36,7 @@ public class TextSearchFacet implements Facet {
|
|||||||
public TextSearchFacet() {
|
public TextSearchFacet() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public void write(JSONWriter writer, Properties options)
|
public void write(JSONWriter writer, Properties options)
|
||||||
throws JSONException {
|
throws JSONException {
|
||||||
|
|
||||||
@ -45,6 +49,7 @@ public class TextSearchFacet implements Facet {
|
|||||||
writer.endObject();
|
writer.endObject();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
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");
|
||||||
@ -72,6 +77,7 @@ public class TextSearchFacet implements Facet {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public RowFilter getRowFilter() {
|
public RowFilter getRowFilter() {
|
||||||
if (_query == null || _query.length() == 0) {
|
if (_query == null || _query.length() == 0) {
|
||||||
return null;
|
return null;
|
||||||
@ -96,7 +102,19 @@ public class TextSearchFacet implements Facet {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public RecordFilter getRecordFilter() {
|
||||||
|
RowFilter rowFilter = getRowFilter();
|
||||||
|
return rowFilter == null ? null : new AnyRowRecordFilter(rowFilter);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public void computeChoices(Project project, FilteredRows filteredRows) {
|
public void computeChoices(Project project, FilteredRows filteredRows) {
|
||||||
// nothing to do
|
// nothing to do
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void computeChoices(Project project, FilteredRecords filteredRecords) {
|
||||||
|
// nothing to do
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,22 @@
|
|||||||
|
package com.metaweb.gridworks.browsing.filters;
|
||||||
|
|
||||||
|
import com.metaweb.gridworks.model.Project;
|
||||||
|
import com.metaweb.gridworks.model.Record;
|
||||||
|
|
||||||
|
public class AnyRowRecordFilter implements RecordFilter {
|
||||||
|
final protected RowFilter _rowFilter;
|
||||||
|
|
||||||
|
public AnyRowRecordFilter(RowFilter rowFilter) {
|
||||||
|
_rowFilter = rowFilter;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean filterRecord(Project project, Record record) {
|
||||||
|
for (int r = record.fromRowIndex; r < record.toRowIndex; r++) {
|
||||||
|
if (_rowFilter.filterRow(project, r, project.rows.get(r))) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,12 @@
|
|||||||
|
package com.metaweb.gridworks.browsing.filters;
|
||||||
|
|
||||||
|
import com.metaweb.gridworks.model.Project;
|
||||||
|
import com.metaweb.gridworks.model.Record;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Interface for judging if a particular record matches or doesn't match some
|
||||||
|
* particular criterion, such as a facet constraint.
|
||||||
|
*/
|
||||||
|
public interface RecordFilter {
|
||||||
|
public boolean filterRecord(Project project, Record record);
|
||||||
|
}
|
@ -66,7 +66,7 @@ public class BinningClusterer extends Clusterer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean visit(Project project, int rowIndex, Row row, boolean includeContextual, boolean includeDependent) {
|
public boolean visit(Project project, int rowIndex, Row row) {
|
||||||
Cell cell = row.getCell(_colindex);
|
Cell cell = row.getCell(_colindex);
|
||||||
if (cell != null && cell.value != null) {
|
if (cell != null && cell.value != null) {
|
||||||
Object v = cell.value;
|
Object v = cell.value;
|
||||||
@ -128,7 +128,7 @@ public class BinningClusterer extends Clusterer {
|
|||||||
|
|
||||||
public void computeClusters(Engine engine) {
|
public void computeClusters(Engine engine) {
|
||||||
BinningRowVisitor visitor = new BinningRowVisitor(_keyer,_config);
|
BinningRowVisitor visitor = new BinningRowVisitor(_keyer,_config);
|
||||||
FilteredRows filteredRows = engine.getAllFilteredRows(true);
|
FilteredRows filteredRows = engine.getAllFilteredRows();
|
||||||
filteredRows.accept(_project, visitor);
|
filteredRows.accept(_project, visitor);
|
||||||
|
|
||||||
Map<String,Map<String,Integer>> map = visitor.getMap();
|
Map<String,Map<String,Integer>> map = visitor.getMap();
|
||||||
|
@ -80,7 +80,7 @@ public class kNNClusterer extends Clusterer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean visit(Project project, int rowIndex, Row row, boolean includeContextual, boolean includeDependent) {
|
public boolean visit(Project project, int rowIndex, Row row) {
|
||||||
Cell cell = row.getCell(_colindex);
|
Cell cell = row.getCell(_colindex);
|
||||||
if (cell != null && cell.value != null) {
|
if (cell != null && cell.value != null) {
|
||||||
Object v = cell.value;
|
Object v = cell.value;
|
||||||
@ -121,7 +121,7 @@ public class kNNClusterer extends Clusterer {
|
|||||||
_clusterer = new NGramClusterer(_distance, _blockingNgramSize);
|
_clusterer = new NGramClusterer(_distance, _blockingNgramSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean visit(Project project, int rowIndex, Row row, boolean includeContextual, boolean includeDependent) {
|
public boolean visit(Project project, int rowIndex, Row row) {
|
||||||
Cell cell = row.getCell(_colindex);
|
Cell cell = row.getCell(_colindex);
|
||||||
if (cell != null && cell.value != null) {
|
if (cell != null && cell.value != null) {
|
||||||
Object v = cell.value;
|
Object v = cell.value;
|
||||||
@ -145,7 +145,7 @@ public class kNNClusterer extends Clusterer {
|
|||||||
public void computeClusters(Engine engine) {
|
public void computeClusters(Engine engine) {
|
||||||
//VPTreeClusteringRowVisitor visitor = new VPTreeClusteringRowVisitor(_distance,_config);
|
//VPTreeClusteringRowVisitor visitor = new VPTreeClusteringRowVisitor(_distance,_config);
|
||||||
BlockingClusteringRowVisitor visitor = new BlockingClusteringRowVisitor(_distance,_config);
|
BlockingClusteringRowVisitor visitor = new BlockingClusteringRowVisitor(_distance,_config);
|
||||||
FilteredRows filteredRows = engine.getAllFilteredRows(false);
|
FilteredRows filteredRows = engine.getAllFilteredRows();
|
||||||
filteredRows.accept(_project, visitor);
|
filteredRows.accept(_project, visitor);
|
||||||
|
|
||||||
_clusters = visitor.getClusters();
|
_clusters = visitor.getClusters();
|
||||||
|
@ -161,7 +161,7 @@ public class GetScatterplotCommand extends Command {
|
|||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
FilteredRows filteredRows = engine.getAllFilteredRows(false);
|
FilteredRows filteredRows = engine.getAllFilteredRows();
|
||||||
filteredRows.accept(project, drawer);
|
filteredRows.accept(project, drawer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -10,6 +10,7 @@ import org.json.JSONException;
|
|||||||
import org.json.JSONWriter;
|
import org.json.JSONWriter;
|
||||||
|
|
||||||
import com.metaweb.gridworks.browsing.facets.NumericBinIndex;
|
import com.metaweb.gridworks.browsing.facets.NumericBinIndex;
|
||||||
|
import com.metaweb.gridworks.browsing.facets.NumericBinRowIndex;
|
||||||
import com.metaweb.gridworks.commands.Command;
|
import com.metaweb.gridworks.commands.Command;
|
||||||
import com.metaweb.gridworks.expr.Evaluable;
|
import com.metaweb.gridworks.expr.Evaluable;
|
||||||
import com.metaweb.gridworks.expr.MetaParser;
|
import com.metaweb.gridworks.expr.MetaParser;
|
||||||
@ -59,7 +60,7 @@ public class GetColumnsInfoCommand extends Command {
|
|||||||
}
|
}
|
||||||
NumericBinIndex index = (NumericBinIndex) column.getPrecompute(key);
|
NumericBinIndex index = (NumericBinIndex) column.getPrecompute(key);
|
||||||
if (index == null) {
|
if (index == null) {
|
||||||
index = new NumericBinIndex(project, column.getName(), column.getCellIndex(), eval);
|
index = new NumericBinRowIndex(project, column.getName(), column.getCellIndex(), eval);
|
||||||
column.setPrecompute(key, index);
|
column.setPrecompute(key, index);
|
||||||
}
|
}
|
||||||
return index;
|
return index;
|
||||||
|
@ -11,10 +11,14 @@ import org.json.JSONException;
|
|||||||
import org.json.JSONWriter;
|
import org.json.JSONWriter;
|
||||||
|
|
||||||
import com.metaweb.gridworks.browsing.Engine;
|
import com.metaweb.gridworks.browsing.Engine;
|
||||||
|
import com.metaweb.gridworks.browsing.FilteredRecords;
|
||||||
import com.metaweb.gridworks.browsing.FilteredRows;
|
import com.metaweb.gridworks.browsing.FilteredRows;
|
||||||
|
import com.metaweb.gridworks.browsing.RecordVisitor;
|
||||||
import com.metaweb.gridworks.browsing.RowVisitor;
|
import com.metaweb.gridworks.browsing.RowVisitor;
|
||||||
|
import com.metaweb.gridworks.browsing.Engine.Mode;
|
||||||
import com.metaweb.gridworks.commands.Command;
|
import com.metaweb.gridworks.commands.Command;
|
||||||
import com.metaweb.gridworks.model.Project;
|
import com.metaweb.gridworks.model.Project;
|
||||||
|
import com.metaweb.gridworks.model.Record;
|
||||||
import com.metaweb.gridworks.model.Row;
|
import com.metaweb.gridworks.model.Row;
|
||||||
import com.metaweb.gridworks.util.Pool;
|
import com.metaweb.gridworks.util.Pool;
|
||||||
|
|
||||||
@ -42,56 +46,71 @@ public class GetRowsCommand extends Command {
|
|||||||
JSONWriter writer = new JSONWriter(response.getWriter());
|
JSONWriter writer = new JSONWriter(response.getWriter());
|
||||||
writer.object();
|
writer.object();
|
||||||
|
|
||||||
{
|
RowAccumulator acc = new RowAccumulator(start, limit) {
|
||||||
RowAccumulator acc = new RowAccumulator(start, limit) {
|
JSONWriter writer;
|
||||||
JSONWriter writer;
|
Properties options;
|
||||||
Properties options;
|
|
||||||
Properties extra;
|
public RowAccumulator init(JSONWriter writer, Properties options) {
|
||||||
|
this.writer = writer;
|
||||||
|
this.options = options;
|
||||||
|
|
||||||
public RowAccumulator init(JSONWriter writer, Properties options) {
|
return this;
|
||||||
this.writer = writer;
|
}
|
||||||
this.options = options;
|
|
||||||
|
@Override
|
||||||
this.extra = new Properties();
|
public boolean internalVisit(Project project, int rowIndex, Row row) {
|
||||||
this.extra.put("contextual", true);
|
try {
|
||||||
|
options.put("rowIndex", rowIndex);
|
||||||
return this;
|
row.write(writer, options);
|
||||||
|
} catch (JSONException e) {
|
||||||
}
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected boolean internalVisit(Project project, Record record) {
|
||||||
|
options.put("recordIndex", record.recordIndex);
|
||||||
|
|
||||||
@Override
|
for (int r = record.fromRowIndex; r < record.toRowIndex; r++) {
|
||||||
public boolean internalVisit(int rowIndex, Row row, boolean contextual, boolean dependent) {
|
|
||||||
try {
|
try {
|
||||||
/*
|
Row row = project.rows.get(r);
|
||||||
* Whatever that's in the "extra" field will be written out
|
|
||||||
* by the row as well. This is how we can customize what the row
|
options.put("rowIndex", r);
|
||||||
* writes, in a limited way.
|
|
||||||
*/
|
|
||||||
if (contextual) {
|
|
||||||
options.put("extra", extra);
|
|
||||||
} else {
|
|
||||||
options.remove("extra");
|
|
||||||
}
|
|
||||||
options.put("rowIndex", rowIndex);
|
|
||||||
|
|
||||||
row.write(writer, options);
|
row.write(writer, options);
|
||||||
|
|
||||||
} catch (JSONException e) {
|
} catch (JSONException e) {
|
||||||
}
|
}
|
||||||
return false;
|
|
||||||
}
|
options.remove("recordIndex");
|
||||||
}.init(writer, options);
|
}
|
||||||
|
return false;
|
||||||
FilteredRows filteredRows = engine.getAllFilteredRows(true);
|
}
|
||||||
|
}.init(writer, options);
|
||||||
|
|
||||||
|
if (engine.getMode() == Mode.RowBased) {
|
||||||
|
FilteredRows filteredRows = engine.getAllFilteredRows();
|
||||||
|
|
||||||
|
writer.key("mode"); writer.value("row-based");
|
||||||
writer.key("rows"); writer.array();
|
writer.key("rows"); writer.array();
|
||||||
filteredRows.accept(project, acc);
|
filteredRows.accept(project, acc);
|
||||||
writer.endArray();
|
writer.endArray();
|
||||||
|
|
||||||
writer.key("filtered"); writer.value(acc.total);
|
writer.key("filtered"); writer.value(acc.total);
|
||||||
|
writer.key("total"); writer.value(project.rows.size());
|
||||||
|
} else {
|
||||||
|
FilteredRecords filteredRecords = engine.getFilteredRecords();
|
||||||
|
|
||||||
|
writer.key("mode"); writer.value("record-based");
|
||||||
|
writer.key("rows"); writer.array();
|
||||||
|
filteredRecords.accept(project, acc);
|
||||||
|
writer.endArray();
|
||||||
|
writer.key("filtered"); writer.value(acc.total);
|
||||||
|
writer.key("total"); writer.value(project.recordModel.getRecordCount());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
writer.key("start"); writer.value(start);
|
writer.key("start"); writer.value(start);
|
||||||
writer.key("limit"); writer.value(limit);
|
writer.key("limit"); writer.value(limit);
|
||||||
writer.key("total"); writer.value(project.rows.size());
|
|
||||||
writer.key("pool"); pool.write(writer, options);
|
writer.key("pool"); pool.write(writer, options);
|
||||||
|
|
||||||
writer.endObject();
|
writer.endObject();
|
||||||
@ -100,7 +119,7 @@ public class GetRowsCommand extends Command {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static protected class RowAccumulator implements RowVisitor {
|
static protected class RowAccumulator implements RowVisitor, RecordVisitor {
|
||||||
final public int start;
|
final public int start;
|
||||||
final public int limit;
|
final public int limit;
|
||||||
|
|
||||||
@ -111,19 +130,32 @@ public class GetRowsCommand extends Command {
|
|||||||
this.limit = limit;
|
this.limit = limit;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean visit(Project project, int rowIndex, Row row, boolean contextual, boolean dependent) {
|
public boolean visit(Project project, int rowIndex, Row row) {
|
||||||
boolean r = false;
|
boolean r = false;
|
||||||
|
|
||||||
if (total >= start && total < start + limit) {
|
if (total >= start && total < start + limit) {
|
||||||
r = internalVisit(rowIndex, row, contextual, dependent);
|
r = internalVisit(project, rowIndex, row);
|
||||||
}
|
|
||||||
if (!contextual) {
|
|
||||||
total++;
|
|
||||||
}
|
}
|
||||||
|
total++;
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected boolean internalVisit(int rowIndex, Row row, boolean contextual, boolean dependent) {
|
@Override
|
||||||
|
public boolean visit(Project project, Record record) {
|
||||||
|
boolean r = false;
|
||||||
|
|
||||||
|
if (total >= start && total < start + limit) {
|
||||||
|
r = internalVisit(project, record);
|
||||||
|
}
|
||||||
|
total++;
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected boolean internalVisit(Project project, int rowIndex, Row row) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected boolean internalVisit(Project project, Record record) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -56,7 +56,7 @@ public class HtmlTableExporter implements Exporter {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean visit(Project project, int rowIndex, Row row, boolean contextual, boolean includeDependent) {
|
public boolean visit(Project project, int rowIndex, Row row) {
|
||||||
try {
|
try {
|
||||||
writer.write("<tr>");
|
writer.write("<tr>");
|
||||||
|
|
||||||
@ -83,7 +83,7 @@ public class HtmlTableExporter implements Exporter {
|
|||||||
}
|
}
|
||||||
}.init(writer);
|
}.init(writer);
|
||||||
|
|
||||||
FilteredRows filteredRows = engine.getAllFilteredRows(true);
|
FilteredRows filteredRows = engine.getAllFilteredRows();
|
||||||
filteredRows.accept(project, visitor);
|
filteredRows.accept(project, visitor);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -48,7 +48,7 @@ public class TsvExporter implements Exporter {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean visit(Project project, int rowIndex, Row row, boolean contextual, boolean includeDependent) {
|
public boolean visit(Project project, int rowIndex, Row row) {
|
||||||
boolean first = true;
|
boolean first = true;
|
||||||
try {
|
try {
|
||||||
for (Column column : project.columnModel.columns) {
|
for (Column column : project.columnModel.columns) {
|
||||||
@ -82,7 +82,7 @@ public class TsvExporter implements Exporter {
|
|||||||
}
|
}
|
||||||
}.init(writer);
|
}.init(writer);
|
||||||
|
|
||||||
FilteredRows filteredRows = engine.getAllFilteredRows(true);
|
FilteredRows filteredRows = engine.getAllFilteredRows();
|
||||||
filteredRows.accept(project, visitor);
|
filteredRows.accept(project, visitor);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -64,7 +64,7 @@ public class XlsExporter implements Exporter {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean visit(Project project, int rowIndex, Row row, boolean contextual, boolean includeDependent) {
|
public boolean visit(Project project, int rowIndex, Row row) {
|
||||||
org.apache.poi.ss.usermodel.Row r = sheet.createRow(rowCount++);
|
org.apache.poi.ss.usermodel.Row r = sheet.createRow(rowCount++);
|
||||||
|
|
||||||
int cellCount = 0;
|
int cellCount = 0;
|
||||||
@ -105,7 +105,7 @@ public class XlsExporter implements Exporter {
|
|||||||
}
|
}
|
||||||
}.init(s, rowCount);
|
}.init(s, rowCount);
|
||||||
|
|
||||||
FilteredRows filteredRows = engine.getAllFilteredRows(true);
|
FilteredRows filteredRows = engine.getAllFilteredRows();
|
||||||
filteredRows.accept(project, visitor);
|
filteredRows.accept(project, visitor);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -32,6 +32,10 @@ public class RecordModel {
|
|||||||
_rowDependencies.get(rowIndex) : null;
|
_rowDependencies.get(rowIndex) : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public int getRecordCount() {
|
||||||
|
return _records.size();
|
||||||
|
}
|
||||||
|
|
||||||
public Record getRecord(int recordIndex) {
|
public Record getRecord(int recordIndex) {
|
||||||
return _records != null && recordIndex >= 0 && recordIndex < _records.size() ?
|
return _records != null && recordIndex >= 0 && recordIndex < _records.size() ?
|
||||||
_records.get(recordIndex) : null;
|
_records.get(recordIndex) : null;
|
||||||
|
@ -15,19 +15,13 @@ import org.json.JSONWriter;
|
|||||||
import com.metaweb.gridworks.Jsonizable;
|
import com.metaweb.gridworks.Jsonizable;
|
||||||
import com.metaweb.gridworks.expr.CellTuple;
|
import com.metaweb.gridworks.expr.CellTuple;
|
||||||
import com.metaweb.gridworks.expr.HasFields;
|
import com.metaweb.gridworks.expr.HasFields;
|
||||||
import com.metaweb.gridworks.model.RecordModel.RowDependency;
|
|
||||||
import com.metaweb.gridworks.util.Pool;
|
import com.metaweb.gridworks.util.Pool;
|
||||||
|
|
||||||
public class Row implements HasFields, Jsonizable {
|
public class Row implements HasFields, Jsonizable {
|
||||||
public boolean flagged;
|
public boolean flagged;
|
||||||
public boolean starred;
|
public boolean starred;
|
||||||
final public List<Cell> cells;
|
final public List<Cell> cells;
|
||||||
/*
|
|
||||||
transient public int recordIndex = -1; // -1 for rows that are not main record rows
|
|
||||||
transient public List<Integer> contextRows;
|
|
||||||
transient public int[] contextRowSlots;
|
|
||||||
transient public int[] contextCellSlots;
|
|
||||||
*/
|
|
||||||
private static final String FLAGGED = "flagged";
|
private static final String FLAGGED = "flagged";
|
||||||
private static final String STARRED = "starred";
|
private static final String STARRED = "starred";
|
||||||
|
|
||||||
@ -134,10 +128,10 @@ public class Row implements HasFields, Jsonizable {
|
|||||||
int rowIndex = (Integer) options.get("rowIndex");
|
int rowIndex = (Integer) options.get("rowIndex");
|
||||||
writer.key("i"); writer.value(rowIndex);
|
writer.key("i"); writer.value(rowIndex);
|
||||||
|
|
||||||
Project project = (Project) options.get("project");
|
if (options.containsKey("recordIndex")) {
|
||||||
RowDependency rd = project.recordModel.getRowDependency(rowIndex);
|
int recordIndex = (Integer) options.get("recordIndex");
|
||||||
if (rd.recordIndex >= 0) {
|
|
||||||
writer.key("j"); writer.value(rd.recordIndex);
|
writer.key("j"); writer.value(recordIndex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -104,7 +104,7 @@ public class ColumnAdditionOperation extends EngineDependentOperation {
|
|||||||
|
|
||||||
List<CellAtRow> cellsAtRows = new ArrayList<CellAtRow>(project.rows.size());
|
List<CellAtRow> cellsAtRows = new ArrayList<CellAtRow>(project.rows.size());
|
||||||
|
|
||||||
FilteredRows filteredRows = engine.getAllFilteredRows(false);
|
FilteredRows filteredRows = engine.getAllFilteredRows();
|
||||||
filteredRows.accept(project, createRowVisitor(project, cellsAtRows));
|
filteredRows.accept(project, createRowVisitor(project, cellsAtRows));
|
||||||
|
|
||||||
String description = createDescription(column, cellsAtRows);
|
String description = createDescription(column, cellsAtRows);
|
||||||
@ -135,7 +135,7 @@ public class ColumnAdditionOperation extends EngineDependentOperation {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean visit(Project project, int rowIndex, Row row, boolean includeContextual, boolean includeDependent) {
|
public boolean visit(Project project, int rowIndex, Row row) {
|
||||||
Cell cell = row.getCell(cellIndex);
|
Cell cell = row.getCell(cellIndex);
|
||||||
Cell newCell = null;
|
Cell newCell = null;
|
||||||
|
|
||||||
|
@ -148,7 +148,7 @@ public class ColumnSplitOperation extends EngineDependentOperation {
|
|||||||
List<Integer> rowIndices = new ArrayList<Integer>(project.rows.size());
|
List<Integer> rowIndices = new ArrayList<Integer>(project.rows.size());
|
||||||
List<List<Serializable>> tuples = new ArrayList<List<Serializable>>(project.rows.size());
|
List<List<Serializable>> tuples = new ArrayList<List<Serializable>>(project.rows.size());
|
||||||
|
|
||||||
FilteredRows filteredRows = engine.getAllFilteredRows(false);
|
FilteredRows filteredRows = engine.getAllFilteredRows();
|
||||||
RowVisitor rowVisitor;
|
RowVisitor rowVisitor;
|
||||||
if ("lengths".equals(_mode)) {
|
if ("lengths".equals(_mode)) {
|
||||||
rowVisitor = new ColumnSplitRowVisitor(column.getCellIndex(), columnNames, rowIndices, tuples) {
|
rowVisitor = new ColumnSplitRowVisitor(column.getCellIndex(), columnNames, rowIndices, tuples) {
|
||||||
@ -234,7 +234,7 @@ public class ColumnSplitOperation extends EngineDependentOperation {
|
|||||||
this.tuples = tuples;
|
this.tuples = tuples;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean visit(Project project, int rowIndex, Row row, boolean includeContextual, boolean includeDependent) {
|
public boolean visit(Project project, int rowIndex, Row row) {
|
||||||
Object value = row.getCellValue(cellIndex);
|
Object value = row.getCellValue(cellIndex);
|
||||||
if (ExpressionUtils.isNonBlankData(value)) {
|
if (ExpressionUtils.isNonBlankData(value)) {
|
||||||
String s = value instanceof String ? ((String) value) : value.toString();
|
String s = value instanceof String ? ((String) value) : value.toString();
|
||||||
|
@ -36,7 +36,7 @@ abstract public class EngineDependentMassCellOperation extends EngineDependentOp
|
|||||||
|
|
||||||
List<CellChange> cellChanges = new ArrayList<CellChange>(project.rows.size());
|
List<CellChange> cellChanges = new ArrayList<CellChange>(project.rows.size());
|
||||||
|
|
||||||
FilteredRows filteredRows = engine.getAllFilteredRows(false);
|
FilteredRows filteredRows = engine.getAllFilteredRows();
|
||||||
try {
|
try {
|
||||||
filteredRows.accept(project, createRowVisitor(project, cellChanges, historyEntryID));
|
filteredRows.accept(project, createRowVisitor(project, cellChanges, historyEntryID));
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
|
@ -140,7 +140,7 @@ public class ExtendDataOperation extends EngineDependentOperation {
|
|||||||
|
|
||||||
_cellIndex = column.getCellIndex();
|
_cellIndex = column.getCellIndex();
|
||||||
|
|
||||||
FilteredRows filteredRows = engine.getAllFilteredRows(false);
|
FilteredRows filteredRows = engine.getAllFilteredRows();
|
||||||
filteredRows.accept(_project, new RowVisitor() {
|
filteredRows.accept(_project, new RowVisitor() {
|
||||||
List<Integer> _rowIndices;
|
List<Integer> _rowIndices;
|
||||||
|
|
||||||
@ -148,13 +148,12 @@ public class ExtendDataOperation extends EngineDependentOperation {
|
|||||||
_rowIndices = rowIndices;
|
_rowIndices = rowIndices;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
public boolean visit(Project project, int rowIndex, Row row, boolean includeContextual, boolean includeDependent) {
|
public boolean visit(Project project, int rowIndex, Row row) {
|
||||||
if (!includeContextual) {
|
Cell cell = row.getCell(_cellIndex);
|
||||||
Cell cell = row.getCell(_cellIndex);
|
if (cell != null && cell.recon != null && cell.recon.match != null) {
|
||||||
if (cell != null && cell.recon != null && cell.recon.match != null) {
|
_rowIndices.add(rowIndex);
|
||||||
_rowIndices.add(rowIndex);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}.init(rowIndices));
|
}.init(rowIndices));
|
||||||
|
@ -196,7 +196,7 @@ public class MassEditOperation extends EngineDependentMassCellOperation {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean visit(Project project, int rowIndex, Row row, boolean includeContextual, boolean includeDependent) {
|
public boolean visit(Project project, int rowIndex, Row row) {
|
||||||
Cell cell = row.getCell(cellIndex);
|
Cell cell = row.getCell(cellIndex);
|
||||||
Cell newCell = null;
|
Cell newCell = null;
|
||||||
|
|
||||||
|
@ -74,7 +74,7 @@ public class ReconDiscardJudgmentsOperation extends EngineDependentMassCellOpera
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean visit(Project project, int rowIndex, Row row, boolean includeContextual, boolean includeDependent) {
|
public boolean visit(Project project, int rowIndex, Row row) {
|
||||||
Cell cell = row.getCell(cellIndex);
|
Cell cell = row.getCell(cellIndex);
|
||||||
if (cell != null && cell.recon != null) {
|
if (cell != null && cell.recon != null) {
|
||||||
Recon newRecon;
|
Recon newRecon;
|
||||||
|
@ -162,7 +162,7 @@ public class ReconJudgeSimilarCellsOperation extends EngineDependentMassCellOper
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean visit(Project project, int rowIndex, Row row, boolean includeContextual, boolean includeDependent) {
|
public boolean visit(Project project, int rowIndex, Row row) {
|
||||||
Cell cell = row.getCell(_cellIndex);
|
Cell cell = row.getCell(_cellIndex);
|
||||||
if (cell != null && ExpressionUtils.isNonBlankData(cell.value)) {
|
if (cell != null && ExpressionUtils.isNonBlankData(cell.value)) {
|
||||||
String value = cell.value instanceof String ?
|
String value = cell.value instanceof String ?
|
||||||
|
@ -84,7 +84,7 @@ public class ReconMarkNewTopicsOperation extends EngineDependentMassCellOperatio
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean visit(Project project, int rowIndex, Row row, boolean includeContextual, boolean includeDependent) {
|
public boolean visit(Project project, int rowIndex, Row row) {
|
||||||
Cell cell = row.getCell(cellIndex);
|
Cell cell = row.getCell(cellIndex);
|
||||||
if (cell != null) {
|
if (cell != null) {
|
||||||
Recon recon = null;
|
Recon recon = null;
|
||||||
|
@ -75,7 +75,7 @@ public class ReconMatchBestCandidatesOperation extends EngineDependentMassCellOp
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean visit(Project project, int rowIndex, Row row, boolean includeContextual, boolean includeDependent) {
|
public boolean visit(Project project, int rowIndex, Row row) {
|
||||||
if (cellIndex < row.cells.size()) {
|
if (cellIndex < row.cells.size()) {
|
||||||
Cell cell = row.cells.get(cellIndex);
|
Cell cell = row.cells.get(cellIndex);
|
||||||
if (cell != null && cell.recon != null) {
|
if (cell != null && cell.recon != null) {
|
||||||
|
@ -108,7 +108,7 @@ public class ReconMatchSpecificTopicOperation extends EngineDependentMassCellOpe
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean visit(Project project, int rowIndex, Row row, boolean includeContextual, boolean includeDependent) {
|
public boolean visit(Project project, int rowIndex, Row row) {
|
||||||
Cell cell = row.getCell(cellIndex);
|
Cell cell = row.getCell(cellIndex);
|
||||||
if (cell != null) {
|
if (cell != null) {
|
||||||
long reconID = cell.recon != null ? cell.recon.id : 0;
|
long reconID = cell.recon != null ? cell.recon.id : 0;
|
||||||
|
@ -174,9 +174,9 @@ public class ReconOperation extends EngineDependentOperation {
|
|||||||
_entries = new ArrayList<ReconEntry>(_project.rows.size());
|
_entries = new ArrayList<ReconEntry>(_project.rows.size());
|
||||||
_cellIndex = column.getCellIndex();
|
_cellIndex = column.getCellIndex();
|
||||||
|
|
||||||
FilteredRows filteredRows = engine.getAllFilteredRows(false);
|
FilteredRows filteredRows = engine.getAllFilteredRows();
|
||||||
filteredRows.accept(_project, new RowVisitor() {
|
filteredRows.accept(_project, new RowVisitor() {
|
||||||
public boolean visit(Project project, int rowIndex, Row row, boolean includeContextual, boolean includeDependent) {
|
public boolean visit(Project project, int rowIndex, Row row) {
|
||||||
if (_cellIndex < row.cells.size()) {
|
if (_cellIndex < row.cells.size()) {
|
||||||
Cell cell = row.cells.get(_cellIndex);
|
Cell cell = row.cells.get(_cellIndex);
|
||||||
if (cell != null && ExpressionUtils.isNonBlankData(cell.value)) {
|
if (cell != null && ExpressionUtils.isNonBlankData(cell.value)) {
|
||||||
|
@ -57,7 +57,7 @@ public class RowFlagOperation extends EngineDependentOperation {
|
|||||||
|
|
||||||
List<Change> changes = new ArrayList<Change>(project.rows.size());
|
List<Change> changes = new ArrayList<Change>(project.rows.size());
|
||||||
|
|
||||||
FilteredRows filteredRows = engine.getAllFilteredRows(false);
|
FilteredRows filteredRows = engine.getAllFilteredRows();
|
||||||
filteredRows.accept(project, createRowVisitor(project, changes));
|
filteredRows.accept(project, createRowVisitor(project, changes));
|
||||||
|
|
||||||
return new HistoryEntry(
|
return new HistoryEntry(
|
||||||
@ -78,7 +78,7 @@ public class RowFlagOperation extends EngineDependentOperation {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean visit(Project project, int rowIndex, Row row, boolean includeContextual, boolean includeDependent) {
|
public boolean visit(Project project, int rowIndex, Row row) {
|
||||||
if (row.flagged != _flagged) {
|
if (row.flagged != _flagged) {
|
||||||
RowFlagChange change = new RowFlagChange(rowIndex, _flagged);
|
RowFlagChange change = new RowFlagChange(rowIndex, _flagged);
|
||||||
|
|
||||||
|
@ -49,7 +49,7 @@ public class RowRemovalOperation extends EngineDependentOperation {
|
|||||||
|
|
||||||
List<Integer> rowIndices = new ArrayList<Integer>();
|
List<Integer> rowIndices = new ArrayList<Integer>();
|
||||||
|
|
||||||
FilteredRows filteredRows = engine.getAllFilteredRows(false);
|
FilteredRows filteredRows = engine.getAllFilteredRows();
|
||||||
filteredRows.accept(project, createRowVisitor(project, rowIndices));
|
filteredRows.accept(project, createRowVisitor(project, rowIndices));
|
||||||
|
|
||||||
return new HistoryEntry(
|
return new HistoryEntry(
|
||||||
@ -70,10 +70,9 @@ public class RowRemovalOperation extends EngineDependentOperation {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean visit(Project project, int rowIndex, Row row, boolean includeContextual, boolean includeDependent) {
|
public boolean visit(Project project, int rowIndex, Row row) {
|
||||||
if (!includeContextual) {
|
rowIndices.add(rowIndex);
|
||||||
rowIndices.add(rowIndex);
|
|
||||||
}
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}.init(rowIndices);
|
}.init(rowIndices);
|
||||||
|
@ -57,7 +57,7 @@ public class RowStarOperation extends EngineDependentOperation {
|
|||||||
|
|
||||||
List<Change> changes = new ArrayList<Change>(project.rows.size());
|
List<Change> changes = new ArrayList<Change>(project.rows.size());
|
||||||
|
|
||||||
FilteredRows filteredRows = engine.getAllFilteredRows(false);
|
FilteredRows filteredRows = engine.getAllFilteredRows();
|
||||||
filteredRows.accept(project, createRowVisitor(project, changes));
|
filteredRows.accept(project, createRowVisitor(project, changes));
|
||||||
|
|
||||||
return new HistoryEntry(
|
return new HistoryEntry(
|
||||||
@ -78,7 +78,7 @@ public class RowStarOperation extends EngineDependentOperation {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean visit(Project project, int rowIndex, Row row, boolean includeContextual, boolean includeDependent) {
|
public boolean visit(Project project, int rowIndex, Row row) {
|
||||||
if (row.starred != _starred) {
|
if (row.starred != _starred) {
|
||||||
RowStarChange change = new RowStarChange(rowIndex, _starred);
|
RowStarChange change = new RowStarChange(rowIndex, _starred);
|
||||||
|
|
||||||
|
@ -119,7 +119,7 @@ public class TextTransformOperation extends EngineDependentMassCellOperation {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean visit(Project project, int rowIndex, Row row, boolean includeContextual, boolean includeDependent) {
|
public boolean visit(Project project, int rowIndex, Row row) {
|
||||||
Cell cell = row.getCell(cellIndex);
|
Cell cell = row.getCell(cellIndex);
|
||||||
Cell newCell = null;
|
Cell newCell = null;
|
||||||
|
|
||||||
|
@ -51,13 +51,14 @@ DataTableView.prototype.render = function() {
|
|||||||
DataTableView.prototype._renderSummaryText = function(elmt) {
|
DataTableView.prototype._renderSummaryText = function(elmt) {
|
||||||
var summaryText;
|
var summaryText;
|
||||||
|
|
||||||
|
var units = theProject.rowModel.mode == "row-based" ? "rows" : "records";
|
||||||
var from = (theProject.rowModel.start + 1);
|
var from = (theProject.rowModel.start + 1);
|
||||||
var to = Math.min(theProject.rowModel.filtered, theProject.rowModel.start + theProject.rowModel.limit);
|
var to = Math.min(theProject.rowModel.filtered, theProject.rowModel.start + theProject.rowModel.limit);
|
||||||
if (theProject.rowModel.filtered == theProject.rowModel.total) {
|
if (theProject.rowModel.filtered == theProject.rowModel.total) {
|
||||||
summaryText = from + ' – ' + to + ' of <span class="viewPanel-summary-row-count">' + (theProject.rowModel.total) + '</span> rows';
|
summaryText = from + ' – ' + to + ' of <span class="viewPanel-summary-row-count">' + (theProject.rowModel.total) + '</span> ' + units;
|
||||||
} else {
|
} else {
|
||||||
summaryText = from + ' – ' + to + ' of <span class="viewPanel-summary-row-count">' +
|
summaryText = from + ' – ' + to + ' of <span class="viewPanel-summary-row-count">' +
|
||||||
(theProject.rowModel.filtered) + '</span> matching rows (' + (theProject.rowModel.total) + ' total)';
|
(theProject.rowModel.filtered) + '</span> matching ' + units + ' (' + (theProject.rowModel.total) + ' total)';
|
||||||
}
|
}
|
||||||
$('<span>').html(summaryText).appendTo(elmt);
|
$('<span>').html(summaryText).appendTo(elmt);
|
||||||
};
|
};
|
||||||
@ -285,15 +286,15 @@ DataTableView.prototype._renderDataTable = function(table) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
var tdIndex = tr.insertCell(tr.cells.length);
|
var tdIndex = tr.insertCell(tr.cells.length);
|
||||||
if ("j" in row) {
|
if (theProject.rowModel.mode == "record-based") {
|
||||||
$(tr).addClass("record");
|
if ("j" in row) {
|
||||||
$('<div></div>').html((row.j + 1) + ".").appendTo(tdIndex);
|
$(tr).addClass("record");
|
||||||
|
$('<div></div>').html((row.j + 1) + ".").appendTo(tdIndex);
|
||||||
|
} else {
|
||||||
|
$('<div></div>').html(" ").appendTo(tdIndex);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
$('<div></div>').html(" ").appendTo(tdIndex);
|
$('<div></div>').html((row.i + 1) + ".").appendTo(tdIndex);
|
||||||
}
|
|
||||||
|
|
||||||
if ("contextual" in row && row.contextual) {
|
|
||||||
$(tr).addClass("contextual");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$(tr).addClass(even ? "even" : "odd");
|
$(tr).addClass(even ? "even" : "odd");
|
||||||
@ -314,7 +315,7 @@ DataTableView.prototype._renderDataTable = function(table) {
|
|||||||
for (var r = 0; r < rows.length; r++) {
|
for (var r = 0; r < rows.length; r++) {
|
||||||
var row = rows[r];
|
var row = rows[r];
|
||||||
var tr = table.insertRow(table.rows.length);
|
var tr = table.insertRow(table.rows.length);
|
||||||
if ("j" in row) {
|
if (theProject.rowModel.mode == "row-based" || "j" in row) {
|
||||||
even = !even;
|
even = !even;
|
||||||
}
|
}
|
||||||
renderRow(tr, r, row, even);
|
renderRow(tr, r, row, even);
|
||||||
|
Loading…
Reference in New Issue
Block a user