Implemented facet-based edit operation for real.

git-svn-id: http://google-refine.googlecode.com/svn/trunk@167 7d457c2a-affb-35e4-300a-418c747d4874
This commit is contained in:
David Huynh 2010-03-02 20:33:11 +00:00
parent d9507200f8
commit 3ecfb4e4d9
5 changed files with 257 additions and 13 deletions

View File

@ -21,6 +21,7 @@ import com.metaweb.gridworks.commands.edit.AnnotateRowsCommand;
import com.metaweb.gridworks.commands.edit.ApplyOperationsCommand;
import com.metaweb.gridworks.commands.edit.CreateProjectCommand;
import com.metaweb.gridworks.commands.edit.DoTextTransformCommand;
import com.metaweb.gridworks.commands.edit.FacetBasedEditCommand;
import com.metaweb.gridworks.commands.edit.JoinMultiValueCellsCommand;
import com.metaweb.gridworks.commands.edit.RemoveColumnCommand;
import com.metaweb.gridworks.commands.edit.SaveProtographCommand;
@ -70,6 +71,7 @@ public class GridworksServlet extends HttpServlet {
_commands.put("compute-facets", new ComputeFacetsCommand());
_commands.put("do-text-transform", new DoTextTransformCommand());
_commands.put("facet-based-edit", new FacetBasedEditCommand());
_commands.put("add-column", new AddColumnCommand());
_commands.put("remove-column", new RemoveColumnCommand());

View File

@ -0,0 +1,29 @@
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.operations.FacetBasedEditOperation;
import com.metaweb.gridworks.util.ParsingUtilities;
public class FacetBasedEditCommand extends EngineDependentCommand {
@Override
protected AbstractOperation createOperation(HttpServletRequest request,
JSONObject engineConfig) throws Exception {
String columnName = request.getParameter("columnName");
String expression = request.getParameter("expression");
String editsString = request.getParameter("edits");
return new FacetBasedEditOperation(
engineConfig,
columnName,
expression,
FacetBasedEditOperation.reconstructEdits(ParsingUtilities.evaluateJsonStringToArray(editsString))
);
}
}

View File

@ -0,0 +1,176 @@
package com.metaweb.gridworks.operations;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import org.json.JSONWriter;
import com.metaweb.gridworks.Jsonizable;
import com.metaweb.gridworks.browsing.RowVisitor;
import com.metaweb.gridworks.expr.Evaluable;
import com.metaweb.gridworks.expr.ExpressionUtils;
import com.metaweb.gridworks.expr.MetaParser;
import com.metaweb.gridworks.model.AbstractOperation;
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.CellChange;
public class FacetBasedEditOperation extends EngineDependentMassCellOperation {
private static final long serialVersionUID = -7698202759999537298L;
final protected String _expression;
final protected List<Edit> _edits;
static public class Edit implements Serializable, Jsonizable {
private static final long serialVersionUID = -4799990738910328002L;
final public List<String> from;
final public Object to;
public Edit(List<String> from, Object to) {
this.from = from;
this.to = to;
}
public void write(JSONWriter writer, Properties options)
throws JSONException {
writer.object();
writer.key("from");
writer.array();
for (String s : from) {
writer.value(s);
}
writer.endArray();
writer.key("to"); writer.value(to);
writer.endObject();
}
}
static public AbstractOperation reconstruct(Project project, JSONObject obj) throws Exception {
JSONObject engineConfig = obj.getJSONObject("engineConfig");
return new FacetBasedEditOperation(
engineConfig,
obj.getString("columnName"),
obj.getString("expression"),
reconstructEdits(obj.getJSONArray("edits"))
);
}
static public List<Edit> reconstructEdits(JSONArray editsA) throws Exception {
int editCount = editsA.length();
List<Edit> edits = new ArrayList<Edit>(editCount);
for (int i = 0; i < editCount; i++) {
JSONObject editO = editsA.getJSONObject(i);
JSONArray fromA = editO.getJSONArray("from");
int fromCount = fromA.length();
List<String> from = new ArrayList<String>(fromCount);
for (int j = 0; j < fromCount; j++) {
from.add(fromA.getString(j));
}
edits.add(new Edit(from, editO.get("to")));
}
return edits;
}
public FacetBasedEditOperation(JSONObject engineConfig, String columnName, String expression, List<Edit> edits) {
super(engineConfig, columnName, true);
_expression = expression;
_edits = edits;
}
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("engineConfig"); writer.value(getEngineConfig());
writer.key("columnName"); writer.value(_columnName);
writer.key("expression"); writer.value(_expression);
writer.key("edits");
writer.array();
for (Edit edit : _edits) {
edit.write(writer, options);
}
writer.endArray();
writer.endObject();
}
protected String getBriefDescription(Project project) {
return "Facet-based edit cells in column " + _columnName;
}
protected String createDescription(Column column,
List<CellChange> cellChanges) {
return "Facet-based edit " + cellChanges.size() +
" cells in column " + column.getHeaderLabel();
}
protected RowVisitor createRowVisitor(Project project, List<CellChange> cellChanges) throws Exception {
Column column = project.columnModel.getColumnByName(_columnName);
Evaluable eval = MetaParser.parse(_expression);
Properties bindings = ExpressionUtils.createBindings(project);
Map<String, Object> fromTo = new HashMap<String, Object>();
for (Edit edit : _edits) {
for (String s : edit.from) {
fromTo.put(s, edit.to);
}
}
return new RowVisitor() {
int cellIndex;
Properties bindings;
List<CellChange> cellChanges;
Evaluable eval;
Map<String, Object> fromTo;
public RowVisitor init(
int cellIndex, Properties bindings, List<CellChange> cellChanges, Evaluable eval, Map<String, Object> fromTo) {
this.cellIndex = cellIndex;
this.bindings = bindings;
this.cellChanges = cellChanges;
this.eval = eval;
this.fromTo = fromTo;
return this;
}
public boolean visit(Project project, int rowIndex, Row row, boolean contextual) {
Cell cell = row.getCell(cellIndex);
ExpressionUtils.bind(bindings, row, rowIndex, cell);
Object v = eval.evaluate(bindings);
if (v != null) {
String from = v.toString();
Object to = fromTo.get(from);
if (to != null) {
Cell newCell = new Cell(to, (cell != null) ? cell.recon : null);
CellChange cellChange = new CellChange(rowIndex, cellIndex, cell, newCell);
cellChanges.add(cellChange);
}
}
return false;
}
}.init(column.getCellIndex(), bindings, cellChanges, eval, fromTo);
}
}

View File

@ -1,5 +1,6 @@
function FacetBasedEditDialog(columnName, entries) {
function FacetBasedEditDialog(columnName, expression, entries) {
this._columnName = columnName;
this._expression = expression;
this._entries = entries;
this._createDialog();
@ -84,13 +85,6 @@ FacetBasedEditDialog.prototype._renderTable = function() {
}
};
FacetBasedEditDialog.prototype._onOK = function() {
};
FacetBasedEditDialog.prototype._dismiss = function() {
DialogSystem.dismissUntil(this._level - 1);
};
FacetBasedEditDialog.prototype._cluster = function() {
var clusters = [];
var map = {};
@ -113,10 +107,13 @@ FacetBasedEditDialog.prototype._cluster = function() {
});
$.each(clusters, function() {
this.choices.sort(function(a, b) {
var c = b.c - a.c;
return c != 0 ? c : a.v.l.localeCompare(b.v.l);
});
if (this.choices.length > 1) {
this.choices.sort(function(a, b) {
var c = b.c - a.c;
return c != 0 ? c : a.v.l.localeCompare(b.v.l);
});
this.edit = true;
}
this.value = this.choices[0].v.l;
});
clusters.sort(function(a, b) {
@ -145,3 +142,43 @@ FacetBasedEditDialog.prototype._uncluster = function() {
this._clusters = clusters;
this._renderTable();
};
FacetBasedEditDialog.prototype._onOK = function() {
var edits = [];
for (var i = 0; i < this._clusters.length; i++) {
var cluster = this._clusters[i];
if (cluster.edit) {
var values = [];
for (var j = 0; j < cluster.choices.length; j++) {
values.push(cluster.choices[j].v.v);
}
edits.push({
from: values,
to: cluster.value
});
}
}
if (edits.length > 0) {
Gridworks.postProcess(
"facet-based-edit",
{},
{
columnName: this._columnName,
expression: this._expression,
edits: JSON.stringify(edits)
},
{ cellsChanged: true }
);
this._dismiss();
} else {
alert("You must check some Edit? checkboxes for your edits to be applied.");
}
};
FacetBasedEditDialog.prototype._dismiss = function() {
DialogSystem.dismissUntil(this._level - 1);
};

View File

@ -220,7 +220,7 @@ ListFacet.prototype._doEdit = function() {
c: choice.c
});
}
new FacetBasedEditDialog(this._config.columnName, entries);
new FacetBasedEditDialog(this._config.columnName, this._config.expression, entries);
};
ListFacet.prototype._select = function(choice, only) {