diff --git a/LICENSE.txt b/LICENSE.txt index 826ed2544..b84cbde1d 100644 --- a/LICENSE.txt +++ b/LICENSE.txt @@ -106,3 +106,9 @@ licenses/icu4j.LICENSE.txt licenses/json.LICENSE.txt json + +Others +------ + +Flag icon + http://pixel-mixer.com/category/free-icons/ \ No newline at end of file diff --git a/src/graphics/star-flag-map.psd b/src/graphics/star-flag-map.psd index e40045d48..e4aac5036 100644 Binary files a/src/graphics/star-flag-map.psd and b/src/graphics/star-flag-map.psd differ diff --git a/src/main/java/com/metaweb/gridworks/commands/edit/AnnotateOneRowCommand.java b/src/main/java/com/metaweb/gridworks/commands/edit/AnnotateOneRowCommand.java index a101f612b..8b4028408 100644 --- a/src/main/java/com/metaweb/gridworks/commands/edit/AnnotateOneRowCommand.java +++ b/src/main/java/com/metaweb/gridworks/commands/edit/AnnotateOneRowCommand.java @@ -38,9 +38,27 @@ public class AnnotateOneRowCommand extends Command { ); performProcessAndRespond(request, response, project, process); - } else { - respond(response, "{ \"code\" : \"error\", \"message\" : \"invalid command parameters\" }"); + return; } + + String flaggedString = request.getParameter("flagged"); + if (flaggedString != null) { + boolean flagged = "true".endsWith(flaggedString); + String description = (flagged ? "Flag row " : "Unflag row ") + (rowIndex + 1); + + FlagOneRowProcess process = new FlagOneRowProcess( + project, + description, + rowIndex, + flagged + ); + + performProcessAndRespond(request, response, project, process); + return; + } + + respond(response, "{ \"code\" : \"error\", \"message\" : \"invalid command parameters\" }"); + } catch (Exception e) { respondException(response, e); } @@ -71,4 +89,29 @@ public class AnnotateOneRowCommand extends Command { ); } } + protected static class FlagOneRowProcess extends QuickHistoryEntryProcess { + final int rowIndex; + final boolean flagged; + + FlagOneRowProcess( + Project project, + String briefDescription, + int rowIndex, + boolean flagged + ) { + super(project, briefDescription); + + this.rowIndex = rowIndex; + this.flagged = flagged; + } + + protected HistoryEntry createHistoryEntry() throws Exception { + return new HistoryEntry( + _project, + (flagged ? "Flag row " : "Unflag row ") + (rowIndex + 1), + null, + new RowStarChange(rowIndex, flagged) + ); + } + } } diff --git a/src/main/java/com/metaweb/gridworks/commands/edit/AnnotateRowsCommand.java b/src/main/java/com/metaweb/gridworks/commands/edit/AnnotateRowsCommand.java index c1d747b8e..165ea10d4 100644 --- a/src/main/java/com/metaweb/gridworks/commands/edit/AnnotateRowsCommand.java +++ b/src/main/java/com/metaweb/gridworks/commands/edit/AnnotateRowsCommand.java @@ -7,6 +7,7 @@ import org.json.JSONObject; import com.metaweb.gridworks.commands.EngineDependentCommand; import com.metaweb.gridworks.model.AbstractOperation; import com.metaweb.gridworks.model.Project; +import com.metaweb.gridworks.operations.RowFlagOperation; import com.metaweb.gridworks.operations.RowStarOperation; public class AnnotateRowsCommand extends EngineDependentCommand { @@ -21,6 +22,13 @@ public class AnnotateRowsCommand extends EngineDependentCommand { return new RowStarOperation(engineConfig, starred); } + + String flaggedString = request.getParameter("flagged"); + if (flaggedString != null) { + boolean flagged = "true".endsWith(flaggedString); + + return new RowFlagOperation(engineConfig, flagged); + } return null; } } diff --git a/src/main/java/com/metaweb/gridworks/model/changes/RowFlagChange.java b/src/main/java/com/metaweb/gridworks/model/changes/RowFlagChange.java new file mode 100644 index 000000000..96859262d --- /dev/null +++ b/src/main/java/com/metaweb/gridworks/model/changes/RowFlagChange.java @@ -0,0 +1,69 @@ +package com.metaweb.gridworks.model.changes; + +import java.io.IOException; +import java.io.LineNumberReader; +import java.io.Writer; +import java.util.Properties; + +import com.metaweb.gridworks.history.Change; +import com.metaweb.gridworks.model.Project; +import com.metaweb.gridworks.model.Row; +import com.metaweb.gridworks.util.Pool; + +public class RowFlagChange implements Change { + final int rowIndex; + final boolean newFlagged; + Boolean oldFlagged = null; + + public RowFlagChange(int rowIndex, boolean newFlagged) { + this.rowIndex = rowIndex; + this.newFlagged = newFlagged; + } + + public void apply(Project project) { + Row row = project.rows.get(rowIndex); + if (oldFlagged == null) { + oldFlagged = row.flagged; + } + row.flagged = newFlagged; + } + + public void revert(Project project) { + Row row = project.rows.get(rowIndex); + + row.flagged = oldFlagged; + } + + public void save(Writer writer, Properties options) throws IOException { + writer.write("row="); writer.write(Integer.toString(rowIndex)); writer.write('\n'); + writer.write("newFlagged="); writer.write(Boolean.toString(newFlagged)); writer.write('\n'); + writer.write("oldFlagged="); writer.write(Boolean.toString(oldFlagged)); writer.write('\n'); + writer.write("/ec/\n"); // end of change marker + } + + static public RowFlagChange load(LineNumberReader reader, Pool pool) throws Exception { + int row = -1; + boolean oldStarred = false; + boolean newStarred = false; + + String line; + while ((line = reader.readLine()) != null && !"/ec/".equals(line)) { + int equal = line.indexOf('='); + CharSequence field = line.subSequence(0, equal); + String value = line.substring(equal + 1); + + if ("row".equals(field)) { + row = Integer.parseInt(value); + } else if ("oldFlagged".equals(field)) { + oldStarred = Boolean.parseBoolean(value); + } else if ("newFlagged".equals(field)) { + oldStarred = Boolean.parseBoolean(value); + } + } + + RowFlagChange change = new RowFlagChange(row, newStarred); + change.oldFlagged = oldStarred; + + return change; + } +} \ No newline at end of file diff --git a/src/main/java/com/metaweb/gridworks/model/changes/RowStarChange.java b/src/main/java/com/metaweb/gridworks/model/changes/RowStarChange.java index ef50654ac..b2d840456 100644 --- a/src/main/java/com/metaweb/gridworks/model/changes/RowStarChange.java +++ b/src/main/java/com/metaweb/gridworks/model/changes/RowStarChange.java @@ -13,7 +13,7 @@ import com.metaweb.gridworks.util.Pool; public class RowStarChange implements Change { final int rowIndex; final boolean newStarred; - boolean oldStarred; + Boolean oldStarred = null; public RowStarChange(int rowIndex, boolean newStarred) { this.rowIndex = rowIndex; @@ -22,8 +22,9 @@ public class RowStarChange implements Change { public void apply(Project project) { Row row = project.rows.get(rowIndex); - - oldStarred = row.starred; + if (oldStarred == null) { + oldStarred = row.starred; + } row.starred = newStarred; } diff --git a/src/main/java/com/metaweb/gridworks/operations/OperationRegistry.java b/src/main/java/com/metaweb/gridworks/operations/OperationRegistry.java index 25f260c93..90d53cff7 100644 --- a/src/main/java/com/metaweb/gridworks/operations/OperationRegistry.java +++ b/src/main/java/com/metaweb/gridworks/operations/OperationRegistry.java @@ -38,6 +38,7 @@ public abstract class OperationRegistry { register("row-removal", RowRemovalOperation.class); register("row-star", RowStarOperation.class); + register("row-flag", RowFlagOperation.class); register("save-protograph", SaveProtographOperation.class); register("text-transform", TextTransformOperation.class); diff --git a/src/main/java/com/metaweb/gridworks/operations/RowFlagOperation.java b/src/main/java/com/metaweb/gridworks/operations/RowFlagOperation.java new file mode 100644 index 000000000..9a05b7a50 --- /dev/null +++ b/src/main/java/com/metaweb/gridworks/operations/RowFlagOperation.java @@ -0,0 +1,90 @@ +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.RowFlagChange; + +public class RowFlagOperation extends EngineDependentOperation { + final protected boolean _flagged; + + static public AbstractOperation reconstruct(Project project, JSONObject obj) throws Exception { + JSONObject engineConfig = obj.getJSONObject("engineConfig"); + boolean flagged = obj.getBoolean("flagged"); + + return new RowFlagOperation( + engineConfig, + flagged + ); + } + + public RowFlagOperation(JSONObject engineConfig, boolean flagged) { + super(engineConfig); + _flagged = flagged; + } + + 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("flagged"); writer.value(_flagged); + writer.endObject(); + } + + protected String getBriefDescription(Project project) { + return (_flagged ? "Flag rows" : "Unflag rows"); + } + + protected HistoryEntry createHistoryEntry(Project project) throws Exception { + Engine engine = createEngine(project); + + List changes = new ArrayList(project.rows.size()); + + FilteredRows filteredRows = engine.getAllFilteredRows(false); + filteredRows.accept(project, createRowVisitor(project, changes)); + + return new HistoryEntry( + project, + (_flagged ? "Flag" : "Unflag") + " " + changes.size() + " rows", + this, + new MassChange(changes, false) + ); + } + + protected RowVisitor createRowVisitor(Project project, List changes) throws Exception { + return new RowVisitor() { + List changes; + + public RowVisitor init(List changes) { + this.changes = changes; + return this; + } + + public boolean visit(Project project, int rowIndex, Row row, boolean includeContextual, boolean includeDependent) { + if (row.starred != _flagged) { + RowFlagChange change = new RowFlagChange(rowIndex, _flagged); + + changes.add(change); + } + return false; + } + }.init(changes); + } +} diff --git a/src/main/webapp/about.html b/src/main/webapp/about.html index 70fb668e9..d0aa096bc 100644 --- a/src/main/webapp/about.html +++ b/src/main/webapp/about.html @@ -1 +1 @@ - About Freebase Gridworks

About Freebase Gridworks

Freebase Gridworks is a power tool that allows you to load data, understand it, clean it up, reconcile it internally, and augment it with data coming from Freebase. All with the comfort and privacy of your own computer.

It was originally developed by Metaweb Technologies, Inc.

License

/*
 * Copyright (c) 2010, Metaweb Technologies, Inc. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *  1. Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *  2. Redistributions in binary form must reproduce the above
 *     copyright notice, this list of conditions and the following
 *     disclaimer in the documentation and/or other materials provided
 *     with the distribution.
 * 
 * THIS SOFTWARE IS PROVIDED BY METAWEB TECHNOLOGIES AND CONTRIBUTORS
 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL METAWEB
 * TECHNOLOGIES OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 */

Dependencies Licenses

licenses/apache2.0.LICENSE.txt
    ant (package org.apache.tools.tar)
    bzip2 (package org.apache.tools.bzip2)
    calendar-parser (package com.metaweb.gridworks.expr.util)
    commons-lang
    commons-codec
    jackson
    jdatapath
    jetty
    jetty-util
    log4j
    poi
    poi-ooxml
    poi-ooxml-schemas
    servlet-api
    xmlbeans
 
licenses/secondstring.LICENSE.txt (BSD family)
    secondstring

licenses/dom4j.LICENSE.txt (BSD family)
    dom4j
    
licenses/simile.LICENSE.txt (BSD family)
    vicino (package edu.mit.simile.vicino)

licenses/arithcode.LICENSE.txt (BSD family)
    arithcode
       
licenses/icu4j.LICENSE.txt (MIT family)
    icu4j
   
licenses/slf4j.LICENSE.txt (MIT family)
    slf4j-api
    slf4j-log4j12
    jcl-over-slf4j

licenses/json.LICENSE.txt (MIT family)    
    json
    
licenses/cos.LICENSE.txt
    cos

Credits

Special Thanks

\ No newline at end of file + About Freebase Gridworks

About Freebase Gridworks

Freebase Gridworks is a power tool that allows you to load data, understand it, clean it up, reconcile it internally, and augment it with data coming from Freebase. All with the comfort and privacy of your own computer.

It was originally developed by Metaweb Technologies, Inc.

License

/*
 * Copyright (c) 2010, Metaweb Technologies, Inc. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *  1. Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *  2. Redistributions in binary form must reproduce the above
 *     copyright notice, this list of conditions and the following
 *     disclaimer in the documentation and/or other materials provided
 *     with the distribution.
 * 
 * THIS SOFTWARE IS PROVIDED BY METAWEB TECHNOLOGIES AND CONTRIBUTORS
 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL METAWEB
 * TECHNOLOGIES OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 */

Dependencies Licenses

licenses/apache2.0.LICENSE.txt
    ant (package org.apache.tools.tar)
    bzip2 (package org.apache.tools.bzip2)
    calendar-parser (package com.metaweb.gridworks.expr.util)
    commons-lang
    commons-codec
    jackson
    jdatapath
    jetty
    jetty-util
    log4j
    poi
    poi-ooxml
    poi-ooxml-schemas
    servlet-api
    xmlbeans
 
licenses/secondstring.LICENSE.txt (BSD family)
    secondstring

licenses/dom4j.LICENSE.txt (BSD family)
    dom4j
    
licenses/simile.LICENSE.txt (BSD family)
    vicino (package edu.mit.simile.vicino)

licenses/arithcode.LICENSE.txt (BSD family)
    arithcode
       
licenses/icu4j.LICENSE.txt (MIT family)
    icu4j
   
licenses/slf4j.LICENSE.txt (MIT family)
    slf4j-api
    slf4j-log4j12
    jcl-over-slf4j

licenses/json.LICENSE.txt (MIT family)    
    json
    
licenses/cos.LICENSE.txt
    cos
    
Flag icon, free for commercial reuse
    http://pixel-mixer.com/category/free-icons/

Credits

Special Thanks

\ No newline at end of file diff --git a/src/main/webapp/images/star-flag-map.png b/src/main/webapp/images/star-flag-map.png index d6af94d2f..eeb18d212 100644 Binary files a/src/main/webapp/images/star-flag-map.png and b/src/main/webapp/images/star-flag-map.png differ diff --git a/src/main/webapp/scripts/views/data-table-view.js b/src/main/webapp/scripts/views/data-table-view.js index 6980f55e9..0bc3c03fd 100644 --- a/src/main/webapp/scripts/views/data-table-view.js +++ b/src/main/webapp/scripts/views/data-table-view.js @@ -122,7 +122,8 @@ DataTableView.prototype._renderDataTable = function(table) { if (keys.length > 0) { var tr = table.insertRow(table.rows.length); tr.insertCell(0); // star - tr.insertCell(1); // row index + tr.insertCell(1); // flag + tr.insertCell(2); // row index for (var c = 0; c < columns.length; c++) { var td = tr.insertCell(tr.cells.length); @@ -143,7 +144,8 @@ DataTableView.prototype._renderDataTable = function(table) { if (groups.length > 0) { var tr = table.insertRow(table.rows.length); tr.insertCell(0); // star - tr.insertCell(1); // row index + tr.insertCell(1); // flag + tr.insertCell(2); // row index for (var c = 0; c < columns.length; c++) { var foundGroup = false; @@ -197,7 +199,7 @@ DataTableView.prototype._renderDataTable = function(table) { var trHead = table.insertRow(table.rows.length); DOM.bind( $(trHead.insertCell(trHead.cells.length)) - .attr("colspan", "2") + .attr("colspan", "3") .addClass("column-header") .html( '' + @@ -260,6 +262,27 @@ DataTableView.prototype._renderDataTable = function(table) { "json" ); }); + + var tdFlag = tr.insertCell(tr.cells.length); + var flag = $(' ') + .addClass(row.flagged ? "data-table-flag-on" : "data-table-flag-off") + .appendTo(tdFlag) + .click(function() { + var newFlagged = !row.flagged; + + Gridworks.postProcess( + "annotate-one-row", + { row: row.i, flagged: newFlagged }, + null, + {}, + { onDone: function(o) { + row.flagged = newFlagged; + renderRow(tr, r, row, even); + } + }, + "json" + ); + }); var tdIndex = tr.insertCell(tr.cells.length); if ("j" in row) { @@ -345,6 +368,22 @@ DataTableView.prototype._createMenuForAllColumns = function(elmt) { } ); } + }, + { + label: "Facet by Flag", + click: function() { + ui.browsingEngine.addFacet( + "list", + { + "name" : "Flagged Rows", + "columnName" : "", + "expression" : "row.flagged" + }, + { + "scroll" : false + } + ); + } } ] }, @@ -364,7 +403,20 @@ DataTableView.prototype._createMenuForAllColumns = function(elmt) { }, {}, { - label: "Remove Matching Rows", + label: "Flag Rows", + click: function() { + Gridworks.postProcess("annotate-rows", { "flagged" : "true" }, null, { rowMetadataChanged: true }); + } + }, + { + label: "Unflag Rows", + click: function() { + Gridworks.postProcess("annotate-rows", { "flagged" : "false" }, null, { rowMetadataChanged: true }); + } + }, + {}, + { + label: "Remove All Matching Rows", click: function() { Gridworks.postProcess("remove-rows", {}, null, { rowMetadataChanged: true }); } diff --git a/src/main/webapp/styles/views/data-table-view.css b/src/main/webapp/styles/views/data-table-view.css index 9eaa4c652..30c3fc7ab 100644 --- a/src/main/webapp/styles/views/data-table-view.css +++ b/src/main/webapp/styles/views/data-table-view.css @@ -200,7 +200,7 @@ a.data-table-recon-match-similar:hover { background-position: 0px -17px; } -a.data-table-star-on, a.data-table-star-off { +a.data-table-star-on, a.data-table-star-off, a.data-table-flag-on, a.data-table-flag-off { display: block; width: 16px; height: 16px; @@ -208,12 +208,18 @@ a.data-table-star-on, a.data-table-star-off { background-repeat: no-repeat; text-decoration: none; } -a.data-table-star-on { +a.data-table-star-on, a.data-table-star-off:hover { background-position: 0px 0px; } -a.data-table-star-off { +a.data-table-star-off, a.data-table-star-on:hover { background-position: -17px 0px; } +a.data-table-flag-on, a.data-table-flag-off:hover { + background-position: 0px -17px; +} +a.data-table-flag-off, a.data-table-flag-on:hover { + background-position: -17px -17px; +} .data-table-cell-editor { border: 1px solid #ccc;