blob: 0a06383c5df3586e6b82e97f57e7fdee917bf901 [file] [log] [blame]
/*******************************************************************************
* Copyright (C) 2007 The University of Manchester
*
* Modifications to the initial code base are copyright of their
* respective authors, or their employers as appropriate.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
******************************************************************************/
package net.sf.taverna.t2.workbench.views.results.saveactions;
import static java.lang.Math.max;
import static java.util.Arrays.asList;
import static net.sf.taverna.t2.baclava.factory.DataThingFactory.bake;
import static net.sf.taverna.t2.workbench.icons.WorkbenchIcons.saveIcon;
import static org.apache.poi.ss.usermodel.CellStyle.BORDER_NONE;
import static org.apache.poi.ss.usermodel.CellStyle.BORDER_THIN;
import static org.apache.poi.ss.usermodel.CellStyle.SOLID_FOREGROUND;
import java.beans.IntrospectionException;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Collection;
import javax.swing.AbstractAction;
import net.sf.taverna.t2.baclava.DataThing;
import net.sf.taverna.t2.baclava.iterator.BaclavaIterator;
import org.apache.poi.hssf.usermodel.HSSFCell;
import org.apache.poi.hssf.usermodel.HSSFCellStyle;
import org.apache.poi.hssf.usermodel.HSSFRow;
import org.apache.poi.hssf.usermodel.HSSFSheet;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.hssf.util.HSSFColor;
/**
* Stores the entire map of result objects to disk as a single XML data document.
*
* @author Tom Oinn
*/
public class SaveAllResultsAsExcel extends SaveAllResultsSPI {
private static final long serialVersionUID = -2759817859804112070L;
HSSFWorkbook wb = null;
HSSFSheet sheet = null;
HSSFCellStyle headingStyle = null;
HSSFCellStyle[] styles = null;
public SaveAllResultsAsExcel() {
super();
putValue(NAME, "Save as Excel");
putValue(SMALL_ICON, saveIcon);
}
@Override
public AbstractAction getAction() {
return new SaveAllResultsAsExcel();
}
@Override
protected void saveData(File f) throws IOException {
try {
generateSheet();
} catch (IntrospectionException e) {
throw new IOException("failed to generate excel sheet model", e);
}
saveSheet(f);
}
/**
* Generate the Excel sheet from the DataThing's in the map. All of the
* results are shown in the same spreadsheet, but in different columns. Flat
* lists are shown vertically, 2d lists as a matrix, and deeper lists are
* flattened to 2d.
*
* @throws IntrospectionException
*/
void generateSheet() throws IntrospectionException {
wb = new HSSFWorkbook();
setStyles();
sheet = wb.createSheet("Workflow results");
sheet.setDisplayGridlines(false);
int currentCol = 0;
for (String portName : chosenReferences.keySet()) {
logger.debug("Output for : " + portName);
DataThing resultValue = bake(getObjectForName(portName));
// Check whether there's a textual type
Boolean textualType = isTextual(resultValue.getDataObject());
if (textualType == null || !textualType)
continue;
logger.debug("Output is textual");
getCell(currentCol, 0).setCellValue(portName);
getCell(currentCol, 0).setCellStyle(headingStyle);
int numCols = 1;
int numRows = 1;
int currentRow = 0;
BaclavaIterator rows;
try {
rows = resultValue.iterator("l('')");
} catch (IntrospectionException ex) {
// Not a list, single value. We'll fake the iterator
DataThing fakeValues = new DataThing(
asList(resultValue.getDataObject()));
rows = fakeValues.iterator("l('')");
}
/*
* If we only have one row, we'll show each value on a new row
* instead
*/
boolean isFlat = rows.size() == 1;
while (rows.hasNext()) {
DataThing row = (DataThing) rows.next();
/*
* Even increase first time, as we don't want to overwrite our
* header
*/
currentRow++;
BaclavaIterator bi = row.iterator("''");
while (bi.hasNext()) {
DataThing containedThing = (DataThing) bi.next();
String containedValue = (String) containedThing.getDataObject();
int columnOffset = 0;
int[] location = bi.getCurrentLocation();
if (!isFlat && location.length > 0) {
columnOffset = location[location.length - 1];
numCols = Math.max(numCols, columnOffset + 1);
}
logger.debug("Storing in cell " + (currentCol + columnOffset) + " "
+ currentRow + ": " + containedValue);
getCell(currentCol + columnOffset, currentRow).setCellValue(containedValue);
if (isFlat)
currentRow++;
}
}
numRows = max(numRows, currentRow);
// Set the styles
for (int x = currentCol; x < currentCol + numCols; x++)
for (int y = 1; y < numRows + 1; y++)
setStyle(currentCol, x, y);
sheet.setColumnWidth(currentCol + numCols, 200);
currentCol += numCols + 1;
}
}
void setStyle(int currentCol, int column, int row) {
if (!hasValue(column, row))
return;
HSSFCell cell = getCell(column, row);
int n = 0, s = 0, w = 0, e = 0;
if (row < 2 || !hasValue(column, row - 1))
n = 1;
if (column == currentCol || !hasValue(column - 1, row))
w = 1;
if (!hasValue(column, row + 1))
s = 1;
if (!hasValue(column + 1, row))
e = 1;
int index = n + 2 * s + 4 * e + 8 * w;
cell.setCellStyle(styles[index]);
}
void setStyles() {
headingStyle = wb.createCellStyle();
headingStyle.setBorderTop(BORDER_THIN);
headingStyle.setBorderBottom(BORDER_THIN);
headingStyle.setBorderLeft(BORDER_THIN);
headingStyle.setBorderRight(BORDER_THIN);
headingStyle.setFillBackgroundColor(HSSFColor.LIGHT_YELLOW.index);
headingStyle.setFillForegroundColor(HSSFColor.LIGHT_YELLOW.index);
headingStyle.setFillPattern(SOLID_FOREGROUND);
styles = new HSSFCellStyle[16];
for (int n = 0; n < 2; n++)
for (int s = 0; s < 2; s++)
for (int e = 0; e < 2; e++)
for (int w = 0; w < 2; w++) {
int index = n + 2 * s + 4 * e + 8 * w;
styles[index] = wb.createCellStyle();
styles[index].setBorderTop(n == 1 ? BORDER_THIN
: BORDER_NONE);
styles[index].setBorderBottom(s == 1 ? BORDER_THIN
: BORDER_NONE);
styles[index].setBorderRight(e == 1 ? BORDER_THIN
: BORDER_NONE);
styles[index].setBorderLeft(w == 1 ? BORDER_THIN
: BORDER_NONE);
styles[index].setFillBackgroundColor(HSSFColor.GOLD.index);
styles[index].setFillForegroundColor(HSSFColor.GOLD.index);
styles[index].setFillPattern(SOLID_FOREGROUND);
}
}
/**
* Check if o is a String or contains elements that satisfy isTextual(o)
* <p>
* Traverse down the Collection o if possible, and check the tree of collection at the deepest
* level.
* </p>
*
* @param o
* Object to check
* @return true if o is a String or is a Collection that contains a string at the deepest level.
* false if o is not a String or Collection, or if it is a collection that contains
* non-strings.
* null if o is a Collection, but it is empty or contains nothing but Collections.
*/
Boolean isTextual(Object o) {
if (o instanceof String)
// We dug down and found a string. Hurray!
return true;
if (o instanceof Collection) {
for (Object child : (Collection<?>) o) {
Boolean isTxt = isTextual(child);
if (isTxt == null)
// Unknown, try next one
continue;
return isTxt;
}
/*
* We looped through and found just empty collections (or we are an
* empty collection), we don't know.
*/
return null;
}
// No, sorry mate.. o was neither a String or Collection
return false;
}
/**
* Get a cell at the given coordinates, create it if needed.
*
* @param column
* @param row
* @return
*/
HSSFCell getCell(int column, int row) {
HSSFRow srow = sheet.getRow(row);
if (srow == null)
srow = sheet.createRow(row);
HSSFCell scell = srow.getCell(column);
if (scell == null)
scell = srow.createCell(column);
return scell;
}
/**
* Check if a cell has a value.
*
* @param column
* @param row
* @return
*/
boolean hasValue(int column, int row) {
HSSFRow srow = sheet.getRow(row);
if (srow == null)
return false;
HSSFCell scell = srow.getCell(column);
if (scell == null)
return false;
return true;
}
/**
* Save the generated worksheet to a file
*
* @param file
* to save to
* @throws FileNotFoundException
* @throws IOException
*/
void saveSheet(File file) throws IOException {
FileOutputStream fos = new FileOutputStream(file);
wb.write(fos);
fos.close();
}
@Override
protected String getFilter() {
return "xls";
}
}