Made operation "Transpose columns into rows" support the option of transposing into 2 new columns rather than just one.
git-svn-id: http://google-refine.googlecode.com/svn/trunk@2362 7d457c2a-affb-35e4-300a-418c747d4874
This commit is contained in:
parent
85a37d23f9
commit
a35b9f53f7
@ -53,17 +53,29 @@ public class TransposeColumnsIntoRowsCommand extends Command {
|
||||
|
||||
try {
|
||||
Project project = getProject(request);
|
||||
AbstractOperation op;
|
||||
|
||||
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);
|
||||
String combinedColumnName = request.getParameter("combinedColumnName");
|
||||
if (combinedColumnName != null) {
|
||||
boolean prependColumnName = Boolean.parseBoolean(request.getParameter("prependColumnName"));
|
||||
String separator = request.getParameter("separator");
|
||||
op = new TransposeColumnsIntoRowsOperation(
|
||||
startColumnName, columnCount,
|
||||
combinedColumnName, prependColumnName, separator,
|
||||
ignoreBlankCells);
|
||||
} else {
|
||||
String keyColumnName = request.getParameter("keyColumnName");
|
||||
String valueColumnName = request.getParameter("valueColumnName");
|
||||
|
||||
op = new TransposeColumnsIntoRowsOperation(
|
||||
startColumnName, columnCount,
|
||||
keyColumnName, valueColumnName,
|
||||
ignoreBlankCells);
|
||||
}
|
||||
|
||||
Process process = op.createProcess(project, new Properties());
|
||||
|
||||
|
@ -49,24 +49,40 @@ import com.google.refine.model.Project;
|
||||
import com.google.refine.model.Row;
|
||||
import com.google.refine.model.changes.MassRowColumnChange;
|
||||
import com.google.refine.operations.OperationRegistry;
|
||||
import com.google.refine.util.JSONUtilities;
|
||||
|
||||
public class TransposeColumnsIntoRowsOperation extends AbstractOperation {
|
||||
final protected String _startColumnName;
|
||||
final protected int _columnCount;
|
||||
final protected boolean _ignoreBlankCells;
|
||||
|
||||
final protected String _combinedColumnName;
|
||||
final protected boolean _prependColumnName;
|
||||
final protected String _separator;
|
||||
final protected boolean _ignoreBlankCells;
|
||||
|
||||
final protected String _keyColumnName;
|
||||
final protected String _valueColumnName;
|
||||
|
||||
static public AbstractOperation reconstruct(Project project, JSONObject obj) throws Exception {
|
||||
String combinedColumnName = JSONUtilities.getString(obj, "combinedColumnName", null);
|
||||
if (combinedColumnName != null) {
|
||||
return new TransposeColumnsIntoRowsOperation(
|
||||
obj.getString("startColumnName"),
|
||||
obj.getInt("columnCount"),
|
||||
obj.getString("combinedColumnName"),
|
||||
combinedColumnName,
|
||||
obj.getBoolean("prependColumnName"),
|
||||
obj.getString("separator"),
|
||||
obj.getBoolean("ignoreBlankCells")
|
||||
);
|
||||
} else {
|
||||
return new TransposeColumnsIntoRowsOperation(
|
||||
obj.getString("startColumnName"),
|
||||
obj.getInt("columnCount"),
|
||||
obj.getString("keyColumnName"),
|
||||
obj.getString("valueColumnName"),
|
||||
obj.getBoolean("ignoreBlankCells")
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
public TransposeColumnsIntoRowsOperation(
|
||||
@ -79,10 +95,33 @@ public class TransposeColumnsIntoRowsOperation extends AbstractOperation {
|
||||
) {
|
||||
_startColumnName = startColumnName;
|
||||
_columnCount = columnCount;
|
||||
_ignoreBlankCells = ignoreBlankCells;
|
||||
|
||||
_combinedColumnName = combinedColumnName;
|
||||
_prependColumnName = prependColumnName;
|
||||
_separator = separator;
|
||||
|
||||
_keyColumnName = null;
|
||||
_valueColumnName = null;
|
||||
}
|
||||
|
||||
public TransposeColumnsIntoRowsOperation(
|
||||
String startColumnName,
|
||||
int columnCount,
|
||||
String keyColumnName,
|
||||
String valueColumnName,
|
||||
boolean ignoreBlankCells
|
||||
) {
|
||||
_startColumnName = startColumnName;
|
||||
_columnCount = columnCount;
|
||||
_ignoreBlankCells = ignoreBlankCells;
|
||||
|
||||
_combinedColumnName = null;
|
||||
_prependColumnName = false;
|
||||
_separator = null;
|
||||
|
||||
_keyColumnName = keyColumnName;
|
||||
_valueColumnName = valueColumnName;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -91,37 +130,66 @@ public class TransposeColumnsIntoRowsOperation extends AbstractOperation {
|
||||
|
||||
writer.object();
|
||||
writer.key("op"); writer.value(OperationRegistry.s_opClassToName.get(this.getClass()));
|
||||
writer.key("description"); writer.value(
|
||||
_columnCount > 0 ?
|
||||
("Transpose cells in " + _columnCount +
|
||||
" column(s) starting with " + _startColumnName + " into rows") :
|
||||
("Transpose cells in columns starting with " +
|
||||
_startColumnName + " into rows"));
|
||||
writer.key("description"); writer.value(getBriefDescription());
|
||||
writer.key("startColumnName"); writer.value(_startColumnName);
|
||||
writer.key("columnCount"); writer.value(_columnCount);
|
||||
writer.key("ignoreBlankCells"); writer.value(_ignoreBlankCells);
|
||||
if (_combinedColumnName != null) {
|
||||
writer.key("combinedColumnName"); writer.value(_combinedColumnName);
|
||||
writer.key("prependColumnName"); writer.value(_prependColumnName);
|
||||
writer.key("separator"); writer.value(_separator);
|
||||
writer.key("ignoreBlankCells"); writer.value(_ignoreBlankCells);
|
||||
} else {
|
||||
writer.key("keyColumnName"); writer.value(_keyColumnName);
|
||||
writer.key("valueColumnName"); writer.value(_valueColumnName);
|
||||
}
|
||||
writer.endObject();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getBriefDescription(Project project) {
|
||||
return _columnCount > 0 ?
|
||||
("Transpose cells in " + _columnCount +
|
||||
" column(s) starting with " + _startColumnName + " into rows") :
|
||||
("Transpose cells in columns starting with " +
|
||||
_startColumnName + " into rows");
|
||||
return getBriefDescription();
|
||||
}
|
||||
|
||||
protected String getBriefDescription() {
|
||||
if (_combinedColumnName != null) {
|
||||
if (_columnCount > 0) {
|
||||
return "Transpose cells in " + _columnCount +
|
||||
" column(s) starting with " + _startColumnName +
|
||||
" into rows in one new column named " + _combinedColumnName;
|
||||
} else {
|
||||
return "Transpose cells in columns starting with " +
|
||||
_startColumnName +
|
||||
" into rows in one new column named " + _combinedColumnName;
|
||||
}
|
||||
} else {
|
||||
if (_columnCount > 0) {
|
||||
return "Transpose cells in " + _columnCount +
|
||||
" column(s) starting with " + _startColumnName +
|
||||
" into rows in two new columns named " +
|
||||
_keyColumnName + " and " + _valueColumnName;
|
||||
} else {
|
||||
return "Transpose cells in columns starting with " +
|
||||
_startColumnName +
|
||||
" into rows in two new columns named " +
|
||||
_keyColumnName + " and " + _valueColumnName;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected HistoryEntry createHistoryEntry(Project project, long historyEntryID) throws Exception {
|
||||
if (_combinedColumnName != null &&
|
||||
!_combinedColumnName.isEmpty() &&
|
||||
project.columnModel.getColumnByName(_combinedColumnName) != null) {
|
||||
if (_combinedColumnName != null) {
|
||||
if (project.columnModel.getColumnByName(_combinedColumnName) != null) {
|
||||
throw new Exception("Another column already named " + _combinedColumnName);
|
||||
}
|
||||
} else {
|
||||
if (project.columnModel.getColumnByName(_keyColumnName) != null) {
|
||||
throw new Exception("Another column already named " + _keyColumnName);
|
||||
}
|
||||
if (project.columnModel.getColumnByName(_valueColumnName) != null) {
|
||||
throw new Exception("Another column already named " + _valueColumnName);
|
||||
}
|
||||
}
|
||||
|
||||
List<Column> newColumns = new ArrayList<Column>();
|
||||
List<Column> oldColumns = project.columnModel.columns;
|
||||
@ -149,10 +217,12 @@ public class TransposeColumnsIntoRowsOperation extends AbstractOperation {
|
||||
|
||||
startColumnIndex = c;
|
||||
|
||||
String columnName = _combinedColumnName != null && _combinedColumnName.length() > 0 ? _combinedColumnName : column.getName();
|
||||
Column newColumn = new Column(newColumns.size(), columnName);
|
||||
|
||||
newColumns.add(newColumn);
|
||||
if (_combinedColumnName != null) {
|
||||
newColumns.add(new Column(newColumns.size(), _combinedColumnName));
|
||||
} else {
|
||||
newColumns.add(new Column(newColumns.size(), _keyColumnName));
|
||||
newColumns.add(new Column(newColumns.size(), _valueColumnName));
|
||||
}
|
||||
|
||||
columnsLeftToTranspose--;
|
||||
} else {
|
||||
@ -172,11 +242,12 @@ public class TransposeColumnsIntoRowsOperation extends AbstractOperation {
|
||||
|
||||
startColumnIndex = c;
|
||||
|
||||
String columnName = _combinedColumnName != null && _combinedColumnName.length() > 0 ?
|
||||
_combinedColumnName : column.getName();
|
||||
Column newColumn = new Column(newColumns.size(), columnName);
|
||||
|
||||
newColumns.add(newColumn);
|
||||
if (_combinedColumnName != null) {
|
||||
newColumns.add(new Column(newColumns.size(), _combinedColumnName));
|
||||
} else {
|
||||
newColumns.add(new Column(newColumns.size(), _keyColumnName));
|
||||
newColumns.add(new Column(newColumns.size(), _valueColumnName));
|
||||
}
|
||||
break;
|
||||
} else {
|
||||
// This column is before all columns to transpose
|
||||
@ -206,8 +277,8 @@ public class TransposeColumnsIntoRowsOperation extends AbstractOperation {
|
||||
if (c < startColumnIndex) {
|
||||
firstNewRow.setCell(c, cell);
|
||||
} else if (c == startColumnIndex || c < startColumnIndex + columnCount) {
|
||||
if (_combinedColumnName != null) {
|
||||
Cell newCell;
|
||||
|
||||
if (cell == null || cell.value == null) {
|
||||
if (_prependColumnName && !_ignoreBlankCells) {
|
||||
newCell = new Cell(column.getName() + _separator, null);
|
||||
@ -220,18 +291,38 @@ public class TransposeColumnsIntoRowsOperation extends AbstractOperation {
|
||||
newCell = cell;
|
||||
}
|
||||
|
||||
Row rowToModify;
|
||||
if (transposedCells == 0) {
|
||||
firstNewRow.setCell(startColumnIndex, newCell);
|
||||
rowToModify = firstNewRow;
|
||||
} else {
|
||||
Row newRow = new Row(newColumns.size());
|
||||
|
||||
newRow.setCell(startColumnIndex, newCell);
|
||||
newRows.add(newRow);
|
||||
rowToModify = new Row(newColumns.size());
|
||||
newRows.add(rowToModify);
|
||||
}
|
||||
rowToModify.setCell(startColumnIndex, newCell);
|
||||
|
||||
transposedCells++;
|
||||
} else {
|
||||
firstNewRow.setCell(c - columnCount + 1, cell);
|
||||
if (_ignoreBlankCells && (cell == null || cell.value == null)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
Row rowToModify;
|
||||
if (transposedCells == 0) {
|
||||
rowToModify = firstNewRow;
|
||||
} else {
|
||||
rowToModify = new Row(newColumns.size());
|
||||
newRows.add(rowToModify);
|
||||
}
|
||||
rowToModify.setCell(startColumnIndex, new Cell(column.getName(), null));
|
||||
rowToModify.setCell(startColumnIndex + 1, cell);
|
||||
|
||||
transposedCells++;
|
||||
}
|
||||
|
||||
} else {
|
||||
firstNewRow.setCell(
|
||||
c - columnCount + (_combinedColumnName != null ? 1 : 2),
|
||||
cell);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -239,7 +330,7 @@ public class TransposeColumnsIntoRowsOperation extends AbstractOperation {
|
||||
return new HistoryEntry(
|
||||
historyEntryID,
|
||||
project,
|
||||
getBriefDescription(null),
|
||||
getBriefDescription(),
|
||||
this,
|
||||
new MassRowColumnChange(newColumns, newRows)
|
||||
);
|
||||
|
@ -253,19 +253,42 @@ DataTableColumnHeaderUI.extendMenu(function(column, columnHeaderUI, menu) {
|
||||
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
|
||||
};
|
||||
|
||||
var mode = dialog.find('input[name="transpose-dialog-column-choices"]:checked')[0].value;
|
||||
if (mode == "2") {
|
||||
config.keyColumnName = $.trim(elmts.keyColumnNameInput[0].value);
|
||||
config.valueColumnName = $.trim(elmts.valueColumnNameInput[0].value);
|
||||
if (config.keyColumnName == "") {
|
||||
alert("Please specify the new key column's name.");
|
||||
return;
|
||||
} else if (config.valueColumnName == "") {
|
||||
alert("Please specify the new value column's name.");
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
config.combinedColumnName = $.trim(elmts.combinedColumnNameInput[0].value);
|
||||
config.prependColumnName = elmts.prependColumnNameCheckbox[0].checked;
|
||||
config.separator = elmts.separatorInput[0].value;
|
||||
if (config.combinedColumnName == "") {
|
||||
alert("Please specify the new column's name.");
|
||||
return;
|
||||
} else if (config.prependColumnName && config.separator == "") {
|
||||
alert("Please specify the separator between original column names and cell values.");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
Refine.postCoreProcess(
|
||||
"transpose-columns-into-rows",
|
||||
config,
|
||||
null,
|
||||
{ modelsChanged: true }
|
||||
{ modelsChanged: true },
|
||||
{
|
||||
onDone: dismiss
|
||||
}
|
||||
);
|
||||
dismiss();
|
||||
});
|
||||
|
||||
for (var i = 0; i < columns.length; i++) {
|
||||
|
@ -1,4 +1,4 @@
|
||||
<div class="dialog-frame" style="width: 600px;">
|
||||
<div class="dialog-frame" style="width: 700px;">
|
||||
<div class="dialog-border">
|
||||
<div class="dialog-header" bind="dialogHeader">Transpose Cells Across Columns into Rows</div>
|
||||
<div class="dialog-body" bind="dialogBody">
|
||||
@ -6,29 +6,53 @@
|
||||
<tr>
|
||||
<td>From Column</td>
|
||||
<td>To Column</td>
|
||||
<td>Formatting Options</td>
|
||||
<td>Transpose into</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-tight"><table>
|
||||
<tr>
|
||||
<td><input type="radio" id="$transpose-dialog-two-columns" name="transpose-dialog-column-choices" value="2" checked /></td>
|
||||
<td><label for="$transpose-dialog-two-columns">Two new columns</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td> </td>
|
||||
<td><div class="grid-layout layout-tightest"><table>
|
||||
<tr>
|
||||
<td colspan="2">Combined column name <input bind="combinedColumnNameInput" size="15" /></td>
|
||||
<td>Key column</td>
|
||||
<td><input bind="keyColumnNameInput" size="15"> (containing original columns' names)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan="2"><input type="checkbox" bind="prependColumnNameCheckbox" checked id="$transpose-dialog-prepend" />
|
||||
<label for="$transpose-dialog-prepend">prepend column name</label></td>
|
||||
<td>Value column</td>
|
||||
<td><input bind="valueColumnNameInput" size="15"> (containing original cells' values)</td>
|
||||
</tr>
|
||||
</table></div></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><input type="radio" id="$transpose-dialog-one-column" name="transpose-dialog-column-choices" value="1" /></td>
|
||||
<td><label for="$transpose-dialog-one-column">One column <input bind="combinedColumnNameInput" size="15" /></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td> </td>
|
||||
<td>Separate column name and cell value with
|
||||
<input bind="separatorInput" size="5" value=":" />
|
||||
<td><div class="grid-layout layout-tightest"><table>
|
||||
<tr>
|
||||
<td><input type="checkbox" bind="prependColumnNameCheckbox" id="$transpose-dialog-prepend" /></td>
|
||||
<td><label for="$transpose-dialog-prepend">prepend the original column's name to each cell</label></td>
|
||||
</tr>
|
||||
</tr>
|
||||
<tr>
|
||||
<td> </td>
|
||||
<td>followed by
|
||||
<input bind="separatorInput" size="2" value=":" />
|
||||
before the cell's value
|
||||
</td>
|
||||
</tr>
|
||||
</table></div></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td> </td>
|
||||
<td><input type="checkbox" bind="ignoreBlankCellsCheckbox" checked id="$transpose-dialog-ignore" />
|
||||
<label for="$transpose-dialog-ignore">ignore blank cells</label></td>
|
||||
<td><input type="checkbox" bind="ignoreBlankCellsCheckbox" checked id="$transpose-dialog-ignore" /></td>
|
||||
<td><label for="$transpose-dialog-ignore">Ignore blank cells</label></td>
|
||||
</tr>
|
||||
</table></div></td>
|
||||
</tr>
|
||||
|
Loading…
Reference in New Issue
Block a user