Implemented "apply operations" feature.

git-svn-id: http://google-refine.googlecode.com/svn/trunk@102 7d457c2a-affb-35e4-300a-418c747d4874
This commit is contained in:
David Huynh 2010-02-18 05:00:56 +00:00
parent 604dd53ebd
commit 8831703a2c
4 changed files with 191 additions and 9 deletions

View File

@ -16,6 +16,7 @@ import org.json.JSONTokener;
import com.metaweb.gridworks.commands.Command;
import com.metaweb.gridworks.commands.edit.AddColumnCommand;
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.JoinMultiValueCellsCommand;
@ -60,6 +61,8 @@ public class GridworksServlet extends HttpServlet {
_commands.put("get-operations", new GetOperationsCommand());
_commands.put("undo-redo", new UndoRedoCommand());
_commands.put("apply-operations", new ApplyOperationsCommand());
_commands.put("compute-facets", new ComputeFacetsCommand());
_commands.put("do-text-transform", new DoTextTransformCommand());

View File

@ -0,0 +1,118 @@
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 org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import com.metaweb.gridworks.commands.Command;
import com.metaweb.gridworks.model.AbstractOperation;
import com.metaweb.gridworks.model.Project;
import com.metaweb.gridworks.model.operations.ApproveNewReconOperation;
import com.metaweb.gridworks.model.operations.ApproveReconOperation;
import com.metaweb.gridworks.model.operations.ColumnAdditionOperation;
import com.metaweb.gridworks.model.operations.ColumnRemovalOperation;
import com.metaweb.gridworks.model.operations.DiscardReconOperation;
import com.metaweb.gridworks.model.operations.MultiValueCellJoinOperation;
import com.metaweb.gridworks.model.operations.MultiValueCellSplitOperation;
import com.metaweb.gridworks.model.operations.ReconOperation;
import com.metaweb.gridworks.model.operations.SaveProtographOperation;
import com.metaweb.gridworks.model.operations.TextTransformOperation;
import com.metaweb.gridworks.process.Process;
import com.metaweb.gridworks.protograph.Protograph;
public class ApplyOperationsCommand extends Command {
@Override
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
Project project = getProject(request);
String jsonString = request.getParameter("operations");
try {
JSONArray a = jsonStringToArray(jsonString);
int count = a.length();
for (int i = 0; i < count; i++) {
JSONObject obj = a.getJSONObject(i);
reconstructOperation(project, obj);
}
respond(response, "{ \"code\" : \"pending\" }");
} catch (JSONException e) {
respondException(response, e);
}
}
protected void reconstructOperation(Project project, JSONObject obj) {
try {
String op = obj.getString("op");
AbstractOperation operation = null;
JSONObject engineConfig = obj.has("engineConfig") ? obj.getJSONObject("engineConfig") : null;
String columnName = obj.has("columnName") ? obj.getString("columnName") : null;
if ("approve-new-recon".equals(op)) {
operation = new ApproveNewReconOperation(engineConfig, columnName);
} else if ("approve-recon".equals(op)) {
operation = new ApproveReconOperation(engineConfig, columnName);
} else if ("add-column".equals(op)) {
operation = new ColumnAdditionOperation(
engineConfig,
obj.getString("baseColumnName"),
obj.getString("expression"),
obj.getString("headerLabel"),
obj.getInt("columnInsertIndex")
);
} else if ("remove-column".equals(op)) {
operation = new ColumnRemovalOperation(columnName);
} else if ("discard-recon".equals(op)) {
operation = new DiscardReconOperation(engineConfig, columnName);
} else if ("join-multivalued-cells".equals(op)) {
operation = new MultiValueCellJoinOperation(
columnName,
obj.getString("keyColumnName"),
obj.getString("separator")
);
} else if ("split-multivalued-cells".equals(op)) {
operation = new MultiValueCellSplitOperation(
columnName,
obj.getString("keyColumnName"),
obj.getString("separator"),
obj.getString("mode")
);
} else if ("recon".equals(op)) {
operation = new ReconOperation(
engineConfig,
columnName,
obj.getString("typeID")
);
} else if ("save-protograph".equals(op)) {
operation = new SaveProtographOperation(
Protograph.reconstruct(obj.getJSONObject("protograph"))
);
} else if ("text-transform".equals(op)) {
operation = new TextTransformOperation(
engineConfig,
columnName,
obj.getString("expression")
);
}
if (operation != null) {
Process process = operation.createProcess(project, new Properties());
project.processManager.queueProcess(process);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}

View File

@ -25,8 +25,8 @@ public class DiscardReconOperation extends EngineDependentMassCellOperation {
throws JSONException {
writer.object();
writer.key("op"); writer.value("disapprove-recon");
writer.key("description"); writer.value("Discard recon judgments in column " + _columnName);
writer.key("op"); writer.value("discard-recon");
writer.key("description"); writer.value("Discard recon matches in column " + _columnName);
writer.key("engineConfig"); writer.value(getEngineConfig());
writer.key("columnName"); writer.value(_columnName);
writer.endObject();

View File

@ -18,15 +18,26 @@ HistoryWidget.prototype._render = function() {
var self = this;
this._div.empty();
this._div.unbind();
$('<h3>Undo/Redo History</h3>').appendTo(this._div);
var bodyDiv = $('<div></div>').addClass("history-panel-body").appendTo(this._div);
bodyDiv.mouseenter(function(evt) {
$(this).addClass("history-panel-body-expanded");
bodyDiv.addClass("history-panel-body-expanded");
});
this._div.mouseenter(function(evt) {
if (self._timerID != null) {
window.clearTimeout(self._timerID);
self._timerID = null;
}
}).mouseleave(function(evt) {
$(this).removeClass("history-panel-body-expanded");
autoscroll();
self._timerID = window.setTimeout(function() {
self._timerID = null;
bodyDiv.removeClass("history-panel-body-expanded");
autoscroll();
}, 1000);
});
var renderEntry = function(container, entry, lastDoneID, title) {
@ -71,7 +82,7 @@ HistoryWidget.prototype._render = function() {
});
$('<span> &bull; </span>').appendTo(footerDiv);
$('<a href="javascript:{}"></a>').text("apply").appendTo(footerDiv).click(function() {
self._applyOperations();
self._showApplyOperationsDialog();
});
};
@ -99,22 +110,26 @@ HistoryWidget.prototype._extractOperations = function() {
null,
function(data) {
if ("operations" in data) {
self._showOperationsDialog(data.operations);
self._showExtractOperationsDialog(data.operations);
}
},
"jsonp"
);
};
HistoryWidget.prototype._showOperationsDialog = function(json) {
HistoryWidget.prototype._showExtractOperationsDialog = function(json) {
var self = this;
var frame = DialogSystem.createDialog();
frame.width("800px");
var header = $('<div></div>').addClass("dialog-header").text("Operations").appendTo(frame);
var header = $('<div></div>').addClass("dialog-header").text("Extract Operations").appendTo(frame);
var body = $('<div></div>').addClass("dialog-body").appendTo(frame);
var footer = $('<div></div>').addClass("dialog-footer").appendTo(frame);
$('<p></p>').text(
"The following JSON code encodes the operations you have done that can be abstracted. " +
"You can copy and save it in order to apply the same operations in the future.").appendTo(body);
var textarea = $('<textarea />').attr("wrap", "hard").width("100%").height("400px").appendTo(body);
textarea.text(JSON.stringify(json, null, 2));
@ -124,5 +139,51 @@ HistoryWidget.prototype._showOperationsDialog = function(json) {
var level = DialogSystem.showDialog(frame);
textarea[0].select();
};
HistoryWidget.prototype._showApplyOperationsDialog = function(json) {
var self = this;
var frame = DialogSystem.createDialog();
frame.width("800px");
var header = $('<div></div>').addClass("dialog-header").text("Apply Operations").appendTo(frame);
var body = $('<div></div>').addClass("dialog-body").appendTo(frame);
var footer = $('<div></div>').addClass("dialog-footer").appendTo(frame);
$('<p></p>').text(
"Paste the JSON code encoding the operations to perform.").appendTo(body);
var textarea = $('<textarea />').attr("wrap", "hard").width("100%").height("400px").appendTo(body);
textarea.text(JSON.stringify(json, null, 2));
$('<button></button>').text("Apply").click(function() {
try {
var json = JSON.parse(textarea[0].value);
} catch (e) {
alert("The JSON you pasted is invalid.");
return;
}
DialogSystem.dismissUntil(level - 1);
$.post(
"/command/apply-operations?" + $.param({ project: theProject.id }),
{ operations: JSON.stringify(json) },
function(data) {
self.update();
ui.dataTableView.update(true);
ui.processWidget.update();
},
"json"
);
}).appendTo(footer);
$('<button></button>').text("Cancel").click(function() {
DialogSystem.dismissUntil(level - 1);
}).appendTo(footer);
var level = DialogSystem.showDialog(frame);
textarea[0].focus();
};