diff --git a/src/main/java/com/metaweb/gridworks/GridworksServlet.java b/src/main/java/com/metaweb/gridworks/GridworksServlet.java index 63612d136..46aef38b1 100644 --- a/src/main/java/com/metaweb/gridworks/GridworksServlet.java +++ b/src/main/java/com/metaweb/gridworks/GridworksServlet.java @@ -80,6 +80,7 @@ public class GridworksServlet extends HttpServlet { {"annotate-one-row", "com.metaweb.gridworks.commands.row.AnnotateOneRowCommand"}, {"annotate-rows", "com.metaweb.gridworks.commands.row.AnnotateRowsCommand"}, {"remove-rows", "com.metaweb.gridworks.commands.row.RemoveRowsCommand"}, + {"reorder-rows", "com.metaweb.gridworks.commands.row.ReorderRowsCommand"}, {"save-protograph", "com.metaweb.gridworks.commands.freebase.SaveProtographCommand"}, diff --git a/src/main/java/com/metaweb/gridworks/browsing/Engine.java b/src/main/java/com/metaweb/gridworks/browsing/Engine.java index cd57bbf23..0095fa62f 100644 --- a/src/main/java/com/metaweb/gridworks/browsing/Engine.java +++ b/src/main/java/com/metaweb/gridworks/browsing/Engine.java @@ -39,6 +39,13 @@ public class Engine implements Jsonizable { protected List _facets = new LinkedList(); protected Mode _mode = Mode.RowBased; + static public String modeToString(Mode mode) { + return mode == Mode.RowBased ? MODE_ROW_BASED : MODE_RECORD_BASED; + } + static public Mode stringToMode(String s) { + return MODE_ROW_BASED.equals(s) ? Mode.RowBased : Mode.RecordBased; + } + public Engine(Project project) { _project = project; } @@ -46,6 +53,9 @@ public class Engine implements Jsonizable { public Mode getMode() { return _mode; } + public void setMode(Mode mode) { + _mode = mode; + } public FilteredRows getAllRows() { return new FilteredRows() { diff --git a/src/main/java/com/metaweb/gridworks/commands/row/ReorderRowsCommand.java b/src/main/java/com/metaweb/gridworks/commands/row/ReorderRowsCommand.java new file mode 100644 index 000000000..06d7039a9 --- /dev/null +++ b/src/main/java/com/metaweb/gridworks/commands/row/ReorderRowsCommand.java @@ -0,0 +1,34 @@ +package com.metaweb.gridworks.commands.row; + +import javax.servlet.http.HttpServletRequest; + +import org.json.JSONException; +import org.json.JSONObject; + +import com.metaweb.gridworks.browsing.Engine; +import com.metaweb.gridworks.commands.EngineDependentCommand; +import com.metaweb.gridworks.model.AbstractOperation; +import com.metaweb.gridworks.model.Project; +import com.metaweb.gridworks.operations.row.RowReorderOperation; +import com.metaweb.gridworks.util.ParsingUtilities; + +public class ReorderRowsCommand extends EngineDependentCommand { + + @Override + protected AbstractOperation createOperation(Project project, + HttpServletRequest request, JSONObject engineConfig) throws Exception { + + String mode = request.getParameter("mode"); + JSONObject sorting = null; + + try{ + String json = request.getParameter("sorting"); + + sorting = (json == null) ? null : ParsingUtilities.evaluateJsonStringToObject(json); + } catch (JSONException e) { + // ignore + } + + return new RowReorderOperation(Engine.stringToMode(mode), sorting); + } +} diff --git a/src/main/java/com/metaweb/gridworks/model/changes/RowReorderChange.java b/src/main/java/com/metaweb/gridworks/model/changes/RowReorderChange.java new file mode 100644 index 000000000..1ba03e2a9 --- /dev/null +++ b/src/main/java/com/metaweb/gridworks/model/changes/RowReorderChange.java @@ -0,0 +1,94 @@ +package com.metaweb.gridworks.model.changes; + +import java.io.IOException; +import java.io.LineNumberReader; +import java.io.Writer; +import java.util.ArrayList; +import java.util.List; +import java.util.Properties; + +import com.metaweb.gridworks.history.Change; +import com.metaweb.gridworks.model.Project; +import com.metaweb.gridworks.model.Row; +import com.metaweb.gridworks.util.Pool; + +public class RowReorderChange implements Change { + final protected List _rowIndices; + + public RowReorderChange(List rowIndices) { + _rowIndices = rowIndices; + } + + public void apply(Project project) { + synchronized (project) { + List oldRows = project.rows; + List newRows = new ArrayList(oldRows.size()); + + for (Integer oldIndex : _rowIndices) { + newRows.add(oldRows.get(oldIndex)); + } + + project.rows.clear(); + project.rows.addAll(newRows); + project.update(); + } + } + + public void revert(Project project) { + synchronized (project) { + int count = project.rows.size(); + + List newRows = project.rows; + List oldRows = new ArrayList(count); + + for (int r = 0; r < count; r++) { + oldRows.add(null); + } + + for (int newIndex = 0; newIndex < count; newIndex++) { + int oldIndex = _rowIndices.get(newIndex); + Row row = newRows.get(newIndex); + oldRows.set(oldIndex, row); + } + + project.rows.clear(); + project.rows.addAll(oldRows); + project.update(); + } + } + + public void save(Writer writer, Properties options) throws IOException { + writer.write("rowIndexCount="); writer.write(Integer.toString(_rowIndices.size())); writer.write('\n'); + for (Integer index : _rowIndices) { + writer.write(index.toString()); + writer.write('\n'); + } + writer.write("/ec/\n"); // end of change marker + } + + static public Change load(LineNumberReader reader, Pool pool) throws Exception { + List rowIndices = null; + + String line; + while ((line = reader.readLine()) != null && !"/ec/".equals(line)) { + int equal = line.indexOf('='); + CharSequence field = line.subSequence(0, equal); + + if ("rowIndexCount".equals(field)) { + int count = Integer.parseInt(line.substring(equal + 1)); + + rowIndices = new ArrayList(count); + for (int i = 0; i < count; i++) { + line = reader.readLine(); + if (line != null) { + rowIndices.add(Integer.parseInt(line)); + } + } + } + } + + RowReorderChange change = new RowReorderChange(rowIndices); + + return change; + } +} diff --git a/src/main/java/com/metaweb/gridworks/operations/OperationRegistry.java b/src/main/java/com/metaweb/gridworks/operations/OperationRegistry.java index cabb9bbe8..3dc7e5578 100644 --- a/src/main/java/com/metaweb/gridworks/operations/OperationRegistry.java +++ b/src/main/java/com/metaweb/gridworks/operations/OperationRegistry.java @@ -26,6 +26,7 @@ import com.metaweb.gridworks.operations.recon.ReconOperation; import com.metaweb.gridworks.operations.row.DenormalizeOperation; import com.metaweb.gridworks.operations.row.RowFlagOperation; import com.metaweb.gridworks.operations.row.RowRemovalOperation; +import com.metaweb.gridworks.operations.row.RowReorderOperation; import com.metaweb.gridworks.operations.row.RowStarOperation; public abstract class OperationRegistry { @@ -58,6 +59,7 @@ public abstract class OperationRegistry { register("row-removal", RowRemovalOperation.class); register("row-star", RowStarOperation.class); register("row-flag", RowFlagOperation.class); + register("row-reorder", RowReorderOperation.class); register("save-protograph", SaveProtographOperation.class); register("text-transform", TextTransformOperation.class); diff --git a/src/main/java/com/metaweb/gridworks/operations/row/RowReorderOperation.java b/src/main/java/com/metaweb/gridworks/operations/row/RowReorderOperation.java new file mode 100644 index 000000000..93349cadd --- /dev/null +++ b/src/main/java/com/metaweb/gridworks/operations/row/RowReorderOperation.java @@ -0,0 +1,122 @@ +package com.metaweb.gridworks.operations.row; + + import java.util.ArrayList; +import java.util.List; +import java.util.Properties; + +import org.json.JSONException; +import org.json.JSONObject; +import org.json.JSONWriter; + +import com.metaweb.gridworks.browsing.Engine; +import com.metaweb.gridworks.browsing.RecordVisitor; +import com.metaweb.gridworks.browsing.RowVisitor; +import com.metaweb.gridworks.browsing.Engine.Mode; +import com.metaweb.gridworks.history.HistoryEntry; +import com.metaweb.gridworks.model.AbstractOperation; +import com.metaweb.gridworks.model.Project; +import com.metaweb.gridworks.model.Record; +import com.metaweb.gridworks.model.Row; +import com.metaweb.gridworks.model.changes.RowReorderChange; +import com.metaweb.gridworks.operations.OperationRegistry; +import com.metaweb.gridworks.sorting.SortingRecordVisitor; +import com.metaweb.gridworks.sorting.SortingRowVisitor; + +public class RowReorderOperation extends AbstractOperation { + static public AbstractOperation reconstruct(Project project, JSONObject obj) throws Exception { + String mode = obj.getString("mode"); + JSONObject sorting = obj.has("sorting") && !obj.isNull("sorting") ? + obj.getJSONObject("sorting") : null; + + return new RowReorderOperation(Engine.stringToMode(mode), sorting); + } + + final protected Mode _mode; + final protected JSONObject _sorting; + + public RowReorderOperation(Mode mode, JSONObject sorting) { + _mode = mode; + _sorting = sorting; + } + + public void write(JSONWriter writer, Properties options) + throws JSONException { + + writer.object(); + writer.key("op"); writer.value(OperationRegistry.s_opClassToName.get(this.getClass())); + writer.key("description"); writer.value(getBriefDescription(null)); + writer.key("mode"); writer.value(Engine.modeToString(_mode)); + writer.key("sorting"); writer.value(_sorting); + writer.endObject(); + } + + protected String getBriefDescription(Project project) { + return "Reorder rows"; + } + + protected HistoryEntry createHistoryEntry(Project project, long historyEntryID) throws Exception { + Engine engine = new Engine(project); + engine.setMode(_mode); + + List rowIndices = new ArrayList(); + if (_mode == Mode.RowBased) { + RowVisitor visitor = new IndexingVisitor(rowIndices); + if (_sorting != null) { + SortingRowVisitor srv = new SortingRowVisitor(visitor); + + srv.initializeFromJSON(project, _sorting); + visitor = srv; + } + + engine.getAllRows().accept(project, visitor); + } else { + RecordVisitor visitor = new IndexingVisitor(rowIndices); + if (_sorting != null) { + SortingRecordVisitor srv = new SortingRecordVisitor(visitor); + + srv.initializeFromJSON(project, _sorting); + visitor = srv; + } + + engine.getAllRecords().accept(project, visitor); + } + + return new HistoryEntry( + historyEntryID, + project, + "Reorder rows", + this, + new RowReorderChange(rowIndices) + ); + } + + static protected class IndexingVisitor implements RowVisitor, RecordVisitor { + List _indices; + + IndexingVisitor(List indices) { + _indices = indices; + } + + @Override + public void start(Project project) { + } + + @Override + public void end(Project project) { + } + + @Override + public boolean visit(Project project, int rowIndex, Row row) { + _indices.add(rowIndex); + return false; + } + + @Override + public boolean visit(Project project, Record record) { + for (int r = record.fromRowIndex; r < record.toRowIndex; r++) { + _indices.add(r); + } + return false; + } + } +} diff --git a/src/main/webapp/scripts/views/data-table-view.js b/src/main/webapp/scripts/views/data-table-view.js index a9936d1c1..45cbd774f 100644 --- a/src/main/webapp/scripts/views/data-table-view.js +++ b/src/main/webapp/scripts/views/data-table-view.js @@ -531,6 +531,22 @@ DataTableView.prototype._createSortingMenu = function(elmt) { self.update(); } }, + { + "label" : "Reorder Rows Permanently", + "click" : function() { + Gridworks.postProcess( + "reorder-rows", + null, + { "sorting" : JSON.stringify(self._sorting) }, + { rowMetadataChanged: true }, + { + onDone: function() { + self._sorting.criteria = []; + } + } + ); + } + }, {} ];