diff --git a/src/main/java/com/metaweb/gridworks/GridworksServlet.java b/src/main/java/com/metaweb/gridworks/GridworksServlet.java index 1be43a1a7..f8ab11e48 100644 --- a/src/main/java/com/metaweb/gridworks/GridworksServlet.java +++ b/src/main/java/com/metaweb/gridworks/GridworksServlet.java @@ -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()); diff --git a/src/main/java/com/metaweb/gridworks/commands/edit/FacetBasedEditCommand.java b/src/main/java/com/metaweb/gridworks/commands/edit/FacetBasedEditCommand.java new file mode 100644 index 000000000..ffe236f19 --- /dev/null +++ b/src/main/java/com/metaweb/gridworks/commands/edit/FacetBasedEditCommand.java @@ -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)) + ); + } +} diff --git a/src/main/java/com/metaweb/gridworks/operations/FacetBasedEditOperation.java b/src/main/java/com/metaweb/gridworks/operations/FacetBasedEditOperation.java new file mode 100644 index 000000000..1d82de4eb --- /dev/null +++ b/src/main/java/com/metaweb/gridworks/operations/FacetBasedEditOperation.java @@ -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 _edits; + + static public class Edit implements Serializable, Jsonizable { + private static final long serialVersionUID = -4799990738910328002L; + + final public List from; + final public Object to; + + public Edit(List 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 reconstructEdits(JSONArray editsA) throws Exception { + int editCount = editsA.length(); + + List edits = new ArrayList(editCount); + for (int i = 0; i < editCount; i++) { + JSONObject editO = editsA.getJSONObject(i); + + JSONArray fromA = editO.getJSONArray("from"); + int fromCount = fromA.length(); + + List from = new ArrayList(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 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 cellChanges) { + + return "Facet-based edit " + cellChanges.size() + + " cells in column " + column.getHeaderLabel(); + } + + protected RowVisitor createRowVisitor(Project project, List cellChanges) throws Exception { + Column column = project.columnModel.getColumnByName(_columnName); + + Evaluable eval = MetaParser.parse(_expression); + Properties bindings = ExpressionUtils.createBindings(project); + + Map fromTo = new HashMap(); + for (Edit edit : _edits) { + for (String s : edit.from) { + fromTo.put(s, edit.to); + } + } + + return new RowVisitor() { + int cellIndex; + Properties bindings; + List cellChanges; + Evaluable eval; + Map fromTo; + + public RowVisitor init( + int cellIndex, Properties bindings, List cellChanges, Evaluable eval, Map 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); + } +} diff --git a/src/main/webapp/scripts/dialogs/facet-based-edit-dialog.js b/src/main/webapp/scripts/dialogs/facet-based-edit-dialog.js index 52e700fad..588f7587e 100644 --- a/src/main/webapp/scripts/dialogs/facet-based-edit-dialog.js +++ b/src/main/webapp/scripts/dialogs/facet-based-edit-dialog.js @@ -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); +}; + diff --git a/src/main/webapp/scripts/facets/list-facet.js b/src/main/webapp/scripts/facets/list-facet.js index e46d1f6ca..7b7abb763 100644 --- a/src/main/webapp/scripts/facets/list-facet.js +++ b/src/main/webapp/scripts/facets/list-facet.js @@ -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) {