Implemented column addition and removal features.
git-svn-id: http://google-refine.googlecode.com/svn/trunk@41 7d457c2a-affb-35e4-300a-418c747d4874
This commit is contained in:
parent
bacb71ab6d
commit
f8e15798e2
@ -15,8 +15,10 @@ import org.json.JSONObject;
|
||||
import org.json.JSONTokener;
|
||||
|
||||
import com.metaweb.gridworks.commands.Command;
|
||||
import com.metaweb.gridworks.commands.edit.AddColumnCommand;
|
||||
import com.metaweb.gridworks.commands.edit.CreateProjectFromUploadCommand;
|
||||
import com.metaweb.gridworks.commands.edit.DoTextTransformCommand;
|
||||
import com.metaweb.gridworks.commands.edit.RemoveColumnCommand;
|
||||
import com.metaweb.gridworks.commands.edit.UndoRedoCommand;
|
||||
import com.metaweb.gridworks.commands.info.ComputeFacetsCommand;
|
||||
import com.metaweb.gridworks.commands.info.GetAllProjectMetadataCommand;
|
||||
@ -51,6 +53,9 @@ public class GridworksServlet extends HttpServlet {
|
||||
_commands.put("compute-facets", new ComputeFacetsCommand());
|
||||
_commands.put("do-text-transform", new DoTextTransformCommand());
|
||||
|
||||
_commands.put("add-column", new AddColumnCommand());
|
||||
_commands.put("remove-column", new RemoveColumnCommand());
|
||||
|
||||
_commands.put("reconcile", new ReconcileCommand());
|
||||
_commands.put("approve-reconcile", new ApproveReconcileCommand());
|
||||
_commands.put("approve-new-reconcile", new ApproveNewReconcileCommand());
|
||||
|
@ -0,0 +1,30 @@
|
||||
package com.metaweb.gridworks.commands.edit;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
import org.json.JSONObject;
|
||||
|
||||
import com.metaweb.gridworks.commands.EngineDependentCommand;
|
||||
import com.metaweb.gridworks.model.AbstractOperation;
|
||||
import com.metaweb.gridworks.model.operations.ColumnAdditionOperation;
|
||||
|
||||
public class AddColumnCommand extends EngineDependentCommand {
|
||||
@Override
|
||||
protected AbstractOperation createOperation(HttpServletRequest request,
|
||||
JSONObject engineConfig) throws Exception {
|
||||
|
||||
int baseCellIndex = Integer.parseInt(request.getParameter("baseCellIndex"));
|
||||
String expression = request.getParameter("expression");
|
||||
String headerLabel = request.getParameter("headerLabel");
|
||||
int columnInsertIndex = Integer.parseInt(request.getParameter("columnInsertIndex"));
|
||||
|
||||
return new ColumnAdditionOperation(
|
||||
engineConfig,
|
||||
baseCellIndex,
|
||||
expression,
|
||||
headerLabel,
|
||||
columnInsertIndex
|
||||
);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,37 @@
|
||||
package com.metaweb.gridworks.commands.edit;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Properties;
|
||||
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import com.metaweb.gridworks.commands.Command;
|
||||
import com.metaweb.gridworks.model.AbstractOperation;
|
||||
import com.metaweb.gridworks.model.Project;
|
||||
import com.metaweb.gridworks.model.operations.ColumnRemovalOperation;
|
||||
import com.metaweb.gridworks.process.Process;
|
||||
|
||||
public class RemoveColumnCommand extends Command {
|
||||
@Override
|
||||
public void doPost(HttpServletRequest request, HttpServletResponse response)
|
||||
throws ServletException, IOException {
|
||||
|
||||
try {
|
||||
Project project = getProject(request);
|
||||
|
||||
int columnRemovalIndex = Integer.parseInt(request.getParameter("columnRemovalIndex"));
|
||||
|
||||
AbstractOperation op = new ColumnRemovalOperation(columnRemovalIndex);
|
||||
Process process = op.createProcess(project, new Properties());
|
||||
|
||||
boolean done = project.processManager.queueProcess(process);
|
||||
|
||||
respond(response, "{ \"code\" : " + (done ? "\"ok\"" : "\"pending\"") + " }");
|
||||
|
||||
} catch (Exception e) {
|
||||
respondException(response, e);
|
||||
}
|
||||
}
|
||||
}
|
@ -9,7 +9,12 @@ import com.metaweb.gridworks.model.Row;
|
||||
public class ExpressionUtils {
|
||||
static public Properties createBindings(Project project) {
|
||||
Properties bindings = new Properties();
|
||||
|
||||
bindings.put("true", true);
|
||||
bindings.put("false", false);
|
||||
|
||||
bindings.put("project", project);
|
||||
|
||||
return bindings;
|
||||
}
|
||||
|
||||
|
@ -37,6 +37,17 @@ public class Row implements Serializable, HasFields, Jsonizable {
|
||||
return null;
|
||||
}
|
||||
|
||||
public void setCell(int cellIndex, Cell cell) {
|
||||
if (cellIndex < cells.size()) {
|
||||
cells.set(cellIndex, cell);
|
||||
} else {
|
||||
while (cellIndex > cells.size()) {
|
||||
cells.add(null);
|
||||
}
|
||||
cells.add(cell);
|
||||
}
|
||||
}
|
||||
|
||||
public class Cells implements HasFields {
|
||||
private Cells() {};
|
||||
|
||||
@ -62,7 +73,11 @@ public class Row implements Serializable, HasFields, Jsonizable {
|
||||
|
||||
writer.key("cells"); writer.array();
|
||||
for (Cell cell : cells) {
|
||||
cell.write(writer, options);
|
||||
if (cell != null) {
|
||||
cell.write(writer, options);
|
||||
} else {
|
||||
writer.value(null);
|
||||
}
|
||||
}
|
||||
writer.endArray();
|
||||
|
||||
|
@ -4,6 +4,7 @@ import java.util.List;
|
||||
|
||||
import com.metaweb.gridworks.model.Column;
|
||||
import com.metaweb.gridworks.model.Project;
|
||||
import com.metaweb.gridworks.model.Row;
|
||||
|
||||
public class ColumnAdditionChange extends ColumnChange {
|
||||
private static final long serialVersionUID = -3938837464064526052L;
|
||||
@ -28,9 +29,12 @@ public class ColumnAdditionChange extends ColumnChange {
|
||||
Column column = new Column(_newCellIndex, _headerLabel);
|
||||
|
||||
project.columnModel.columns.add(_columnIndex, column);
|
||||
|
||||
for (CellAtRow cell : _newCells) {
|
||||
project.rows.get(cell.row).cells.set(_newCellIndex, cell.cell);
|
||||
try {
|
||||
for (CellAtRow cell : _newCells) {
|
||||
project.rows.get(cell.row).setCell(_newCellIndex, cell.cell);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -39,7 +43,8 @@ public class ColumnAdditionChange extends ColumnChange {
|
||||
public void revert(Project project) {
|
||||
synchronized (project) {
|
||||
for (CellAtRow cell : _newCells) {
|
||||
project.rows.get(cell.row).cells.remove(_newCellIndex);
|
||||
Row row = project.rows.get(cell.row);
|
||||
row.setCell(_newCellIndex, null);
|
||||
}
|
||||
|
||||
project.columnModel.columns.remove(_columnIndex);
|
||||
|
@ -31,6 +31,8 @@ public class ColumnRemovalChange extends ColumnChange {
|
||||
oldCell = row.cells.get(cellIndex);
|
||||
}
|
||||
_oldCells[i] = new CellAtRow(i, oldCell);
|
||||
|
||||
row.setCell(cellIndex, null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,19 +0,0 @@
|
||||
package com.metaweb.gridworks.model.changes;
|
||||
|
||||
import com.metaweb.gridworks.model.Project;
|
||||
|
||||
public class ColumnSplitChange extends ColumnChange {
|
||||
|
||||
@Override
|
||||
public void apply(Project project) {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void revert(Project project) {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,126 @@
|
||||
package com.metaweb.gridworks.model.operations;
|
||||
|
||||
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.FilteredRows;
|
||||
import com.metaweb.gridworks.browsing.RowVisitor;
|
||||
import com.metaweb.gridworks.expr.Evaluable;
|
||||
import com.metaweb.gridworks.expr.ExpressionUtils;
|
||||
import com.metaweb.gridworks.expr.Parser;
|
||||
import com.metaweb.gridworks.history.Change;
|
||||
import com.metaweb.gridworks.history.HistoryEntry;
|
||||
import com.metaweb.gridworks.model.Cell;
|
||||
import com.metaweb.gridworks.model.Column;
|
||||
import com.metaweb.gridworks.model.Project;
|
||||
import com.metaweb.gridworks.model.Row;
|
||||
import com.metaweb.gridworks.model.changes.CellAtRow;
|
||||
import com.metaweb.gridworks.model.changes.ColumnAdditionChange;
|
||||
import com.metaweb.gridworks.process.Process;
|
||||
import com.metaweb.gridworks.process.QuickHistoryEntryProcess;
|
||||
|
||||
public class ColumnAdditionOperation extends EngineDependentOperation {
|
||||
private static final long serialVersionUID = -5672677479629932356L;
|
||||
|
||||
final protected int _baseCellIndex;
|
||||
final protected String _expression;
|
||||
|
||||
final protected String _headerLabel;
|
||||
final protected int _columnInsertIndex;
|
||||
|
||||
public ColumnAdditionOperation(
|
||||
JSONObject engineConfig,
|
||||
int baseCellIndex,
|
||||
String expression,
|
||||
String headerLabel,
|
||||
int columnInsertIndex
|
||||
) {
|
||||
super(engineConfig);
|
||||
|
||||
_baseCellIndex = baseCellIndex;
|
||||
_expression = expression;
|
||||
|
||||
_headerLabel = headerLabel;
|
||||
_columnInsertIndex = columnInsertIndex;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Process createProcess(Project project, Properties options)
|
||||
throws Exception {
|
||||
|
||||
Engine engine = createEngine(project);
|
||||
|
||||
Column column = project.columnModel.getColumnByCellIndex(_baseCellIndex);
|
||||
if (column == null) {
|
||||
throw new Exception("No column corresponding to cell index " + _baseCellIndex);
|
||||
}
|
||||
|
||||
List<CellAtRow> cellsAtRows = new ArrayList<CellAtRow>(project.rows.size());
|
||||
|
||||
FilteredRows filteredRows = engine.getAllFilteredRows();
|
||||
filteredRows.accept(project, createRowVisitor(project, cellsAtRows));
|
||||
|
||||
String description = createDescription(column, cellsAtRows);
|
||||
|
||||
Change change = new ColumnAdditionChange(_headerLabel, _columnInsertIndex, cellsAtRows);
|
||||
HistoryEntry historyEntry = new HistoryEntry(
|
||||
project, description, this, change);
|
||||
|
||||
return new QuickHistoryEntryProcess(project, historyEntry);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(JSONWriter writer, Properties options)
|
||||
throws JSONException {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
protected String createDescription(Column column, List<CellAtRow> cellsAtRows) {
|
||||
return "Create new column " + _headerLabel +
|
||||
" based on column " + column.getHeaderLabel() +
|
||||
" by filling " + cellsAtRows.size() +
|
||||
" rows with " + _expression;
|
||||
}
|
||||
|
||||
protected RowVisitor createRowVisitor(Project project, List<CellAtRow> cellsAtRows) throws Exception {
|
||||
Evaluable eval = new Parser(_expression).getExpression();
|
||||
Properties bindings = ExpressionUtils.createBindings(project);
|
||||
|
||||
return new RowVisitor() {
|
||||
int cellIndex;
|
||||
Properties bindings;
|
||||
List<CellAtRow> cellsAtRows;
|
||||
Evaluable eval;
|
||||
|
||||
public RowVisitor init(int cellIndex, Properties bindings, List<CellAtRow> cellsAtRows, Evaluable eval) {
|
||||
this.cellIndex = cellIndex;
|
||||
this.bindings = bindings;
|
||||
this.cellsAtRows = cellsAtRows;
|
||||
this.eval = eval;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean visit(Project project, int rowIndex, Row row) {
|
||||
if (cellIndex < row.cells.size()) {
|
||||
Cell cell = row.cells.get(cellIndex);
|
||||
if (cell.value != null) {
|
||||
ExpressionUtils.bind(bindings, row, cell);
|
||||
|
||||
Cell newCell = new Cell(eval.evaluate(bindings), null);
|
||||
|
||||
cellsAtRows.add(new CellAtRow(rowIndex, newCell));
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}.init(_baseCellIndex, bindings, cellsAtRows, eval);
|
||||
}
|
||||
}
|
@ -0,0 +1,52 @@
|
||||
package com.metaweb.gridworks.model.operations;
|
||||
|
||||
import java.util.Properties;
|
||||
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONWriter;
|
||||
|
||||
import com.metaweb.gridworks.history.Change;
|
||||
import com.metaweb.gridworks.history.HistoryEntry;
|
||||
import com.metaweb.gridworks.model.AbstractOperation;
|
||||
import com.metaweb.gridworks.model.Column;
|
||||
import com.metaweb.gridworks.model.Project;
|
||||
import com.metaweb.gridworks.model.changes.ColumnRemovalChange;
|
||||
import com.metaweb.gridworks.process.Process;
|
||||
import com.metaweb.gridworks.process.QuickHistoryEntryProcess;
|
||||
|
||||
public class ColumnRemovalOperation implements AbstractOperation {
|
||||
private static final long serialVersionUID = 8422079695048733734L;
|
||||
|
||||
final protected int _columnRemovalIndex;
|
||||
|
||||
public ColumnRemovalOperation(
|
||||
int columnRemoveIndex
|
||||
) {
|
||||
_columnRemovalIndex = columnRemoveIndex;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Process createProcess(Project project, Properties options)
|
||||
throws Exception {
|
||||
|
||||
Column column = project.columnModel.columns.get(_columnRemovalIndex);
|
||||
if (column == null) {
|
||||
throw new Exception("No column at index " + _columnRemovalIndex);
|
||||
}
|
||||
|
||||
String description = "Remove column " + column.getHeaderLabel();
|
||||
|
||||
Change change = new ColumnRemovalChange(_columnRemovalIndex);
|
||||
HistoryEntry historyEntry = new HistoryEntry(
|
||||
project, description, this, change);
|
||||
|
||||
return new QuickHistoryEntryProcess(project, historyEntry);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(JSONWriter writer, Properties options)
|
||||
throws JSONException {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
}
|
@ -8,22 +8,7 @@ function onLoad() {
|
||||
id: parseInt(params.project)
|
||||
};
|
||||
|
||||
Ajax.chainGetJSON(
|
||||
"/command/get-project-metadata?" + $.param({ project: theProject.id }), null,
|
||||
function(data) {
|
||||
theProject.metadata = data;
|
||||
},
|
||||
"/command/get-column-model?" + $.param({ project: theProject.id }), null,
|
||||
function(data) {
|
||||
theProject.columnModel = data;
|
||||
for (var i = 0; i < theProject.columnModel.columns.length; i++) {
|
||||
theProject.columnModel.columns[i].collapsed = false;
|
||||
}
|
||||
},
|
||||
function() {
|
||||
initializeUI();
|
||||
}
|
||||
);
|
||||
reinitializeProjectData(initializeUI);
|
||||
}
|
||||
}
|
||||
$(onLoad);
|
||||
@ -55,3 +40,20 @@ function initializeUI() {
|
||||
ui.historyWidget = new HistoryWidget(ui.historyPanel);
|
||||
ui.dataTableView = new DataTableView(ui.viewPanel);
|
||||
}
|
||||
|
||||
function reinitializeProjectData(f) {
|
||||
Ajax.chainGetJSON(
|
||||
"/command/get-project-metadata?" + $.param({ project: theProject.id }), null,
|
||||
function(data) {
|
||||
theProject.metadata = data;
|
||||
},
|
||||
"/command/get-column-model?" + $.param({ project: theProject.id }), null,
|
||||
function(data) {
|
||||
theProject.columnModel = data;
|
||||
for (var i = 0; i < theProject.columnModel.columns.length; i++) {
|
||||
theProject.columnModel.columns[i].collapsed = false;
|
||||
}
|
||||
},
|
||||
f
|
||||
);
|
||||
}
|
@ -6,7 +6,14 @@ function DataTableView(div) {
|
||||
}
|
||||
|
||||
DataTableView.prototype.update = function(reset) {
|
||||
this._showRows(reset ? 0 : theProject.rowModel.start);
|
||||
if (reset) {
|
||||
var self = this;
|
||||
reinitializeProjectData(function() {
|
||||
self._showRows(0);
|
||||
});
|
||||
} else {
|
||||
this._showRows(theProject.rowModel.start);
|
||||
}
|
||||
};
|
||||
|
||||
DataTableView.prototype.render = function() {
|
||||
@ -117,7 +124,7 @@ DataTableView.prototype.render = function() {
|
||||
}
|
||||
|
||||
var renderCell = function(cell, td) {
|
||||
if (cell.v == null) {
|
||||
if (cell == null || cell.v == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
@ -466,6 +473,15 @@ DataTableView.prototype._createMenuForColumnHeader = function(column, index, elm
|
||||
]
|
||||
},
|
||||
{},
|
||||
{
|
||||
label: "Add Column Based on This Column",
|
||||
click: function() { self._doAddColumn(column, index, "value"); }
|
||||
},
|
||||
{
|
||||
label: "Remove This Column",
|
||||
click: function() { self._doRemoveColumn(column, index); }
|
||||
},
|
||||
{},
|
||||
{
|
||||
label: "Text Transform",
|
||||
submenu: [
|
||||
@ -545,24 +561,34 @@ DataTableView.prototype._doFilterByExpressionPrompt = function(column, expressio
|
||||
);
|
||||
};
|
||||
|
||||
DataTableView.prototype._createUpdateFunction = function() {
|
||||
DataTableView.prototype._createUpdateFunction = function(onBefore) {
|
||||
var self = this;
|
||||
return function(data) {
|
||||
if (data.code == "ok") {
|
||||
self.update();
|
||||
ui.historyWidget.update();
|
||||
var onDone = function() {
|
||||
self.update();
|
||||
ui.historyWidget.update();
|
||||
};
|
||||
} else {
|
||||
ui.processWidget.update();
|
||||
var onDone = function() {
|
||||
ui.processWidget.update();
|
||||
}
|
||||
}
|
||||
|
||||
if (onBefore) {
|
||||
onBefore(onDone);
|
||||
} else {
|
||||
onDone();
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
DataTableView.prototype._doPostThenUpdate = function(command, params) {
|
||||
DataTableView.prototype._doPostThenUpdate = function(command, params, updateColumnModel) {
|
||||
params.project = theProject.id;
|
||||
$.post(
|
||||
"/command/" + command + "?" + $.param(params),
|
||||
{ engine: JSON.stringify(ui.browsingEngine.getJSON()) },
|
||||
this._createUpdateFunction(),
|
||||
this._createUpdateFunction(updateColumnModel ? reinitializeProjectData : undefined),
|
||||
"json"
|
||||
);
|
||||
};
|
||||
@ -637,3 +663,36 @@ DataTableView.prototype._doApproveNewTopics = function(column) {
|
||||
{ cell: column.cellIndex }
|
||||
);
|
||||
};
|
||||
|
||||
DataTableView.prototype._doAddColumn = function(column, index, initialExpression) {
|
||||
var self = this;
|
||||
DataTableView.promptExpressionOnVisibleRows(
|
||||
column,
|
||||
"Add Column Based on Column " + column.headerLabel,
|
||||
initialExpression,
|
||||
function(expression) {
|
||||
var headerLabel = window.prompt("Enter header label for new column:");
|
||||
if (headerLabel != null) {
|
||||
self._doPostThenUpdate(
|
||||
"add-column",
|
||||
{
|
||||
baseCellIndex: column.cellIndex,
|
||||
expression: expression,
|
||||
headerLabel: headerLabel,
|
||||
columnInsertIndex: index + 1
|
||||
},
|
||||
true
|
||||
);
|
||||
}
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
DataTableView.prototype._doRemoveColumn = function(column, index) {
|
||||
this._doPostThenUpdate(
|
||||
"remove-column",
|
||||
{ columnRemovalIndex: index },
|
||||
true
|
||||
);
|
||||
};
|
||||
|
||||
|
@ -72,7 +72,7 @@ HistoryWidget.prototype._onClickHistoryEntry = function(evt, entry, lastDoneID)
|
||||
function(data) {
|
||||
if (data.code == "ok") {
|
||||
self.update();
|
||||
ui.dataTableView.update();
|
||||
ui.dataTableView.update(true);
|
||||
} else {
|
||||
// update process UI
|
||||
}
|
||||
|
@ -81,6 +81,9 @@ MenuSystem.createAndShowStandardMenu = function(items, elmt, options) {
|
||||
if ("tooltip" in item) {
|
||||
menuItem.attr("title", item.tooltip);
|
||||
}
|
||||
menuItem.mouseover(function() {
|
||||
MenuSystem.dismissUntil(level);
|
||||
});
|
||||
}
|
||||
} else if ("heading" in item) {
|
||||
$('<div></div>').addClass("menu-section").text(item.heading).appendTo(menu);
|
||||
|
Loading…
Reference in New Issue
Block a user