From 496823e5646435634fb1222770be4dfb33224afc Mon Sep 17 00:00:00 2001 From: David Huynh Date: Thu, 20 May 2010 22:10:34 +0000 Subject: [PATCH] Added start() and end() methods to RowVisitor and RecordVisitor so visitors can do things before and after all visitations. Added sorting package. It's not hooked up, yet. git-svn-id: http://google-refine.googlecode.com/svn/trunk@834 7d457c2a-affb-35e4-300a-418c747d4874 --- .../metaweb/gridworks/browsing/Engine.java | 30 ++-- .../gridworks/browsing/RecordVisitor.java | 4 + .../gridworks/browsing/RowVisitor.java | 4 + .../facets/ScatterplotDrawingRowVisitor.java | 10 ++ .../util/ConjunctiveFilteredRecords.java | 24 ++-- .../util/ConjunctiveFilteredRows.java | 20 ++- .../util/ExpressionNominalValueGrouper.java | 10 ++ .../util/ExpressionNumericValueBinner.java | 10 ++ .../util/RowVisitorAsRecordVisitor.java | 10 ++ .../clustering/binning/BinningClusterer.java | 10 ++ .../clustering/knn/kNNClusterer.java | 20 +++ .../commands/row/GetRowsCommand.java | 10 ++ .../exporters/HtmlTableExporter.java | 10 ++ .../gridworks/exporters/TsvExporter.java | 10 ++ .../gridworks/exporters/XlsExporter.java | 10 ++ .../operations/ColumnAdditionOperation.java | 10 ++ .../operations/ColumnSplitOperation.java | 10 ++ .../operations/ExtendDataOperation.java | 11 ++ .../operations/MassEditOperation.java | 10 ++ .../ReconDiscardJudgmentsOperation.java | 10 ++ .../ReconJudgeSimilarCellsOperation.java | 10 ++ .../ReconMarkNewTopicsOperation.java | 10 ++ .../ReconMatchBestCandidatesOperation.java | 10 ++ .../ReconMatchSpecificTopicOperation.java | 10 ++ .../gridworks/operations/ReconOperation.java | 10 ++ .../operations/RowFlagOperation.java | 10 ++ .../operations/RowRemovalOperation.java | 10 ++ .../operations/RowStarOperation.java | 10 ++ .../operations/TextTransformOperation.java | 10 ++ .../metaweb/gridworks/sorting/BaseSorter.java | 136 ++++++++++++++++++ .../gridworks/sorting/BooleanCriterion.java | 32 +++++ .../metaweb/gridworks/sorting/Criterion.java | 94 ++++++++++++ .../gridworks/sorting/DateCriterion.java | 35 +++++ .../gridworks/sorting/NumberCriterion.java | 50 +++++++ .../sorting/SortingRecordVisitor.java | 60 ++++++++ .../gridworks/sorting/SortingRowVisitor.java | 69 +++++++++ .../gridworks/sorting/StringCriterion.java | 40 ++++++ 37 files changed, 824 insertions(+), 25 deletions(-) create mode 100644 src/main/java/com/metaweb/gridworks/sorting/BaseSorter.java create mode 100644 src/main/java/com/metaweb/gridworks/sorting/BooleanCriterion.java create mode 100644 src/main/java/com/metaweb/gridworks/sorting/Criterion.java create mode 100644 src/main/java/com/metaweb/gridworks/sorting/DateCriterion.java create mode 100644 src/main/java/com/metaweb/gridworks/sorting/NumberCriterion.java create mode 100644 src/main/java/com/metaweb/gridworks/sorting/SortingRecordVisitor.java create mode 100644 src/main/java/com/metaweb/gridworks/sorting/SortingRowVisitor.java create mode 100644 src/main/java/com/metaweb/gridworks/sorting/StringCriterion.java diff --git a/src/main/java/com/metaweb/gridworks/browsing/Engine.java b/src/main/java/com/metaweb/gridworks/browsing/Engine.java index 2176288fd..cd57bbf23 100644 --- a/src/main/java/com/metaweb/gridworks/browsing/Engine.java +++ b/src/main/java/com/metaweb/gridworks/browsing/Engine.java @@ -51,11 +51,17 @@ public class Engine implements Jsonizable { 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); - } + try { + visitor.start(project); + + int c = project.rows.size(); + for (int rowIndex = 0; rowIndex < c; rowIndex++) { + Row row = project.rows.get(rowIndex); + visitor.visit(project, rowIndex, row); + } + } finally { + visitor.end(project); + } } }; } @@ -86,10 +92,16 @@ public class Engine implements Jsonizable { 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)); - } + try { + visitor.start(project); + + int c = project.recordModel.getRecordCount(); + for (int r = 0; r < c; r++) { + visitor.visit(project, project.recordModel.getRecord(r)); + } + } finally { + visitor.end(project); + } } }; } diff --git a/src/main/java/com/metaweb/gridworks/browsing/RecordVisitor.java b/src/main/java/com/metaweb/gridworks/browsing/RecordVisitor.java index 83194fe02..e78661fc6 100644 --- a/src/main/java/com/metaweb/gridworks/browsing/RecordVisitor.java +++ b/src/main/java/com/metaweb/gridworks/browsing/RecordVisitor.java @@ -8,8 +8,12 @@ import com.metaweb.gridworks.model.Record; * particular criteria, such as facets' constraints. */ public interface RecordVisitor { + public void start(Project project); // called before any visit() call + public boolean visit( Project project, Record record ); + + public void end(Project project); // called after all visit() calls } diff --git a/src/main/java/com/metaweb/gridworks/browsing/RowVisitor.java b/src/main/java/com/metaweb/gridworks/browsing/RowVisitor.java index e7021a868..7ca073e76 100644 --- a/src/main/java/com/metaweb/gridworks/browsing/RowVisitor.java +++ b/src/main/java/com/metaweb/gridworks/browsing/RowVisitor.java @@ -8,9 +8,13 @@ import com.metaweb.gridworks.model.Row; * particular criteria, such as facets' constraints. */ public interface RowVisitor { + public void start(Project project); // called before any visit() call + public boolean visit( Project project, int rowIndex, // zero-based row index Row row ); + + public void end(Project project); // called after all visit() calls } diff --git a/src/main/java/com/metaweb/gridworks/browsing/facets/ScatterplotDrawingRowVisitor.java b/src/main/java/com/metaweb/gridworks/browsing/facets/ScatterplotDrawingRowVisitor.java index 55241aca7..1c6c041d9 100644 --- a/src/main/java/com/metaweb/gridworks/browsing/facets/ScatterplotDrawingRowVisitor.java +++ b/src/main/java/com/metaweb/gridworks/browsing/facets/ScatterplotDrawingRowVisitor.java @@ -87,6 +87,16 @@ public class ScatterplotDrawingRowVisitor implements RowVisitor, RecordVisitor { g2.setPaint(color); } + @Override + public void start(Project project) { + // nothing to do + } + + @Override + public void end(Project project) { + // nothing to do + } + @Override public boolean visit(Project project, int rowIndex, Row row) { Cell cellx = row.getCell(col_x); diff --git a/src/main/java/com/metaweb/gridworks/browsing/util/ConjunctiveFilteredRecords.java b/src/main/java/com/metaweb/gridworks/browsing/util/ConjunctiveFilteredRecords.java index 7b90abe18..e17b453f8 100644 --- a/src/main/java/com/metaweb/gridworks/browsing/util/ConjunctiveFilteredRecords.java +++ b/src/main/java/com/metaweb/gridworks/browsing/util/ConjunctiveFilteredRecords.java @@ -21,15 +21,21 @@ public class ConjunctiveFilteredRecords implements FilteredRecords { @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; - } - } - } + try { + visitor.start(project); + + 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; + } + } + } + } finally { + visitor.end(project); + } } protected boolean matchRecord(Project project, Record record) { diff --git a/src/main/java/com/metaweb/gridworks/browsing/util/ConjunctiveFilteredRows.java b/src/main/java/com/metaweb/gridworks/browsing/util/ConjunctiveFilteredRows.java index bae1a4dd4..d470c6dc7 100644 --- a/src/main/java/com/metaweb/gridworks/browsing/util/ConjunctiveFilteredRows.java +++ b/src/main/java/com/metaweb/gridworks/browsing/util/ConjunctiveFilteredRows.java @@ -21,13 +21,19 @@ public class ConjunctiveFilteredRows implements FilteredRows { } 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); - if (matchRow(project, rowIndex, row)) { - visitRow(project, visitor, rowIndex, row); - } - } + try { + visitor.start(project); + + int c = project.rows.size(); + for (int rowIndex = 0; rowIndex < c; rowIndex++) { + Row row = project.rows.get(rowIndex); + if (matchRow(project, rowIndex, row)) { + visitRow(project, visitor, rowIndex, row); + } + } + } finally { + visitor.end(project); + } } protected void visitRow(Project project, RowVisitor visitor, int rowIndex, Row row) { diff --git a/src/main/java/com/metaweb/gridworks/browsing/util/ExpressionNominalValueGrouper.java b/src/main/java/com/metaweb/gridworks/browsing/util/ExpressionNominalValueGrouper.java index b6774214a..31eac1298 100644 --- a/src/main/java/com/metaweb/gridworks/browsing/util/ExpressionNominalValueGrouper.java +++ b/src/main/java/com/metaweb/gridworks/browsing/util/ExpressionNominalValueGrouper.java @@ -56,6 +56,16 @@ public class ExpressionNominalValueGrouper implements RowVisitor, RecordVisitor _cellIndex = cellIndex; } + @Override + public void start(Project project) { + // nothing to do + } + + @Override + public void end(Project project) { + // nothing to do + } + public boolean visit(Project project, int rowIndex, Row row) { hasError = false; hasBlank = false; diff --git a/src/main/java/com/metaweb/gridworks/browsing/util/ExpressionNumericValueBinner.java b/src/main/java/com/metaweb/gridworks/browsing/util/ExpressionNumericValueBinner.java index b83c1ac21..c43be41ad 100644 --- a/src/main/java/com/metaweb/gridworks/browsing/util/ExpressionNumericValueBinner.java +++ b/src/main/java/com/metaweb/gridworks/browsing/util/ExpressionNumericValueBinner.java @@ -50,6 +50,16 @@ public class ExpressionNumericValueBinner implements RowVisitor, RecordVisitor { bins = new int[_index.getBins().length]; } + @Override + public void start(Project project) { + // nothing to do + } + + @Override + public void end(Project project) { + // nothing to do + } + @Override public boolean visit(Project project, int rowIndex, Row row) { resetFlags(); diff --git a/src/main/java/com/metaweb/gridworks/browsing/util/RowVisitorAsRecordVisitor.java b/src/main/java/com/metaweb/gridworks/browsing/util/RowVisitorAsRecordVisitor.java index 9d2a151c8..d67e10f20 100644 --- a/src/main/java/com/metaweb/gridworks/browsing/util/RowVisitorAsRecordVisitor.java +++ b/src/main/java/com/metaweb/gridworks/browsing/util/RowVisitorAsRecordVisitor.java @@ -12,6 +12,16 @@ public class RowVisitorAsRecordVisitor implements RecordVisitor { _rowVisitor = rowVisitor; } + @Override + public void start(Project project) { + _rowVisitor.start(project); + } + + @Override + public void end(Project project) { + _rowVisitor.end(project); + } + @Override public boolean visit(Project project, Record record) { for (int r = record.fromRowIndex; r < record.toRowIndex; r++) { 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 608e1ddb1..ec30c4c76 100644 --- a/src/main/java/com/metaweb/gridworks/clustering/binning/BinningClusterer.java +++ b/src/main/java/com/metaweb/gridworks/clustering/binning/BinningClusterer.java @@ -66,6 +66,16 @@ public class BinningClusterer extends Clusterer { } } + @Override + public void start(Project project) { + // nothing to do + } + + @Override + public void end(Project project) { + // nothing to do + } + public boolean visit(Project project, int rowIndex, Row row) { Cell cell = row.getCell(_colindex); if (cell != null && cell.value != null) { 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 53466e784..38432e55e 100644 --- a/src/main/java/com/metaweb/gridworks/clustering/knn/kNNClusterer.java +++ b/src/main/java/com/metaweb/gridworks/clustering/knn/kNNClusterer.java @@ -80,6 +80,16 @@ public class kNNClusterer extends Clusterer { } } + @Override + public void start(Project project) { + // nothing to do + } + + @Override + public void end(Project project) { + // nothing to do + } + public boolean visit(Project project, int rowIndex, Row row) { Cell cell = row.getCell(_colindex); if (cell != null && cell.value != null) { @@ -121,6 +131,16 @@ public class kNNClusterer extends Clusterer { _clusterer = new NGramClusterer(_distance, _blockingNgramSize); } + @Override + public void start(Project project) { + // nothing to do + } + + @Override + public void end(Project project) { + // nothing to do + } + public boolean visit(Project project, int rowIndex, Row row) { Cell cell = row.getCell(_colindex); if (cell != null && cell.value != null) { diff --git a/src/main/java/com/metaweb/gridworks/commands/row/GetRowsCommand.java b/src/main/java/com/metaweb/gridworks/commands/row/GetRowsCommand.java index c49e3e4d2..f0874afcf 100644 --- a/src/main/java/com/metaweb/gridworks/commands/row/GetRowsCommand.java +++ b/src/main/java/com/metaweb/gridworks/commands/row/GetRowsCommand.java @@ -94,6 +94,16 @@ public class GetRowsCommand extends Command { this.options = options; } + @Override + public void start(Project project) { + // nothing to do + } + + @Override + public void end(Project project) { + // nothing to do + } + public boolean visit(Project project, int rowIndex, Row row) { if (total >= start && total < start + limit) { internalVisit(project, rowIndex, row); diff --git a/src/main/java/com/metaweb/gridworks/exporters/HtmlTableExporter.java b/src/main/java/com/metaweb/gridworks/exporters/HtmlTableExporter.java index 296430e3a..4926a3ccd 100644 --- a/src/main/java/com/metaweb/gridworks/exporters/HtmlTableExporter.java +++ b/src/main/java/com/metaweb/gridworks/exporters/HtmlTableExporter.java @@ -56,6 +56,16 @@ public class HtmlTableExporter implements Exporter { return this; } + @Override + public void start(Project project) { + // nothing to do + } + + @Override + public void end(Project project) { + // nothing to do + } + public boolean visit(Project project, int rowIndex, Row row) { try { writer.write(""); diff --git a/src/main/java/com/metaweb/gridworks/exporters/TsvExporter.java b/src/main/java/com/metaweb/gridworks/exporters/TsvExporter.java index 9760a617e..07684b757 100644 --- a/src/main/java/com/metaweb/gridworks/exporters/TsvExporter.java +++ b/src/main/java/com/metaweb/gridworks/exporters/TsvExporter.java @@ -48,6 +48,16 @@ public class TsvExporter implements Exporter { return this; } + @Override + public void start(Project project) { + // nothing to do + } + + @Override + public void end(Project project) { + // nothing to do + } + public boolean visit(Project project, int rowIndex, Row row) { boolean first = true; try { diff --git a/src/main/java/com/metaweb/gridworks/exporters/XlsExporter.java b/src/main/java/com/metaweb/gridworks/exporters/XlsExporter.java index ebdd2ac14..79b9c2abf 100644 --- a/src/main/java/com/metaweb/gridworks/exporters/XlsExporter.java +++ b/src/main/java/com/metaweb/gridworks/exporters/XlsExporter.java @@ -64,6 +64,16 @@ public class XlsExporter implements Exporter { return this; } + @Override + public void start(Project project) { + // nothing to do + } + + @Override + public void end(Project project) { + // nothing to do + } + public boolean visit(Project project, int rowIndex, Row row) { org.apache.poi.ss.usermodel.Row r = sheet.createRow(rowCount++); diff --git a/src/main/java/com/metaweb/gridworks/operations/ColumnAdditionOperation.java b/src/main/java/com/metaweb/gridworks/operations/ColumnAdditionOperation.java index 88ad99565..c83d8d776 100644 --- a/src/main/java/com/metaweb/gridworks/operations/ColumnAdditionOperation.java +++ b/src/main/java/com/metaweb/gridworks/operations/ColumnAdditionOperation.java @@ -135,6 +135,16 @@ public class ColumnAdditionOperation extends EngineDependentOperation { return this; } + @Override + public void start(Project project) { + // nothing to do + } + + @Override + public void end(Project project) { + // nothing to do + } + public boolean visit(Project project, int rowIndex, Row row) { Cell cell = row.getCell(cellIndex); Cell newCell = null; diff --git a/src/main/java/com/metaweb/gridworks/operations/ColumnSplitOperation.java b/src/main/java/com/metaweb/gridworks/operations/ColumnSplitOperation.java index 3dff92923..eaac625e1 100644 --- a/src/main/java/com/metaweb/gridworks/operations/ColumnSplitOperation.java +++ b/src/main/java/com/metaweb/gridworks/operations/ColumnSplitOperation.java @@ -234,6 +234,16 @@ public class ColumnSplitOperation extends EngineDependentOperation { this.tuples = tuples; } + @Override + public void start(Project project) { + // nothing to do + } + + @Override + public void end(Project project) { + // nothing to do + } + public boolean visit(Project project, int rowIndex, Row row) { Object value = row.getCellValue(cellIndex); if (ExpressionUtils.isNonBlankData(value)) { diff --git a/src/main/java/com/metaweb/gridworks/operations/ExtendDataOperation.java b/src/main/java/com/metaweb/gridworks/operations/ExtendDataOperation.java index e86cefede..8f92ba19e 100644 --- a/src/main/java/com/metaweb/gridworks/operations/ExtendDataOperation.java +++ b/src/main/java/com/metaweb/gridworks/operations/ExtendDataOperation.java @@ -148,6 +148,17 @@ public class ExtendDataOperation extends EngineDependentOperation { _rowIndices = rowIndices; return this; } + + @Override + public void start(Project project) { + // nothing to do + } + + @Override + public void end(Project project) { + // nothing to do + } + public boolean visit(Project project, int rowIndex, Row row) { Cell cell = row.getCell(_cellIndex); if (cell != null && cell.recon != null && cell.recon.match != null) { diff --git a/src/main/java/com/metaweb/gridworks/operations/MassEditOperation.java b/src/main/java/com/metaweb/gridworks/operations/MassEditOperation.java index 3264ee896..e7eda4aa8 100644 --- a/src/main/java/com/metaweb/gridworks/operations/MassEditOperation.java +++ b/src/main/java/com/metaweb/gridworks/operations/MassEditOperation.java @@ -196,6 +196,16 @@ public class MassEditOperation extends EngineDependentMassCellOperation { return this; } + @Override + public void start(Project project) { + // nothing to do + } + + @Override + public void end(Project project) { + // nothing to do + } + public boolean visit(Project project, int rowIndex, Row row) { Cell cell = row.getCell(cellIndex); Cell newCell = null; diff --git a/src/main/java/com/metaweb/gridworks/operations/ReconDiscardJudgmentsOperation.java b/src/main/java/com/metaweb/gridworks/operations/ReconDiscardJudgmentsOperation.java index 8b17ea82f..e56c69445 100644 --- a/src/main/java/com/metaweb/gridworks/operations/ReconDiscardJudgmentsOperation.java +++ b/src/main/java/com/metaweb/gridworks/operations/ReconDiscardJudgmentsOperation.java @@ -74,6 +74,16 @@ public class ReconDiscardJudgmentsOperation extends EngineDependentMassCellOpera return this; } + @Override + public void start(Project project) { + // nothing to do + } + + @Override + public void end(Project project) { + // nothing to do + } + public boolean visit(Project project, int rowIndex, Row row) { Cell cell = row.getCell(cellIndex); if (cell != null && cell.recon != null) { diff --git a/src/main/java/com/metaweb/gridworks/operations/ReconJudgeSimilarCellsOperation.java b/src/main/java/com/metaweb/gridworks/operations/ReconJudgeSimilarCellsOperation.java index 347cf80ea..f06798690 100644 --- a/src/main/java/com/metaweb/gridworks/operations/ReconJudgeSimilarCellsOperation.java +++ b/src/main/java/com/metaweb/gridworks/operations/ReconJudgeSimilarCellsOperation.java @@ -162,6 +162,16 @@ public class ReconJudgeSimilarCellsOperation extends EngineDependentMassCellOper return this; } + @Override + public void start(Project project) { + // nothing to do + } + + @Override + public void end(Project project) { + // nothing to do + } + public boolean visit(Project project, int rowIndex, Row row) { 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 9b0b81c80..1f00597da 100644 --- a/src/main/java/com/metaweb/gridworks/operations/ReconMarkNewTopicsOperation.java +++ b/src/main/java/com/metaweb/gridworks/operations/ReconMarkNewTopicsOperation.java @@ -84,6 +84,16 @@ public class ReconMarkNewTopicsOperation extends EngineDependentMassCellOperatio return this; } + @Override + public void start(Project project) { + // nothing to do + } + + @Override + public void end(Project project) { + // nothing to do + } + public boolean visit(Project project, int rowIndex, Row row) { Cell cell = row.getCell(cellIndex); if (cell != null) { diff --git a/src/main/java/com/metaweb/gridworks/operations/ReconMatchBestCandidatesOperation.java b/src/main/java/com/metaweb/gridworks/operations/ReconMatchBestCandidatesOperation.java index 4d57e4d9d..76ecb3ad1 100644 --- a/src/main/java/com/metaweb/gridworks/operations/ReconMatchBestCandidatesOperation.java +++ b/src/main/java/com/metaweb/gridworks/operations/ReconMatchBestCandidatesOperation.java @@ -75,6 +75,16 @@ public class ReconMatchBestCandidatesOperation extends EngineDependentMassCellOp return this; } + @Override + public void start(Project project) { + // nothing to do + } + + @Override + public void end(Project project) { + // nothing to do + } + public boolean visit(Project project, int rowIndex, Row row) { if (cellIndex < row.cells.size()) { Cell cell = row.cells.get(cellIndex); diff --git a/src/main/java/com/metaweb/gridworks/operations/ReconMatchSpecificTopicOperation.java b/src/main/java/com/metaweb/gridworks/operations/ReconMatchSpecificTopicOperation.java index 420d29fdc..a7ae3333b 100644 --- a/src/main/java/com/metaweb/gridworks/operations/ReconMatchSpecificTopicOperation.java +++ b/src/main/java/com/metaweb/gridworks/operations/ReconMatchSpecificTopicOperation.java @@ -108,6 +108,16 @@ public class ReconMatchSpecificTopicOperation extends EngineDependentMassCellOpe return this; } + @Override + public void start(Project project) { + // nothing to do + } + + @Override + public void end(Project project) { + // nothing to do + } + public boolean visit(Project project, int rowIndex, Row row) { Cell cell = row.getCell(cellIndex); if (cell != null) { diff --git a/src/main/java/com/metaweb/gridworks/operations/ReconOperation.java b/src/main/java/com/metaweb/gridworks/operations/ReconOperation.java index 19440bdc7..3b93541e5 100644 --- a/src/main/java/com/metaweb/gridworks/operations/ReconOperation.java +++ b/src/main/java/com/metaweb/gridworks/operations/ReconOperation.java @@ -176,6 +176,16 @@ public class ReconOperation extends EngineDependentOperation { FilteredRows filteredRows = engine.getAllFilteredRows(); filteredRows.accept(_project, new RowVisitor() { + @Override + public void start(Project project) { + // nothing to do + } + + @Override + public void end(Project project) { + // nothing to do + } + public boolean visit(Project project, int rowIndex, Row row) { if (_cellIndex < row.cells.size()) { Cell cell = row.cells.get(_cellIndex); diff --git a/src/main/java/com/metaweb/gridworks/operations/RowFlagOperation.java b/src/main/java/com/metaweb/gridworks/operations/RowFlagOperation.java index 1e3c5eb44..955a0cd6d 100644 --- a/src/main/java/com/metaweb/gridworks/operations/RowFlagOperation.java +++ b/src/main/java/com/metaweb/gridworks/operations/RowFlagOperation.java @@ -78,6 +78,16 @@ public class RowFlagOperation extends EngineDependentOperation { return this; } + @Override + public void start(Project project) { + // nothing to do + } + + @Override + public void end(Project project) { + // nothing to do + } + public boolean visit(Project project, int rowIndex, Row row) { if (row.flagged != _flagged) { RowFlagChange change = new RowFlagChange(rowIndex, _flagged); diff --git a/src/main/java/com/metaweb/gridworks/operations/RowRemovalOperation.java b/src/main/java/com/metaweb/gridworks/operations/RowRemovalOperation.java index 913727f83..c7946e1b8 100644 --- a/src/main/java/com/metaweb/gridworks/operations/RowRemovalOperation.java +++ b/src/main/java/com/metaweb/gridworks/operations/RowRemovalOperation.java @@ -70,6 +70,16 @@ public class RowRemovalOperation extends EngineDependentOperation { return this; } + @Override + public void start(Project project) { + // nothing to do + } + + @Override + public void end(Project project) { + // nothing to do + } + public boolean visit(Project project, int rowIndex, Row row) { rowIndices.add(rowIndex); diff --git a/src/main/java/com/metaweb/gridworks/operations/RowStarOperation.java b/src/main/java/com/metaweb/gridworks/operations/RowStarOperation.java index 1cf52d7df..7ff9a9635 100644 --- a/src/main/java/com/metaweb/gridworks/operations/RowStarOperation.java +++ b/src/main/java/com/metaweb/gridworks/operations/RowStarOperation.java @@ -78,6 +78,16 @@ public class RowStarOperation extends EngineDependentOperation { return this; } + @Override + public void start(Project project) { + // nothing to do + } + + @Override + public void end(Project project) { + // nothing to do + } + public boolean visit(Project project, int rowIndex, Row row) { 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 1b620a702..a099b502d 100644 --- a/src/main/java/com/metaweb/gridworks/operations/TextTransformOperation.java +++ b/src/main/java/com/metaweb/gridworks/operations/TextTransformOperation.java @@ -119,6 +119,16 @@ public class TextTransformOperation extends EngineDependentMassCellOperation { return this; } + @Override + public void start(Project project) { + // nothing to do + } + + @Override + public void end(Project project) { + // nothing to do + } + public boolean visit(Project project, int rowIndex, Row row) { Cell cell = row.getCell(cellIndex); Cell newCell = null; diff --git a/src/main/java/com/metaweb/gridworks/sorting/BaseSorter.java b/src/main/java/com/metaweb/gridworks/sorting/BaseSorter.java new file mode 100644 index 000000000..7437092b4 --- /dev/null +++ b/src/main/java/com/metaweb/gridworks/sorting/BaseSorter.java @@ -0,0 +1,136 @@ +package com.metaweb.gridworks.sorting; + +import java.util.List; + +import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; + +import com.metaweb.gridworks.expr.EvalError; +import com.metaweb.gridworks.model.Project; +import com.metaweb.gridworks.sorting.Criterion.KeyMaker; + +abstract public class BaseSorter { + protected Criterion[] _criteria; + protected KeyMaker[] _keyMakers; + protected ComparatorWrapper[] _comparatorWrappers; + protected List _keys; + + public class ComparatorWrapper { + final public int criterionIndex; + final protected int multiplier; + + public ComparatorWrapper(int criterionIndex) { + this.criterionIndex = criterionIndex; + this.multiplier = _criteria[criterionIndex].reverse ? -1 : 1; + } + + public Object getKey(Project project, Object o, int index) { + Object[] keys = _keys.get(index); + if (keys == null) { + keys = makeKeys(project, o, index); + _keys.set(index, keys); + } + return keys[criterionIndex]; + } + + public int compare(Project project, Object o1, int i1, Object o2, int i2) { + Criterion c = _criteria[criterionIndex]; + Object key1 = getKey(project, o1, i1); + Object key2 = getKey(project, o2, i2); + + if (key1 == null) { + if (key2 == null) { + return 0; + } else if (key2 instanceof EvalError) { + return c.blankPosition - c.errorPosition; + } else { + return c.blankPosition; + } + } else if (key1 instanceof EvalError) { + if (key2 == null) { + return c.errorPosition - c.blankPosition; + } else if (key2 instanceof EvalError) { + return 0; + } else { + return c.errorPosition; + } + } else { + if (key2 == null) { + return -c.blankPosition; + } else if (key2 instanceof EvalError) { + return -c.errorPosition; + } else { + return _keyMakers[criterionIndex].compareKeys(key1, key2) * multiplier; + } + } + } + } + + public void initializeFromJSON(Project project, JSONObject obj) throws JSONException { + if (obj.has("criteria") && !obj.isNull("criteria")) { + JSONArray a = obj.getJSONArray("criteria"); + int count = a.length(); + + _criteria = new Criterion[count]; + _keyMakers = new KeyMaker[count]; + _comparatorWrappers = new ComparatorWrapper[count]; + + for (int i = 0; i < count; i++) { + JSONObject obj2 = a.getJSONObject(i); + + _criteria[i] = createCriterionFromJSON(project, obj2); + _keyMakers[i] = _criteria[i].createKeyMaker(); + _comparatorWrappers[i] = new ComparatorWrapper(i); + } + } else { + _criteria = new Criterion[0]; + _keyMakers = new KeyMaker[0]; + _comparatorWrappers = new ComparatorWrapper[0]; + } + } + + public boolean hasCriteria() { + return _criteria != null && _criteria.length > 0; + } + + protected Criterion createCriterionFromJSON(Project project, JSONObject obj) throws JSONException { + String valueType = "string"; + if (obj.has("valueType") && !obj.isNull("valueType")) { + valueType = obj.getString("valueType"); + } + + Criterion c = null; + if ("boolean".equals(valueType)) { + c = new BooleanCriterion(); + } else if ("date".equals(valueType)) { + c = new DateCriterion(); + } else if ("number".equals(valueType)) { + c = new NumberCriterion(); + } else { + c = new StringCriterion(); + } + + c.initializeFromJSON(project, obj); + return c; + } + + abstract protected Object makeKey( + Project project, KeyMaker keyMaker, Criterion c, Object o, int index); + + protected Object[] makeKeys(Project project, Object o, int index) { + Object[] keys = new Object[_keyMakers.length]; + for (int i = 0; i < keys.length; i++) { + keys[i] = makeKey(project, _keyMakers[i], _criteria[i], o, index); + } + return keys; + } + + protected int compare(Project project, Object o1, int i1, Object o2, int i2) { + int c = 0; + for (int i = 0; c == 0 && i < _comparatorWrappers.length; i++) { + c = _comparatorWrappers[i].compare(project, o1, i1, o2, i2); + } + return c; + } +} diff --git a/src/main/java/com/metaweb/gridworks/sorting/BooleanCriterion.java b/src/main/java/com/metaweb/gridworks/sorting/BooleanCriterion.java new file mode 100644 index 000000000..e2d2d6282 --- /dev/null +++ b/src/main/java/com/metaweb/gridworks/sorting/BooleanCriterion.java @@ -0,0 +1,32 @@ +package com.metaweb.gridworks.sorting; + +import com.metaweb.gridworks.expr.EvalError; +import com.metaweb.gridworks.expr.ExpressionUtils; + +public class BooleanCriterion extends Criterion { + final static protected EvalError s_error = new EvalError("Not a boolean"); + + @Override + public KeyMaker createKeyMaker() { + return new KeyMaker() { + @Override + protected Object makeKey(Object value) { + if (ExpressionUtils.isNonBlankData(value)) { + if (value instanceof Boolean) { + return value; + } else if (value instanceof String) { + return Boolean.parseBoolean((String) value); + } else { + return s_error; + } + } + return value; + } + + @Override + public int compareKeys(Object key1, Object key2) { + return ((Boolean) key1).compareTo((Boolean) key2); + } + }; + } +} diff --git a/src/main/java/com/metaweb/gridworks/sorting/Criterion.java b/src/main/java/com/metaweb/gridworks/sorting/Criterion.java new file mode 100644 index 000000000..e5793a1ee --- /dev/null +++ b/src/main/java/com/metaweb/gridworks/sorting/Criterion.java @@ -0,0 +1,94 @@ +package com.metaweb.gridworks.sorting; + +import org.json.JSONException; +import org.json.JSONObject; + +import com.metaweb.gridworks.expr.ExpressionUtils; +import com.metaweb.gridworks.model.Column; +import com.metaweb.gridworks.model.Project; +import com.metaweb.gridworks.model.Record; +import com.metaweb.gridworks.model.Row; + +abstract public class Criterion { + public String columnName; + protected int cellIndex; + + // These take on positive and negative values to indicate where blanks and errors + // go relative to non-blank values. They are also relative to each another. + // Blanks and errors are not affected by the reverse flag. + public int blankPosition = 1; + public int errorPosition = 2; + + public boolean reverse; + + public void initializeFromJSON(Project project, JSONObject obj) throws JSONException { + if (obj.has("column") && !obj.isNull("column")) { + columnName = obj.getString("column"); + + Column column = project.columnModel.getColumnByName(columnName); + cellIndex = column != null ? column.getCellIndex() : -1; + } + + if (obj.has("blankPosition") && !obj.isNull("blankPosition")) { + blankPosition = obj.getInt("blankPosition"); + } + if (obj.has("errorPosition") && !obj.isNull("errorPosition")) { + blankPosition = obj.getInt("errorPosition"); + } + + if (obj.has("reverse") && !obj.isNull("reverse")) { + reverse = obj.getBoolean("reverse"); + } + } + + abstract public class KeyMaker { + public Object makeKey(Project project, Record record) { + Object error = null; + Object finalKey = null; + + for (int r = record.fromRowIndex; r < record.toRowIndex; r++) { + Object key = makeKey(project, project.rows.get(r), r); + if (ExpressionUtils.isError(key)) { + error = key; + } else if (ExpressionUtils.isNonBlankData(key)) { + if (finalKey == null) { + finalKey = key; + } else { + int c = compareKeys(finalKey, key); + if (reverse) { + if (c < 0) { // key > finalKey + finalKey = key; + } + } else { + if (c > 0) { // key < finalKey + finalKey = key; + } + } + } + } + } + + if (finalKey != null) { + return finalKey; + } else if (error != null) { + return error; + } else { + return null; + } + } + + public Object makeKey(Project project, Row row, int rowIndex) { + if (cellIndex < 0) { + return null; + } else { + Object value = row.getCellValue(cellIndex); + return makeKey(value); + } + } + + abstract public int compareKeys(Object key1, Object key2); + + abstract protected Object makeKey(Object value); + } + abstract public KeyMaker createKeyMaker(); +} diff --git a/src/main/java/com/metaweb/gridworks/sorting/DateCriterion.java b/src/main/java/com/metaweb/gridworks/sorting/DateCriterion.java new file mode 100644 index 000000000..107d54b2a --- /dev/null +++ b/src/main/java/com/metaweb/gridworks/sorting/DateCriterion.java @@ -0,0 +1,35 @@ +package com.metaweb.gridworks.sorting; + +import java.util.Calendar; +import java.util.Date; + +import com.metaweb.gridworks.expr.EvalError; +import com.metaweb.gridworks.expr.ExpressionUtils; + +public class DateCriterion extends Criterion { + final static protected EvalError s_error = new EvalError("Not a date"); + + @Override + public KeyMaker createKeyMaker() { + return new KeyMaker() { + @Override + protected Object makeKey(Object value) { + if (ExpressionUtils.isNonBlankData(value)) { + if (value instanceof Date) { + return value; + } else if (value instanceof Calendar) { + return ((Calendar) value).getTime(); + } else { + return s_error; + } + } + return value; + } + + @Override + public int compareKeys(Object key1, Object key2) { + return ((Date) key1).compareTo((Date) key2); + } + }; + } +} diff --git a/src/main/java/com/metaweb/gridworks/sorting/NumberCriterion.java b/src/main/java/com/metaweb/gridworks/sorting/NumberCriterion.java new file mode 100644 index 000000000..e2fa4c32e --- /dev/null +++ b/src/main/java/com/metaweb/gridworks/sorting/NumberCriterion.java @@ -0,0 +1,50 @@ +package com.metaweb.gridworks.sorting; + +import java.util.Calendar; +import java.util.Date; + +import com.metaweb.gridworks.expr.EvalError; +import com.metaweb.gridworks.expr.ExpressionUtils; + +public class NumberCriterion extends Criterion { + + final static protected EvalError s_error = new EvalError("Not a number"); + + @Override + public KeyMaker createKeyMaker() { + return new KeyMaker() { + @Override + protected Object makeKey(Object value) { + if (ExpressionUtils.isNonBlankData(value)) { + if (value instanceof Number) { + return value; + } else if (value instanceof Boolean) { + return ((Boolean) value).booleanValue() ? 1 : 0; + } else if (value instanceof Date) { + return ((Date) value).getTime(); + } else if (value instanceof Calendar) { + return ((Calendar) value).getTime().getTime(); + } else if (value instanceof String) { + try { + double d = Double.parseDouble((String) value); + if (!Double.isNaN(d)) { + return d; + } + } catch (NumberFormatException e) { + // fall through + } + } + return s_error; + } + return value; + } + + @Override + public int compareKeys(Object key1, Object key2) { + double d1 = ((Number) key1).doubleValue(); + double d2 = ((Number) key2).doubleValue(); + return d1 < d2 ? -1 : (d1 > d2 ? 1 : 0); + } + }; + } +} diff --git a/src/main/java/com/metaweb/gridworks/sorting/SortingRecordVisitor.java b/src/main/java/com/metaweb/gridworks/sorting/SortingRecordVisitor.java new file mode 100644 index 000000000..9cdb8cd17 --- /dev/null +++ b/src/main/java/com/metaweb/gridworks/sorting/SortingRecordVisitor.java @@ -0,0 +1,60 @@ +package com.metaweb.gridworks.sorting; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.List; + +import com.metaweb.gridworks.browsing.RecordVisitor; +import com.metaweb.gridworks.browsing.RowVisitor; +import com.metaweb.gridworks.model.Project; +import com.metaweb.gridworks.model.Record; +import com.metaweb.gridworks.sorting.Criterion.KeyMaker; + +public class SortingRecordVisitor extends BaseSorter implements RecordVisitor { + final protected RowVisitor _visitor; + protected List _records; + + public SortingRecordVisitor(RowVisitor visitor) { + _visitor = visitor; + } + + @Override + public void start(Project project) { + _records = new ArrayList(project.recordModel.getRecordCount()); + } + + @Override + public void end(Project project) { + _visitor.start(project); + + Collections.sort(_records, new Comparator() { + Project project; + + Comparator init(Project project) { + this.project = project; + return this; + } + + @Override + public int compare(Record o1, Record o2) { + return SortingRecordVisitor.this.compare(project, o1, o1.recordIndex, o2, o2.recordIndex); + } + }.init(project)); + + _visitor.end(project); + } + + @Override + public boolean visit(Project project, Record record) { + _records.add(record); + return false; + } + + @Override + protected Object makeKey( + Project project, KeyMaker keyMaker, Criterion c, Object o, int index) { + + return keyMaker.makeKey(project, (Record) o); + } +} diff --git a/src/main/java/com/metaweb/gridworks/sorting/SortingRowVisitor.java b/src/main/java/com/metaweb/gridworks/sorting/SortingRowVisitor.java new file mode 100644 index 000000000..2d608e967 --- /dev/null +++ b/src/main/java/com/metaweb/gridworks/sorting/SortingRowVisitor.java @@ -0,0 +1,69 @@ +package com.metaweb.gridworks.sorting; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.List; + +import com.metaweb.gridworks.browsing.RowVisitor; +import com.metaweb.gridworks.model.Project; +import com.metaweb.gridworks.model.Row; +import com.metaweb.gridworks.sorting.Criterion.KeyMaker; + +public class SortingRowVisitor extends BaseSorter implements RowVisitor { + final protected RowVisitor _visitor; + protected List _indexedRows; + + static protected class IndexedRow { + final int index; + final Row row; + + IndexedRow(int index, Row row) { + this.index = index; + this.row = row; + } + } + + public SortingRowVisitor(RowVisitor visitor) { + _visitor = visitor; + } + + @Override + public void start(Project project) { + _indexedRows = new ArrayList(project.rows.size()); + } + + @Override + public void end(Project project) { + _visitor.start(project); + + Collections.sort(_indexedRows, new Comparator() { + Project project; + + Comparator init(Project project) { + this.project = project; + return this; + } + + @Override + public int compare(IndexedRow o1, IndexedRow o2) { + return SortingRowVisitor.this.compare(project, o1.row, o1.index, o2.row, o2.index); + } + }.init(project)); + + _visitor.end(project); + } + + @Override + public boolean visit(Project project, int rowIndex, Row row) { + _indexedRows.add(new IndexedRow(rowIndex, row)); + return false; + } + + @Override + protected Object makeKey( + Project project, KeyMaker keyMaker, Criterion c, Object o, int index) { + + return keyMaker.makeKey(project, (Row) o, index); + } +} diff --git a/src/main/java/com/metaweb/gridworks/sorting/StringCriterion.java b/src/main/java/com/metaweb/gridworks/sorting/StringCriterion.java new file mode 100644 index 000000000..c155ee16b --- /dev/null +++ b/src/main/java/com/metaweb/gridworks/sorting/StringCriterion.java @@ -0,0 +1,40 @@ +package com.metaweb.gridworks.sorting; + +import org.json.JSONException; +import org.json.JSONObject; + +import com.metaweb.gridworks.expr.ExpressionUtils; +import com.metaweb.gridworks.model.Project; + +public class StringCriterion extends Criterion { + public boolean caseSensitive; + + @Override + public void initializeFromJSON(Project project, JSONObject obj) throws JSONException { + super.initializeFromJSON(project, obj); + + if (obj.has("caseSensitive") && !obj.isNull("caseSensitive")) { + caseSensitive = obj.getBoolean("caseSensitive"); + } + } + + @Override + public KeyMaker createKeyMaker() { + return new KeyMaker() { + @Override + protected Object makeKey(Object value) { + return (ExpressionUtils.isNonBlankData(value) && !(value instanceof String)) ? + value.toString() : value; + } + + @Override + public int compareKeys(Object key1, Object key2) { + if (StringCriterion.this.caseSensitive) { + return ((String) key1).compareTo((String) key2); + } else { + return ((String) key1).compareToIgnoreCase((String) key2); + } + } + }; + } +}