Added support for starring rows.

git-svn-id: http://google-refine.googlecode.com/svn/trunk@129 7d457c2a-affb-35e4-300a-418c747d4874
This commit is contained in:
David Huynh 2010-02-23 07:45:12 +00:00
parent 92806cea7e
commit ec1604e815
13 changed files with 360 additions and 14 deletions

Binary file not shown.

BIN
src/graphics/star.psd Normal file

Binary file not shown.

View File

@ -16,6 +16,8 @@ import org.json.JSONTokener;
import com.metaweb.gridworks.commands.Command; import com.metaweb.gridworks.commands.Command;
import com.metaweb.gridworks.commands.edit.AddColumnCommand; import com.metaweb.gridworks.commands.edit.AddColumnCommand;
import com.metaweb.gridworks.commands.edit.AnnotateOneRowCommand;
import com.metaweb.gridworks.commands.edit.AnnotateRowsCommand;
import com.metaweb.gridworks.commands.edit.ApplyOperationsCommand; import com.metaweb.gridworks.commands.edit.ApplyOperationsCommand;
import com.metaweb.gridworks.commands.edit.CreateProjectCommand; import com.metaweb.gridworks.commands.edit.CreateProjectCommand;
import com.metaweb.gridworks.commands.edit.DoTextTransformCommand; import com.metaweb.gridworks.commands.edit.DoTextTransformCommand;
@ -82,6 +84,9 @@ public class GridworksServlet extends HttpServlet {
_commands.put("recon-judge-one-cell", new ReconJudgeOneCellCommand()); _commands.put("recon-judge-one-cell", new ReconJudgeOneCellCommand());
_commands.put("recon-judge-similar-cells", new ReconJudgeSimilarCellsCommand()); _commands.put("recon-judge-similar-cells", new ReconJudgeSimilarCellsCommand());
_commands.put("annotate-one-row", new AnnotateOneRowCommand());
_commands.put("annotate-rows", new AnnotateRowsCommand());
_commands.put("save-protograph", new SaveProtographCommand()); _commands.put("save-protograph", new SaveProtographCommand());
_commands.put("preview-expression", new PreviewExpressionCommand()); _commands.put("preview-expression", new PreviewExpressionCommand());

View File

@ -0,0 +1,85 @@
package com.metaweb.gridworks.commands.edit;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.json.JSONWriter;
import com.metaweb.gridworks.commands.Command;
import com.metaweb.gridworks.history.HistoryEntry;
import com.metaweb.gridworks.model.Project;
import com.metaweb.gridworks.model.changes.RowStarChange;
import com.metaweb.gridworks.process.QuickHistoryEntryProcess;
public class AnnotateOneRowCommand extends Command {
@Override
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.setCharacterEncoding("UTF-8");
response.setHeader("Content-Type", "application/json");
try {
Project project = getProject(request);
int rowIndex = Integer.parseInt(request.getParameter("row"));
String starredString = request.getParameter("starred");
if (starredString != null) {
boolean starred = "true".endsWith(starredString);
String description = starred ? "Star row " + rowIndex : "Unstar row " + rowIndex;
StarOneRowProcess process = new StarOneRowProcess(
project,
description,
rowIndex,
starred
);
boolean done = project.processManager.queueProcess(process);
if (done) {
JSONWriter writer = new JSONWriter(response.getWriter());
writer.object();
writer.key("code"); writer.value("ok");
writer.endObject();
} else {
respond(response, "{ \"code\" : \"pending\" }");
}
} else {
respond(response, "{ \"code\" : \"error\", \"message\" : \"invalid command parameters\" }");
}
} catch (Exception e) {
respondException(response, e);
}
}
protected class StarOneRowProcess extends QuickHistoryEntryProcess {
final int rowIndex;
final boolean starred;
StarOneRowProcess(
Project project,
String briefDescription,
int rowIndex,
boolean starred
) {
super(project, briefDescription);
this.rowIndex = rowIndex;
this.starred = starred;
}
protected HistoryEntry createHistoryEntry() throws Exception {
return new HistoryEntry(
_project,
starred ? "Star row " + rowIndex : "Unstar row " + rowIndex,
null,
new RowStarChange(rowIndex, starred)
);
}
}
}

View File

@ -0,0 +1,25 @@
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.RowStarOperation;
public class AnnotateRowsCommand extends EngineDependentCommand {
@Override
protected AbstractOperation createOperation(HttpServletRequest request,
JSONObject engineConfig) throws Exception {
String starredString = request.getParameter("starred");
if (starredString != null) {
boolean starred = "true".endsWith(starredString);
return new RowStarOperation(engineConfig, starred);
}
return null;
}
}

View File

@ -0,0 +1,42 @@
package com.metaweb.gridworks.model.changes;
import java.util.List;
import com.metaweb.gridworks.history.Change;
import com.metaweb.gridworks.model.Project;
public class MassChange implements Change {
private static final long serialVersionUID = -3926239320561407450L;
final protected List<? extends Change> _changes;
final protected boolean _updateRowContextDependencies;
public MassChange(List<? extends Change> changes, boolean updateRowContextDependencies) {
_changes = changes;
_updateRowContextDependencies = updateRowContextDependencies;
}
public void apply(Project project) {
synchronized (project) {
for (Change change : _changes) {
change.apply(project);
}
if (_updateRowContextDependencies) {
project.recomputeRowContextDependencies();
}
}
}
public void revert(Project project) {
synchronized (project) {
for (Change change : _changes) {
change.revert(project);
}
if (_updateRowContextDependencies) {
project.recomputeRowContextDependencies();
}
}
}
}

View File

@ -0,0 +1,31 @@
package com.metaweb.gridworks.model.changes;
import com.metaweb.gridworks.history.Change;
import com.metaweb.gridworks.model.Project;
import com.metaweb.gridworks.model.Row;
public class RowStarChange implements Change {
private static final long serialVersionUID = 7343472491567342093L;
final int rowIndex;
final boolean newStarred;
boolean oldStarred;
public RowStarChange(int rowIndex, boolean newStarred) {
this.rowIndex = rowIndex;
this.newStarred = newStarred;
}
public void apply(Project project) {
Row row = project.rows.get(rowIndex);
oldStarred = row.starred;
row.starred = newStarred;
}
public void revert(Project project) {
Row row = project.rows.get(rowIndex);
row.starred = oldStarred;
}
}

View File

@ -31,6 +31,8 @@ public abstract class OperationRegistry {
register("column-addition", ColumnAdditionOperation.class); register("column-addition", ColumnAdditionOperation.class);
register("column-removal", ColumnRemovalOperation.class); register("column-removal", ColumnRemovalOperation.class);
register("row-star", RowStarOperation.class);
register("save-protograph", SaveProtographOperation.class); register("save-protograph", SaveProtographOperation.class);
register("text-transform", TextTransformOperation.class); register("text-transform", TextTransformOperation.class);
} }

View File

@ -0,0 +1,92 @@
package com.metaweb.gridworks.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.history.Change;
import com.metaweb.gridworks.history.HistoryEntry;
import com.metaweb.gridworks.model.AbstractOperation;
import com.metaweb.gridworks.model.Project;
import com.metaweb.gridworks.model.Row;
import com.metaweb.gridworks.model.changes.MassChange;
import com.metaweb.gridworks.model.changes.RowStarChange;
public class RowStarOperation extends EngineDependentOperation {
private static final long serialVersionUID = 7047630960948704761L;
final protected boolean _starred;
static public AbstractOperation reconstruct(Project project, JSONObject obj) throws Exception {
JSONObject engineConfig = obj.getJSONObject("engineConfig");
boolean starred = obj.getBoolean("starred");
return new RowStarOperation(
engineConfig,
starred
);
}
public RowStarOperation(JSONObject engineConfig, boolean starred) {
super(engineConfig);
_starred = starred;
}
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());
writer.key("engineConfig"); writer.value(getEngineConfig());
writer.key("starred"); writer.value(_starred);
writer.endObject();
}
protected String getBriefDescription() {
return (_starred ? "Star rows" : "Unstar rows");
}
protected HistoryEntry createHistoryEntry(Project project) throws Exception {
Engine engine = createEngine(project);
List<Change> changes = new ArrayList<Change>(project.rows.size());
FilteredRows filteredRows = engine.getAllFilteredRows(false);
filteredRows.accept(project, createRowVisitor(project, changes));
return new HistoryEntry(
project,
(_starred ? "Star" : "Unstar") + " " + changes.size() + " rows",
this,
new MassChange(changes, false)
);
}
protected RowVisitor createRowVisitor(Project project, List<Change> changes) throws Exception {
return new RowVisitor() {
List<Change> changes;
public RowVisitor init(List<Change> changes) {
this.changes = changes;
return this;
}
public boolean visit(Project project, int rowIndex, Row row, boolean contextual) {
if (row.starred != _starred) {
RowStarChange change = new RowStarChange(rowIndex, _starred);
changes.add(change);
}
return false;
}
}.init(changes);
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 778 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 465 B

View File

@ -101,7 +101,8 @@ DataTableView.prototype.render = function() {
var renderColumnKeys = function(keys) { var renderColumnKeys = function(keys) {
if (keys.length > 0) { if (keys.length > 0) {
var tr = table.insertRow(table.rows.length); var tr = table.insertRow(table.rows.length);
tr.insertCell(0); // row index tr.insertCell(0); // star
tr.insertCell(1); // row index
for (var c = 0; c < columns.length; c++) { for (var c = 0; c < columns.length; c++) {
var td = tr.insertCell(tr.cells.length); var td = tr.insertCell(tr.cells.length);
@ -120,7 +121,8 @@ DataTableView.prototype.render = function() {
if (groups.length > 0) { if (groups.length > 0) {
var tr = table.insertRow(table.rows.length); var tr = table.insertRow(table.rows.length);
tr.insertCell(0); // row index tr.insertCell(0); // star
tr.insertCell(1); // row index
for (var c = 0; c < columns.length; c++) { for (var c = 0; c < columns.length; c++) {
var foundGroup = false; var foundGroup = false;
@ -167,9 +169,9 @@ DataTableView.prototype.render = function() {
var trHead = table.insertRow(table.rows.length); var trHead = table.insertRow(table.rows.length);
var td = trHead.insertCell(trHead.cells.length); var tdHeadIndex = trHead.insertCell(trHead.cells.length);
$(td).addClass("column-header"); $(tdHeadIndex).attr("colspan", "2").addClass("column-header");
$('<img src="/images/menu-dropdown.png" />').addClass("column-header-menu").appendTo(td).click(function() { $('<img src="/images/menu-dropdown.png" />').addClass("column-header-menu").appendTo(tdHeadIndex).click(function() {
self._createMenuForAllColumns(this); self._createMenuForAllColumns(this);
}); });
@ -197,21 +199,42 @@ DataTableView.prototype.render = function() {
*/ */
var rows = theProject.rowModel.rows; var rows = theProject.rowModel.rows;
var even = true; var renderRow = function(tr, r, row, even) {
for (var r = 0; r < rows.length; r++) {
var row = rows[r];
var cells = row.cells; var cells = row.cells;
var tr = table.insertRow(table.rows.length); var tdStar = tr.insertCell(tr.cells.length);
var star = $('<a href="javascript:{}">&nbsp;</a>')
.addClass(row.starred ? "data-table-star-on" : "data-table-star-off")
.appendTo(tdStar)
.click(function() {
var newStarred = !row.starred;
$.post(
"/command/annotate-one-row?" + $.param({ project: theProject.id, row: row.i, starred: newStarred }),
null,
function(o) {
if (o.code == "ok") {
row.starred = newStarred;
var td = tr.insertCell(tr.cells.length); $(tr).empty();
renderRow(tr, r, row, even);
ui.historyWidget.update();
} else {
ui.processWidget.update();
}
},
"json"
);
});
var tdIndex = tr.insertCell(tr.cells.length);
if ("j" in row) { if ("j" in row) {
even = !even;
$(tr).addClass("record"); $(tr).addClass("record");
$('<div></div>').html((row.j + 1) + ".").appendTo(td); $('<div></div>').html((row.j + 1) + ".").appendTo(tdIndex);
} else { } else {
$('<div></div>').html("&nbsp;").appendTo(td); $('<div></div>').html("&nbsp;").appendTo(tdIndex);
} }
if ("contextual" in row && row.contextual) { if ("contextual" in row && row.contextual) {
@ -230,6 +253,16 @@ DataTableView.prototype.render = function() {
new DataTableCellUI(this, cell, row.i, column.cellIndex, td); new DataTableCellUI(this, cell, row.i, column.cellIndex, td);
} }
} }
};
var even = true;
for (var r = 0; r < rows.length; r++) {
var row = rows[r];
var tr = table.insertRow(table.rows.length);
if ("j" in row) {
even = !even;
}
renderRow(tr, r, row, even);
} }
}; };
@ -287,6 +320,19 @@ DataTableView.prototype._createMenuForAllColumns = function(elmt) {
} }
self.render(); self.render();
} }
},
{},
{
label: "Star Rows",
click: function() {
self.doPostThenUpdate("annotate-rows", { "starred" : "true" }, false);
}
},
{
label: "Unstar Rows",
click: function() {
self.doPostThenUpdate("annotate-rows", { "starred" : "false" }, false);
}
} }
], elmt); ], elmt);
}; };

View File

@ -42,6 +42,9 @@ table.column-header-layout td {
} }
img.column-header-menu { img.column-header-menu {
position: relative;
top: -5px;
left: 5px;
} }
.viewPanel-summary { .viewPanel-summary {
@ -117,3 +120,18 @@ a.data-table-recon-match-similar {
a.data-table-recon-match-similar:hover { a.data-table-recon-match-similar:hover {
background-position: 0px -17px; background-position: 0px -17px;
} }
a.data-table-star-on, a.data-table-star-off {
display: block;
width: 16px;
height: 16px;
background-image: url('../images/star-flag-map.png');
background-repeat: no-repeat;
text-decoration: none;
}
a.data-table-star-on {
background-position: 0px 0px;
}
a.data-table-star-off {
background-position: -17px 0px;
}