diff --git a/src/main/java/com/metaweb/gridworks/browsing/ConjunctiveFilteredRows.java b/src/main/java/com/metaweb/gridworks/browsing/ConjunctiveFilteredRows.java index c0a1d72f0..55323214f 100644 --- a/src/main/java/com/metaweb/gridworks/browsing/ConjunctiveFilteredRows.java +++ b/src/main/java/com/metaweb/gridworks/browsing/ConjunctiveFilteredRows.java @@ -9,10 +9,12 @@ import com.metaweb.gridworks.model.Row; public class ConjunctiveFilteredRows implements FilteredRows { final protected List _rowFilters = new LinkedList(); - final protected boolean _contextual; + final protected boolean _includeContextual; + final protected boolean _includeDependent; - public ConjunctiveFilteredRows(boolean contextual) { - _contextual = contextual; + public ConjunctiveFilteredRows(boolean includeContextual, boolean includeDependent) { + _includeContextual = includeContextual; + _includeDependent = includeDependent; } public void add(RowFilter rowFilter) { @@ -20,63 +22,66 @@ public class ConjunctiveFilteredRows implements FilteredRows { } public void accept(Project project, RowVisitor visitor) { - if (_contextual) { - contextualAccept(project, visitor); - } else { - simpleAccept(project, visitor); - } - } - - protected void simpleAccept(Project project, RowVisitor visitor) { - for (int i = 0; i < project.rows.size(); i++) { - Row row = project.rows.get(i); - - boolean ok = true; - for (RowFilter rowFilter : _rowFilters) { - if (!rowFilter.filterRow(project, i, row)) { - ok = false; - break; - } - } - - if (ok) { - visitor.visit(project, i, row, false); - } - } - } - - protected void contextualAccept(Project project, RowVisitor visitor) { int lastVisitedRow = -1; - - for (int i = 0; i < project.rows.size(); i++) { + int lastRecordRowAccepted = -1; + + int c = project.rows.size(); + for (int i = 0; i < c; i++) { Row row = project.rows.get(i); - boolean ok = true; - for (RowFilter rowFilter : _rowFilters) { - if (!rowFilter.filterRow(project, i, row)) { - ok = false; - break; - } + if (checkRow(project, i, row)) { + if (row.recordIndex >= 0) { + // this is a record row itself + + lastRecordRowAccepted = i; + } + + visitRow(project, visitor, i, row, lastVisitedRow); + + lastVisitedRow = i; + } else if ( + _includeDependent && + row.recordIndex < 0 && + row.contextRows != null && + row.contextRows.size() > 0) { + + if (row.contextRows.get(0) == lastRecordRowAccepted) { + visitor.visit(project, i, row, false, true); + lastVisitedRow = i; + } } - - if (ok) { - if (row.contextRows != null && lastVisitedRow < i - 1) { - for (int contextRowIndex : row.contextRows) { - if (contextRowIndex > lastVisitedRow) { - visitor.visit( - project, - contextRowIndex, - project.rows.get(contextRowIndex), - true - ); - lastVisitedRow = contextRowIndex; - } + } + } + + protected void visitRow(Project project, RowVisitor visitor, int rowIndex, Row row, int lastVisitedRow) { + if (_includeContextual) { + if (row.contextRows != null && lastVisitedRow < rowIndex - 1) { + for (int contextRowIndex : row.contextRows) { + if (contextRowIndex > lastVisitedRow) { + visitor.visit( + project, + contextRowIndex, + project.rows.get(contextRowIndex), + true, + false + ); + lastVisitedRow = contextRowIndex; } } - - visitor.visit(project, i, row, false); - lastVisitedRow = i; + } + + visitor.visit(project, rowIndex, row, false, false); + } else { + visitor.visit(project, rowIndex, row, false, false); + } + } + + protected boolean checkRow(Project project, int rowIndex, Row row) { + for (RowFilter rowFilter : _rowFilters) { + if (!rowFilter.filterRow(project, rowIndex, row)) { + return false; } } + return true; } } diff --git a/src/main/java/com/metaweb/gridworks/browsing/Engine.java b/src/main/java/com/metaweb/gridworks/browsing/Engine.java index f3de287f5..afa85489a 100644 --- a/src/main/java/com/metaweb/gridworks/browsing/Engine.java +++ b/src/main/java/com/metaweb/gridworks/browsing/Engine.java @@ -20,17 +20,18 @@ import com.metaweb.gridworks.model.Project; public class Engine implements Jsonizable { protected Project _project; protected List _facets = new LinkedList(); + protected boolean _includeDependent; public Engine(Project project) { _project = project; } - public FilteredRows getAllFilteredRows(boolean contextual) { - return getFilteredRows(null, contextual); + public FilteredRows getAllFilteredRows(boolean includeContextual) { + return getFilteredRows(null, includeContextual); } - public FilteredRows getFilteredRows(Facet except, boolean contextual) { - ConjunctiveFilteredRows cfr = new ConjunctiveFilteredRows(contextual); + public FilteredRows getFilteredRows(Facet except, boolean includeContextual) { + ConjunctiveFilteredRows cfr = new ConjunctiveFilteredRows(includeContextual, _includeDependent); for (Facet facet : _facets) { if (facet != except) { RowFilter rowFilter = facet.getRowFilter(); @@ -64,6 +65,10 @@ public class Engine implements Jsonizable { _facets.add(facet); } } + + if (o.has("includeDependent") && !o.isNull("includeDependent")) { + _includeDependent = o.getBoolean("includeDependent"); + } } public void computeFacets() throws JSONException { @@ -78,11 +83,13 @@ public class Engine implements Jsonizable { throws JSONException { writer.object(); - writer.key("facets"); writer.array(); - for (Facet facet : _facets) { - facet.write(writer, options); - } - writer.endArray(); + writer.key("facets"); + writer.array(); + for (Facet facet : _facets) { + facet.write(writer, options); + } + writer.endArray(); + writer.key("includeDependent"); writer.value(_includeDependent); writer.endObject(); } } diff --git a/src/main/java/com/metaweb/gridworks/browsing/RowVisitor.java b/src/main/java/com/metaweb/gridworks/browsing/RowVisitor.java index 80b3263c5..9f160a2cd 100644 --- a/src/main/java/com/metaweb/gridworks/browsing/RowVisitor.java +++ b/src/main/java/com/metaweb/gridworks/browsing/RowVisitor.java @@ -4,6 +4,11 @@ import com.metaweb.gridworks.model.Project; import com.metaweb.gridworks.model.Row; public interface RowVisitor { - public boolean visit(Project project, int rowIndex, Row row, boolean contextual); - + public boolean visit( + Project project, + int rowIndex, // zero-based row index + Row row, + boolean contextual, // true if this row is included because it's the context row of an included row + boolean dependent // true if this row is included because it depends on an included row + ); } diff --git a/src/main/java/com/metaweb/gridworks/browsing/facets/ExpressionNominalRowGrouper.java b/src/main/java/com/metaweb/gridworks/browsing/facets/ExpressionNominalRowGrouper.java index abf687a6d..cd063fc3b 100644 --- a/src/main/java/com/metaweb/gridworks/browsing/facets/ExpressionNominalRowGrouper.java +++ b/src/main/java/com/metaweb/gridworks/browsing/facets/ExpressionNominalRowGrouper.java @@ -25,7 +25,7 @@ public class ExpressionNominalRowGrouper implements RowVisitor { _cellIndex = cellIndex; } - public boolean visit(Project project, int rowIndex, Row row, boolean contextual) { + public boolean visit(Project project, int rowIndex, Row row, boolean includeContextual, boolean includeDependent) { Cell cell = _cellIndex < 0 ? null : row.getCell(_cellIndex); Properties bindings = ExpressionUtils.createBindings(project); diff --git a/src/main/java/com/metaweb/gridworks/browsing/facets/ExpressionNumericRowBinner.java b/src/main/java/com/metaweb/gridworks/browsing/facets/ExpressionNumericRowBinner.java index 4af316717..2add2c968 100644 --- a/src/main/java/com/metaweb/gridworks/browsing/facets/ExpressionNumericRowBinner.java +++ b/src/main/java/com/metaweb/gridworks/browsing/facets/ExpressionNumericRowBinner.java @@ -28,7 +28,7 @@ public class ExpressionNumericRowBinner implements RowVisitor { bins = new int[_index.getBins().length]; } - public boolean visit(Project project, int rowIndex, Row row, boolean contextual) { + public boolean visit(Project project, int rowIndex, Row row, boolean includeContextual, boolean includeDependent) { Cell cell = row.getCell(_cellIndex); Properties bindings = ExpressionUtils.createBindings(project); diff --git a/src/main/java/com/metaweb/gridworks/clustering/binning/BinningClusterer.java b/src/main/java/com/metaweb/gridworks/clustering/binning/BinningClusterer.java index 4a1aa8d9f..f3a934148 100644 --- a/src/main/java/com/metaweb/gridworks/clustering/binning/BinningClusterer.java +++ b/src/main/java/com/metaweb/gridworks/clustering/binning/BinningClusterer.java @@ -62,7 +62,7 @@ public class BinningClusterer extends Clusterer { } } - public boolean visit(Project project, int rowIndex, Row row, boolean contextual) { + public boolean visit(Project project, int rowIndex, Row row, boolean includeContextual, boolean includeDependent) { Cell cell = row.getCell(_colindex); if (cell != null && cell.value != null) { String v = cell.value.toString(); diff --git a/src/main/java/com/metaweb/gridworks/clustering/knn/kNNClusterer.java b/src/main/java/com/metaweb/gridworks/clustering/knn/kNNClusterer.java index d89f49950..c721967b9 100644 --- a/src/main/java/com/metaweb/gridworks/clustering/knn/kNNClusterer.java +++ b/src/main/java/com/metaweb/gridworks/clustering/knn/kNNClusterer.java @@ -76,7 +76,7 @@ public class kNNClusterer extends Clusterer { } } - public boolean visit(Project project, int rowIndex, Row row, boolean contextual) { + public boolean visit(Project project, int rowIndex, Row row, boolean includeContextual, boolean includeDependent) { Cell cell = row.cells.get(_colindex); if (cell != null && cell.value != null) { Object v = cell.value; @@ -114,7 +114,7 @@ public class kNNClusterer extends Clusterer { } } - public boolean visit(Project project, int rowIndex, Row row, boolean contextual) { + public boolean visit(Project project, int rowIndex, Row row, boolean includeContextual, boolean includeDependent) { Cell cell = row.getCell(_colindex); if (cell != null && cell.value != null) { Object v = cell.value; diff --git a/src/main/java/com/metaweb/gridworks/commands/info/GetRowsCommand.java b/src/main/java/com/metaweb/gridworks/commands/info/GetRowsCommand.java index c6b4851e4..1b587557c 100644 --- a/src/main/java/com/metaweb/gridworks/commands/info/GetRowsCommand.java +++ b/src/main/java/com/metaweb/gridworks/commands/info/GetRowsCommand.java @@ -53,7 +53,7 @@ public class GetRowsCommand extends Command { } @Override - public boolean internalVisit(int rowIndex, Row row, boolean contextual) { + public boolean internalVisit(int rowIndex, Row row, boolean contextual, boolean includeDependent) { try { if (contextual) { options.put("extra", extra); @@ -99,19 +99,19 @@ public class GetRowsCommand extends Command { this.limit = limit; } - public boolean visit(Project project, int rowIndex, Row row, boolean contextual) { + public boolean visit(Project project, int rowIndex, Row row, boolean includeContextual, boolean includeDependent) { boolean r = false; if (total >= start && total < start + limit) { - r = internalVisit(rowIndex, row, contextual); + r = internalVisit(rowIndex, row, includeContextual, includeDependent); } - if (!contextual) { + if (!includeContextual) { total++; } return r; } - protected boolean internalVisit(int rowIndex, Row row, boolean contextual) { + protected boolean internalVisit(int rowIndex, Row row, boolean contextual, boolean includeDependent) { return false; } } diff --git a/src/main/java/com/metaweb/gridworks/exporters/TsvExporter.java b/src/main/java/com/metaweb/gridworks/exporters/TsvExporter.java index ca8a35398..7857ab419 100644 --- a/src/main/java/com/metaweb/gridworks/exporters/TsvExporter.java +++ b/src/main/java/com/metaweb/gridworks/exporters/TsvExporter.java @@ -38,7 +38,7 @@ public class TsvExporter implements Exporter { return this; } - public boolean visit(Project project, int rowIndex, Row row, boolean contextual) { + public boolean visit(Project project, int rowIndex, Row row, boolean contextual, boolean includeDependent) { boolean first = true; try { for (Column column : project.columnModel.columns) { diff --git a/src/main/java/com/metaweb/gridworks/model/Project.java b/src/main/java/com/metaweb/gridworks/model/Project.java index c7d63915f..623cf8c33 100644 --- a/src/main/java/com/metaweb/gridworks/model/Project.java +++ b/src/main/java/com/metaweb/gridworks/model/Project.java @@ -246,13 +246,17 @@ public class Project { lastNonBlankRowsByGroup[i] = -1; } + int rowCount = rows.size(); + int groupCount = keyedGroups.size(); + int recordIndex = 0; - for (int r = 0; r < rows.size(); r++) { + for (int r = 0; r < rowCount; r++) { Row row = rows.get(r); + row.contextRows = null; row.contextRowSlots = null; row.contextCellSlots = null; - for (int g = 0; g < keyedGroups.size(); g++) { + for (int g = 0; g < groupCount; g++) { Group group = keyedGroups.get(g); if (!ExpressionUtils.isNonBlankData(row.getCellValue(group.keyCellIndex))) { @@ -296,6 +300,7 @@ public class Project { rootKeyedGroup.cellIndices = new int[count - 1]; rootKeyedGroup.keyCellIndex = columnModel.columns.get(columnModel.getKeyColumnIndex()).getCellIndex(); + for (int i = 0; i < count; i++) { if (i < rootKeyedGroup.keyCellIndex) { rootKeyedGroup.cellIndices[i] = i; diff --git a/src/main/java/com/metaweb/gridworks/operations/ColumnAdditionOperation.java b/src/main/java/com/metaweb/gridworks/operations/ColumnAdditionOperation.java index cec825294..5010e07d1 100644 --- a/src/main/java/com/metaweb/gridworks/operations/ColumnAdditionOperation.java +++ b/src/main/java/com/metaweb/gridworks/operations/ColumnAdditionOperation.java @@ -121,10 +121,10 @@ public class ColumnAdditionOperation extends EngineDependentOperation { Properties bindings = ExpressionUtils.createBindings(project); return new RowVisitor() { - int cellIndex; - Properties bindings; - List cellsAtRows; - Evaluable eval; + int cellIndex; + Properties bindings; + List cellsAtRows; + Evaluable eval; public RowVisitor init(int cellIndex, Properties bindings, List cellsAtRows, Evaluable eval) { this.cellIndex = cellIndex; @@ -134,7 +134,7 @@ public class ColumnAdditionOperation extends EngineDependentOperation { return this; } - public boolean visit(Project project, int rowIndex, Row row, boolean contextual) { + public boolean visit(Project project, int rowIndex, Row row, boolean includeContextual, boolean includeDependent) { Cell cell = row.getCell(cellIndex); ExpressionUtils.bind(bindings, row, rowIndex, cell); diff --git a/src/main/java/com/metaweb/gridworks/operations/MassEditOperation.java b/src/main/java/com/metaweb/gridworks/operations/MassEditOperation.java index ed3e8c3ef..08d21e8ee 100644 --- a/src/main/java/com/metaweb/gridworks/operations/MassEditOperation.java +++ b/src/main/java/com/metaweb/gridworks/operations/MassEditOperation.java @@ -163,7 +163,7 @@ public class MassEditOperation extends EngineDependentMassCellOperation { return this; } - public boolean visit(Project project, int rowIndex, Row row, boolean contextual) { + public boolean visit(Project project, int rowIndex, Row row, boolean includeContextual, boolean includeDependent) { Cell cell = row.getCell(cellIndex); ExpressionUtils.bind(bindings, row, rowIndex, cell); diff --git a/src/main/java/com/metaweb/gridworks/operations/ReconDiscardJudgmentsOperation.java b/src/main/java/com/metaweb/gridworks/operations/ReconDiscardJudgmentsOperation.java index 0eacc7b9d..861922560 100644 --- a/src/main/java/com/metaweb/gridworks/operations/ReconDiscardJudgmentsOperation.java +++ b/src/main/java/com/metaweb/gridworks/operations/ReconDiscardJudgmentsOperation.java @@ -69,7 +69,7 @@ public class ReconDiscardJudgmentsOperation extends EngineDependentMassCellOpera return this; } - public boolean visit(Project project, int rowIndex, Row row, boolean contextual) { + public boolean visit(Project project, int rowIndex, Row row, boolean includeContextual, boolean includeDependent) { Cell cell = row.getCell(cellIndex); if (cell != null && cell.recon != null) { Recon recon = cell.recon.dup(); diff --git a/src/main/java/com/metaweb/gridworks/operations/ReconJudgeSimilarCellsOperation.java b/src/main/java/com/metaweb/gridworks/operations/ReconJudgeSimilarCellsOperation.java index d45493163..87b311487 100644 --- a/src/main/java/com/metaweb/gridworks/operations/ReconJudgeSimilarCellsOperation.java +++ b/src/main/java/com/metaweb/gridworks/operations/ReconJudgeSimilarCellsOperation.java @@ -159,7 +159,7 @@ public class ReconJudgeSimilarCellsOperation extends EngineDependentMassCellOper return this; } - public boolean visit(Project project, int rowIndex, Row row, boolean contextual) { + public boolean visit(Project project, int rowIndex, Row row, boolean includeContextual, boolean includeDependent) { Cell cell = row.getCell(_cellIndex); if (cell != null && ExpressionUtils.isNonBlankData(cell.value) && diff --git a/src/main/java/com/metaweb/gridworks/operations/ReconMarkNewTopicsOperation.java b/src/main/java/com/metaweb/gridworks/operations/ReconMarkNewTopicsOperation.java index 4248df511..2a636fbe1 100644 --- a/src/main/java/com/metaweb/gridworks/operations/ReconMarkNewTopicsOperation.java +++ b/src/main/java/com/metaweb/gridworks/operations/ReconMarkNewTopicsOperation.java @@ -82,7 +82,7 @@ public class ReconMarkNewTopicsOperation extends EngineDependentMassCellOperatio return this; } - public boolean visit(Project project, int rowIndex, Row row, boolean contextual) { + public boolean visit(Project project, int rowIndex, Row row, boolean includeContextual, boolean includeDependent) { Cell cell = row.getCell(cellIndex); if (cell != null) { Recon recon = null; diff --git a/src/main/java/com/metaweb/gridworks/operations/ReconMatchBestCandidatesOperation.java b/src/main/java/com/metaweb/gridworks/operations/ReconMatchBestCandidatesOperation.java index dd475a4ab..34f88636b 100644 --- a/src/main/java/com/metaweb/gridworks/operations/ReconMatchBestCandidatesOperation.java +++ b/src/main/java/com/metaweb/gridworks/operations/ReconMatchBestCandidatesOperation.java @@ -69,7 +69,7 @@ public class ReconMatchBestCandidatesOperation extends EngineDependentMassCellOp return this; } - public boolean visit(Project project, int rowIndex, Row row, boolean contextual) { + public boolean visit(Project project, int rowIndex, Row row, boolean includeContextual, boolean includeDependent) { if (cellIndex < row.cells.size()) { Cell cell = row.cells.get(cellIndex); if (cell.recon != null) { diff --git a/src/main/java/com/metaweb/gridworks/operations/ReconMatchSpecificTopicOperation.java b/src/main/java/com/metaweb/gridworks/operations/ReconMatchSpecificTopicOperation.java index 3d3307192..3aace050b 100644 --- a/src/main/java/com/metaweb/gridworks/operations/ReconMatchSpecificTopicOperation.java +++ b/src/main/java/com/metaweb/gridworks/operations/ReconMatchSpecificTopicOperation.java @@ -103,7 +103,7 @@ public class ReconMatchSpecificTopicOperation extends EngineDependentMassCellOpe return this; } - public boolean visit(Project project, int rowIndex, Row row, boolean contextual) { + public boolean visit(Project project, int rowIndex, Row row, boolean includeContextual, boolean includeDependent) { if (cellIndex < row.cells.size()) { Cell cell = row.cells.get(cellIndex); diff --git a/src/main/java/com/metaweb/gridworks/operations/ReconOperation.java b/src/main/java/com/metaweb/gridworks/operations/ReconOperation.java index d8bb36ca5..ae29a582a 100644 --- a/src/main/java/com/metaweb/gridworks/operations/ReconOperation.java +++ b/src/main/java/com/metaweb/gridworks/operations/ReconOperation.java @@ -170,7 +170,7 @@ public class ReconOperation extends EngineDependentOperation { FilteredRows filteredRows = engine.getAllFilteredRows(false); filteredRows.accept(_project, new RowVisitor() { - public boolean visit(Project project, int rowIndex, Row row, boolean contextual) { + public boolean visit(Project project, int rowIndex, Row row, boolean includeContextual, boolean includeDependent) { if (_cellIndex < row.cells.size()) { Cell cell = row.cells.get(_cellIndex); if (cell != null && ExpressionUtils.isNonBlankData(cell.value)) { diff --git a/src/main/java/com/metaweb/gridworks/operations/RowStarOperation.java b/src/main/java/com/metaweb/gridworks/operations/RowStarOperation.java index 0e650e3ff..f122ed00d 100644 --- a/src/main/java/com/metaweb/gridworks/operations/RowStarOperation.java +++ b/src/main/java/com/metaweb/gridworks/operations/RowStarOperation.java @@ -77,7 +77,7 @@ public class RowStarOperation extends EngineDependentOperation { return this; } - public boolean visit(Project project, int rowIndex, Row row, boolean contextual) { + public boolean visit(Project project, int rowIndex, Row row, boolean includeContextual, boolean includeDependent) { if (row.starred != _starred) { RowStarChange change = new RowStarChange(rowIndex, _starred); diff --git a/src/main/java/com/metaweb/gridworks/operations/TextTransformOperation.java b/src/main/java/com/metaweb/gridworks/operations/TextTransformOperation.java index 71a92a107..2ff4dabf6 100644 --- a/src/main/java/com/metaweb/gridworks/operations/TextTransformOperation.java +++ b/src/main/java/com/metaweb/gridworks/operations/TextTransformOperation.java @@ -118,7 +118,7 @@ public class TextTransformOperation extends EngineDependentMassCellOperation { return this; } - public boolean visit(Project project, int rowIndex, Row row, boolean contextual) { + public boolean visit(Project project, int rowIndex, Row row, boolean includeContextual, boolean includeDependent) { Cell cell = row.getCell(cellIndex); Object oldValue = cell != null ? cell.value : null; diff --git a/src/main/webapp/scripts/project/browsing-engine.js b/src/main/webapp/scripts/project/browsing-engine.js index 5ef5078d0..5203b3e63 100644 --- a/src/main/webapp/scripts/project/browsing-engine.js +++ b/src/main/webapp/scripts/project/browsing-engine.js @@ -42,7 +42,10 @@ BrowsingEngine.prototype._initializeUI = function() { this._div.html( '
refreshing facets ...
' + - '' + + '
' + + ' show dependent rows • ' + + 'refresh
' + + '' + '
    ' ); this._elmts = DOM.bind(this._div); @@ -54,6 +57,10 @@ BrowsingEngine.prototype._initializeUI = function() { }); this._elmts.facets.disableSelection(); + this._elmts.includeDependentRowsCheck.change(function() { + Gridworks.update({ engineChanged: true }); + }); + this._elmts.refreshLink.click(function() { self.update(); }); }; @@ -73,7 +80,10 @@ BrowsingEngine.prototype._updateFacetOrder = function() { }; BrowsingEngine.prototype.getJSON = function(keepUnrestrictedFacets) { - var a = { facets: [] }; + var a = { + facets: [], + includeDependent: this._elmts.includeDependentRowsCheck[0].checked + }; for (var i = 0; i < this._facets.length; i++) { var facet = this._facets[i]; if (keepUnrestrictedFacets || facet.facet.hasSelection()) {