Added new command Transpose Cells in Columns into Rows.
git-svn-id: http://google-refine.googlecode.com/svn/trunk@1111 7d457c2a-affb-35e4-300a-418c747d4874
This commit is contained in:
parent
a192674118
commit
ee14955605
@ -71,6 +71,7 @@ public class GridworksServlet extends Butterfly {
|
||||
{"mass-edit", "com.metaweb.gridworks.commands.cell.MassEditCommand"},
|
||||
{"join-multi-value-cells", "com.metaweb.gridworks.commands.cell.JoinMultiValueCellsCommand"},
|
||||
{"split-multi-value-cells", "com.metaweb.gridworks.commands.cell.SplitMultiValueCellsCommand"},
|
||||
{"transpose-columns-into-rows", "com.metaweb.gridworks.commands.cell.TransposeColumnsIntoRowsCommand"},
|
||||
|
||||
{"add-column", "com.metaweb.gridworks.commands.column.AddColumnCommand"},
|
||||
{"remove-column", "com.metaweb.gridworks.commands.column.RemoveColumnCommand"},
|
||||
|
@ -0,0 +1,42 @@
|
||||
package com.metaweb.gridworks.commands.cell;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Properties;
|
||||
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import com.metaweb.gridworks.commands.Command;
|
||||
import com.metaweb.gridworks.model.AbstractOperation;
|
||||
import com.metaweb.gridworks.model.Project;
|
||||
import com.metaweb.gridworks.operations.cell.TransposeColumnsIntoRowsOperation;
|
||||
import com.metaweb.gridworks.process.Process;
|
||||
|
||||
public class TransposeColumnsIntoRowsCommand extends Command {
|
||||
@Override
|
||||
public void doPost(HttpServletRequest request, HttpServletResponse response)
|
||||
throws ServletException, IOException {
|
||||
|
||||
try {
|
||||
Project project = getProject(request);
|
||||
|
||||
String startColumnName = request.getParameter("startColumnName");
|
||||
int columnCount = Integer.parseInt(request.getParameter("columnCount"));
|
||||
String combinedColumnName = request.getParameter("combinedColumnName");
|
||||
|
||||
boolean prependColumnName = Boolean.parseBoolean(request.getParameter("prependColumnName"));
|
||||
String separator = request.getParameter("separator");
|
||||
boolean ignoreBlankCells = Boolean.parseBoolean(request.getParameter("ignoreBlankCells"));
|
||||
|
||||
AbstractOperation op = new TransposeColumnsIntoRowsOperation(
|
||||
startColumnName, columnCount, combinedColumnName, prependColumnName, separator, ignoreBlankCells);
|
||||
|
||||
Process process = op.createProcess(project, new Properties());
|
||||
|
||||
performProcessAndRespond(request, response, project, process);
|
||||
} catch (Exception e) {
|
||||
respondException(response, e);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,139 @@
|
||||
package com.metaweb.gridworks.model.changes;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.LineNumberReader;
|
||||
import java.io.Writer;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Properties;
|
||||
|
||||
import com.metaweb.gridworks.history.Change;
|
||||
import com.metaweb.gridworks.model.Column;
|
||||
import com.metaweb.gridworks.model.Project;
|
||||
import com.metaweb.gridworks.model.Row;
|
||||
import com.metaweb.gridworks.util.Pool;
|
||||
|
||||
public class MassRowColumnChange implements Change {
|
||||
final protected List<Column> _newColumns;
|
||||
final protected List<Row> _newRows;
|
||||
protected List<Column> _oldColumns;
|
||||
protected List<Row> _oldRows;
|
||||
|
||||
public MassRowColumnChange(List<Column> newColumns, List<Row> newRows) {
|
||||
_newColumns = newColumns;
|
||||
_newRows = newRows;
|
||||
}
|
||||
|
||||
public void apply(Project project) {
|
||||
synchronized (project) {
|
||||
_oldColumns = new ArrayList<Column>(project.columnModel.columns);
|
||||
_oldRows = new ArrayList<Row>(project.rows);
|
||||
|
||||
project.columnModel.columns.clear();
|
||||
project.columnModel.columns.addAll(_newColumns);
|
||||
|
||||
project.rows.clear();
|
||||
project.rows.addAll(_newRows);
|
||||
|
||||
project.update();
|
||||
}
|
||||
}
|
||||
|
||||
public void revert(Project project) {
|
||||
synchronized (project) {
|
||||
project.columnModel.columns.clear();
|
||||
project.columnModel.columns.addAll(_oldColumns);
|
||||
|
||||
project.rows.clear();
|
||||
project.rows.addAll(_oldRows);
|
||||
|
||||
project.update();
|
||||
}
|
||||
}
|
||||
|
||||
public void save(Writer writer, Properties options) throws IOException {
|
||||
writer.write("newColumnCount="); writer.write(Integer.toString(_newColumns.size())); writer.write('\n');
|
||||
for (Column column : _newColumns) {
|
||||
column.save(writer);
|
||||
writer.write('\n');
|
||||
}
|
||||
writer.write("oldColumnCount="); writer.write(Integer.toString(_oldColumns.size())); writer.write('\n');
|
||||
for (Column column : _oldColumns) {
|
||||
column.save(writer);
|
||||
writer.write('\n');
|
||||
}
|
||||
writer.write("newRowCount="); writer.write(Integer.toString(_newRows.size())); writer.write('\n');
|
||||
for (Row row : _newRows) {
|
||||
row.save(writer, options);
|
||||
writer.write('\n');
|
||||
}
|
||||
writer.write("oldRowCount="); writer.write(Integer.toString(_oldRows.size())); writer.write('\n');
|
||||
for (Row row : _oldRows) {
|
||||
row.save(writer, options);
|
||||
writer.write('\n');
|
||||
}
|
||||
writer.write("/ec/\n"); // end of change marker
|
||||
}
|
||||
|
||||
static public Change load(LineNumberReader reader, Pool pool) throws Exception {
|
||||
List<Column> oldColumns = null;
|
||||
List<Column> newColumns = null;
|
||||
|
||||
List<Row> oldRows = null;
|
||||
List<Row> newRows = null;
|
||||
|
||||
String line;
|
||||
while ((line = reader.readLine()) != null && !"/ec/".equals(line)) {
|
||||
int equal = line.indexOf('=');
|
||||
CharSequence field = line.subSequence(0, equal);
|
||||
|
||||
if ("oldRowCount".equals(field)) {
|
||||
int count = Integer.parseInt(line.substring(equal + 1));
|
||||
|
||||
oldRows = new ArrayList<Row>(count);
|
||||
for (int i = 0; i < count; i++) {
|
||||
line = reader.readLine();
|
||||
if (line != null) {
|
||||
oldRows.add(Row.load(line, pool));
|
||||
}
|
||||
}
|
||||
} else if ("newRowCount".equals(field)) {
|
||||
int count = Integer.parseInt(line.substring(equal + 1));
|
||||
|
||||
newRows = new ArrayList<Row>(count);
|
||||
for (int i = 0; i < count; i++) {
|
||||
line = reader.readLine();
|
||||
if (line != null) {
|
||||
newRows.add(Row.load(line, pool));
|
||||
}
|
||||
}
|
||||
} else if ("oldColumnCount".equals(field)) {
|
||||
int count = Integer.parseInt(line.substring(equal + 1));
|
||||
|
||||
oldColumns = new ArrayList<Column>(count);
|
||||
for (int i = 0; i < count; i++) {
|
||||
line = reader.readLine();
|
||||
if (line != null) {
|
||||
oldColumns.add(Column.load(line));
|
||||
}
|
||||
}
|
||||
} else if ("newColumnCount".equals(field)) {
|
||||
int count = Integer.parseInt(line.substring(equal + 1));
|
||||
|
||||
newColumns = new ArrayList<Column>(count);
|
||||
for (int i = 0; i < count; i++) {
|
||||
line = reader.readLine();
|
||||
if (line != null) {
|
||||
newColumns.add(Column.load(line));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MassRowColumnChange change = new MassRowColumnChange(newColumns, newRows);
|
||||
change._oldColumns = oldColumns;
|
||||
change._oldRows = oldRows;
|
||||
|
||||
return change;
|
||||
}
|
||||
}
|
@ -0,0 +1,171 @@
|
||||
package com.metaweb.gridworks.operations.cell;
|
||||
|
||||
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.history.HistoryEntry;
|
||||
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.MassRowColumnChange;
|
||||
import com.metaweb.gridworks.operations.OperationRegistry;
|
||||
|
||||
public class TransposeColumnsIntoRowsOperation extends AbstractOperation {
|
||||
final protected String _startColumnName;
|
||||
final protected int _columnCount;
|
||||
final protected String _combinedColumnName;
|
||||
final protected boolean _prependColumnName;
|
||||
final protected String _separator;
|
||||
final protected boolean _ignoreBlankCells;
|
||||
|
||||
static public AbstractOperation reconstruct(Project project, JSONObject obj) throws Exception {
|
||||
return new TransposeColumnsIntoRowsOperation(
|
||||
obj.getString("startColumnName"),
|
||||
obj.getInt("columnCount"),
|
||||
obj.getString("combinedColumnName"),
|
||||
obj.getBoolean("prependColumnName"),
|
||||
obj.getString("separator"),
|
||||
obj.getBoolean("ignoreBlankCells")
|
||||
);
|
||||
}
|
||||
|
||||
public TransposeColumnsIntoRowsOperation(
|
||||
String startColumnName,
|
||||
int columnCount,
|
||||
String combinedColumnName,
|
||||
boolean prependColumnName,
|
||||
String separator,
|
||||
boolean ignoreBlankCells
|
||||
) {
|
||||
_startColumnName = startColumnName;
|
||||
_columnCount = columnCount;
|
||||
_combinedColumnName = combinedColumnName;
|
||||
_prependColumnName = prependColumnName;
|
||||
_separator = separator;
|
||||
_ignoreBlankCells = ignoreBlankCells;
|
||||
}
|
||||
|
||||
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("Transpose cells in " + _columnCount + " column(s) starting with " + _startColumnName + " into rows");
|
||||
writer.key("startColumnName"); writer.value(_startColumnName);
|
||||
writer.key("columnCount"); writer.value(_columnCount);
|
||||
writer.key("combinedColumnName"); writer.value(_combinedColumnName);
|
||||
writer.key("prependColumnName"); writer.value(_prependColumnName);
|
||||
writer.key("separator"); writer.value(_separator);
|
||||
writer.key("ignoreBlankCells"); writer.value(_ignoreBlankCells);
|
||||
writer.endObject();
|
||||
}
|
||||
|
||||
protected String getBriefDescription(Project project) {
|
||||
return "Transpose cells in " + _columnCount + " column(s) starting with " + _startColumnName + " into rows";
|
||||
}
|
||||
|
||||
@Override
|
||||
protected HistoryEntry createHistoryEntry(Project project, long historyEntryID) throws Exception {
|
||||
List<Column> newColumns = new ArrayList<Column>();
|
||||
List<Column> oldColumns = project.columnModel.columns;
|
||||
|
||||
int columnsLeftToTranspose = _columnCount;
|
||||
int startColumnIndex = oldColumns.size();
|
||||
for (int c = 0; c < oldColumns.size(); c++) {
|
||||
Column column = oldColumns.get(c);
|
||||
if (columnsLeftToTranspose == 0) {
|
||||
// This column is beyond the columns to transpose
|
||||
|
||||
Column newColumn = new Column(newColumns.size(), column.getOriginalHeaderLabel());
|
||||
newColumn.setName(column.getName());
|
||||
|
||||
newColumns.add(newColumn);
|
||||
} else if (columnsLeftToTranspose < _columnCount) {
|
||||
// This column is a column to transpose, but not the first
|
||||
// nothing to do
|
||||
|
||||
columnsLeftToTranspose--;
|
||||
} else if (_startColumnName.equals(column.getName())) {
|
||||
// This is the first column to transpose
|
||||
|
||||
startColumnIndex = c;
|
||||
|
||||
String columnName = _combinedColumnName != null && _combinedColumnName.length() > 0 ? _combinedColumnName : column.getName();
|
||||
Column newColumn = new Column(newColumns.size(), columnName);
|
||||
|
||||
newColumns.add(newColumn);
|
||||
|
||||
columnsLeftToTranspose--;
|
||||
} else {
|
||||
// This column is before all columns to transpose
|
||||
|
||||
Column newColumn = new Column(newColumns.size(), column.getOriginalHeaderLabel());
|
||||
newColumn.setName(column.getName());
|
||||
|
||||
newColumns.add(newColumn);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
List<Row> oldRows = project.rows;
|
||||
List<Row> newRows = new ArrayList<Row>(oldRows.size() * _columnCount);
|
||||
for (int r = 0; r < oldRows.size(); r++) {
|
||||
Row oldRow = project.rows.get(r);
|
||||
Row firstNewRow = new Row(newColumns.size());
|
||||
|
||||
newRows.add(firstNewRow);
|
||||
|
||||
int transposedCells = 0;
|
||||
for (int c = 0; c < oldColumns.size(); c++) {
|
||||
Column column = oldColumns.get(c);
|
||||
Cell cell = oldRow.getCell(column.getCellIndex());
|
||||
|
||||
if (c < startColumnIndex) {
|
||||
firstNewRow.setCell(c, cell);
|
||||
} else if (c == startColumnIndex || c < startColumnIndex + _columnCount) {
|
||||
Cell newCell;
|
||||
|
||||
if (cell == null || cell.value == null) {
|
||||
if (_prependColumnName && !_ignoreBlankCells) {
|
||||
newCell = new Cell(column.getName() + _separator, null);
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
} else if (_prependColumnName) {
|
||||
newCell = new Cell(column.getName() + _separator + cell.value, null);
|
||||
} else {
|
||||
newCell = cell;
|
||||
}
|
||||
|
||||
if (transposedCells == 0) {
|
||||
firstNewRow.setCell(startColumnIndex, newCell);
|
||||
} else {
|
||||
Row newRow = new Row(newColumns.size());
|
||||
|
||||
newRow.setCell(startColumnIndex, newCell);
|
||||
newRows.add(newRow);
|
||||
}
|
||||
|
||||
transposedCells++;
|
||||
} else {
|
||||
firstNewRow.setCell(c - _columnCount + 1, cell);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return new HistoryEntry(
|
||||
historyEntryID,
|
||||
project,
|
||||
getBriefDescription(null),
|
||||
this,
|
||||
new MassRowColumnChange(newColumns, newRows)
|
||||
);
|
||||
}
|
||||
}
|
@ -127,6 +127,10 @@ BrowsingEngine.prototype._updateFacetOrder = function() {
|
||||
this._facets = newFacets;
|
||||
};
|
||||
|
||||
BrowsingEngine.prototype.getMode = function() {
|
||||
return this._elmts.modeSelectors.find("input:checked")[0].value;
|
||||
};
|
||||
|
||||
BrowsingEngine.prototype.getJSON = function(keepUnrestrictedFacets, except) {
|
||||
var a = {
|
||||
facets: [],
|
||||
|
@ -320,6 +320,15 @@ DataTableColumnHeaderUI.prototype._createMenuForColumnHeader = function(elmt) {
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
label: "Transpose",
|
||||
submenu: [
|
||||
{
|
||||
label: "Cells Across Columns into Rows",
|
||||
click: function() { self._doTransposeColumnsIntoRows(); }
|
||||
}
|
||||
]
|
||||
},
|
||||
{},
|
||||
(
|
||||
this._dataTableView._getSortingCriterionForColumn(this._column.name) == null ?
|
||||
@ -1083,6 +1092,74 @@ DataTableColumnHeaderUI.prototype._doSplitColumn = function() {
|
||||
footerElmts.cancelButton.click(dismiss);
|
||||
};
|
||||
|
||||
DataTableColumnHeaderUI.prototype._doTransposeColumnsIntoRows = function() {
|
||||
var self = this;
|
||||
var dialog = $(DOM.loadHTML("core", "scripts/views/data-table/transpose-columns-into-rows.html"));
|
||||
|
||||
var elmts = DOM.bind(dialog);
|
||||
elmts.dialogHeader.text('Transpose Cells Across Columns into Rows');
|
||||
|
||||
var level = DialogSystem.showDialog(dialog);
|
||||
var dismiss = function() {
|
||||
DialogSystem.dismissUntil(level - 1);
|
||||
};
|
||||
|
||||
var columns = theProject.columnModel.columns;
|
||||
|
||||
elmts.cancelButton.click(function() { dismiss(); });
|
||||
elmts.okButton.click(function() {
|
||||
var config = {
|
||||
startColumnName: elmts.fromColumnSelect[0].value,
|
||||
columnCount: elmts.toColumnSelect[0].value,
|
||||
combinedColumnName: $.trim(elmts.combinedColumnNameInput[0].value),
|
||||
prependColumnName: elmts.prependColumnNameCheckbox[0].checked,
|
||||
separator: elmts.separatorInput[0].value,
|
||||
ignoreBlankCells: elmts.ignoreBlankCellsCheckbox[0].checked
|
||||
};
|
||||
|
||||
Gridworks.postProcess(
|
||||
"transpose-columns-into-rows",
|
||||
config,
|
||||
null,
|
||||
{ modelsChanged: true }
|
||||
);
|
||||
dismiss();
|
||||
});
|
||||
|
||||
for (var i = 0; i < columns.length; i++) {
|
||||
var column = columns[i];
|
||||
var option = $('<option>').attr("value", column.name).text(column.name).appendTo(elmts.fromColumnSelect);
|
||||
if (column.name == this._column.name) {
|
||||
option.attr("selected", "true");
|
||||
}
|
||||
}
|
||||
|
||||
var populateToColumn = function() {
|
||||
elmts.toColumnSelect.empty();
|
||||
|
||||
var toColumnName = elmts.fromColumnSelect[0].value;
|
||||
|
||||
var j = 0;
|
||||
for (; j < columns.length; j++) {
|
||||
var column = columns[j];
|
||||
if (column.name == toColumnName) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
for (var k = j + 1; k < columns.length; k++) {
|
||||
var column = columns[k];
|
||||
var option = $('<option>').attr("value", k - j + 1).text(column.name).appendTo(elmts.toColumnSelect);
|
||||
if (k == columns.length - 1) {
|
||||
option.attr("selected", "true");
|
||||
}
|
||||
}
|
||||
};
|
||||
populateToColumn();
|
||||
|
||||
elmts.fromColumnSelect.bind("change", populateToColumn);
|
||||
};
|
||||
|
||||
DataTableColumnHeaderUI.prototype._showSortingCriterion = function(criterion, hasOtherCriteria) {
|
||||
var self = this;
|
||||
|
||||
|
@ -0,0 +1,38 @@
|
||||
<div class="dialog-frame" style="width: 600px;">
|
||||
<div class="dialog-header" bind="dialogHeader"></div>
|
||||
<div class="dialog-body" bind="dialogBody">
|
||||
<div class="grid-layout layout-normal layout-full grid-layout-for-ui"><table>
|
||||
<tr>
|
||||
<td>From Column</td>
|
||||
<td>To Column</td>
|
||||
<td>Formatting Options</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><select bind="fromColumnSelect" size="20" style="width: 100%;"></select></td>
|
||||
<td><select bind="toColumnSelect" size="20" style="width: 100%;"></select></td>
|
||||
<td><div class="grid-layout layout-tightest"><table>
|
||||
<tr>
|
||||
<td colspan="2">Combined column name <input bind="combinedColumnNameInput" size="15" /></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan="2"><input type="checkbox" bind="prependColumnNameCheckbox" checked /> prepend column name</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td> </td>
|
||||
<td>Separate column name and cell value with
|
||||
<input bind="separatorInput" size="5" value=":" />
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td> </td>
|
||||
<td><input type="checkbox" bind="ignoreBlankCellsCheckbox" checked /> ignore blank cells</td>
|
||||
</tr>
|
||||
</table></div></td>
|
||||
</tr>
|
||||
</table></div>
|
||||
</div>
|
||||
<div class="dialog-footer" bind="dialogFooter">
|
||||
<button bind="okButton">Transpose</button>
|
||||
<button bind="cancelButton">Cancel</button>
|
||||
</div>
|
||||
</div>
|
Loading…
Reference in New Issue
Block a user