<changes>
<release version="3.8-beta3" date="2011-??-??">
- <action dev="poi-developers" type="add">51171 - Improved performance of opening large .xls files</action>
+ <action dev="poi-developers" type="add">51160 - Initial version of SXSSF, a low memory foortprint API to produce xlsx files</action>
+ <action dev="poi-developers" type="fix">51171 - Improved performance of opening large .xls files</action>
<action dev="poi-developers" type="add">51172 - Add XWPF support for GIF pictures</action>
<action dev="poi-developers" type="add">NPOIFS Mini Streams now support extending the underlying big block stream to fit more data</action>
<action dev="poi-developers" type="fix">51148 - XWPFDocument now properly tracks paragraphs and tables when adding/removing them</action>
--- /dev/null
+/*
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ====================================================================
+ */
+package org.apache.poi.ss.examples;
+
+import org.apache.poi.ss.usermodel.*;
+import org.apache.poi.hssf.usermodel.HSSFWorkbook;
+import org.apache.poi.ss.util.CellRangeAddress;
+import org.apache.poi.ss.util.CellReference;
+import org.apache.poi.xssf.usermodel.XSSFWorkbook;
+import org.apache.poi.xssf.streaming.SXSSFWorkbook;
+
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.util.Calendar;
+import java.util.HashMap;
+import java.util.Map;
+
+public class SSPerformanceTest {
+ public static void main(String[] args) {
+ if (args.length != 4) usage("need four command arguments");
+
+ String type = args[0];
+ long timeStarted = System.currentTimeMillis();
+ Workbook workBook = createWorkbook(type);
+ boolean isHType = workBook instanceof HSSFWorkbook;
+
+ int rows = parseInt(args[1], "Failed to parse rows value as integer");
+ int cols = parseInt(args[2], "Failed to parse cols value as integer");
+ boolean saveFile = parseInt(args[3], "Failed to parse saveFile value as integer") != 0;
+
+ Map<String, CellStyle> styles = createStyles(workBook);
+
+ Sheet sheet = workBook.createSheet("Main Sheet");
+
+ Cell headerCell = sheet.createRow(0).createCell(0);
+ headerCell.setCellValue("Header text is spanned across multiple cells");
+ headerCell.setCellStyle(styles.get("header"));
+ sheet.addMergedRegion(CellRangeAddress.valueOf("$A$1:$F$1"));
+
+ int sheetNo = 0;
+ int rowIndexInSheet = 1;
+ double value = 0;
+ Calendar calendar = Calendar.getInstance();
+ for (int rowIndex = 0; rowIndex < rows; rowIndex++) {
+ if (isHType && sheetNo != rowIndex / 0x10000) {
+ sheet = workBook.createSheet("Spillover from sheet " + (++sheetNo));
+ headerCell.setCellValue("Header text is spanned across multiple cells");
+ headerCell.setCellStyle(styles.get("header"));
+ sheet.addMergedRegion(CellRangeAddress.valueOf("$A$1:$F$1"));
+ rowIndexInSheet = 1;
+ }
+
+ Row row = sheet.createRow(rowIndexInSheet);
+ for (int colIndex = 0; colIndex < cols; colIndex++) {
+ Cell cell = row.createCell(colIndex);
+ String address = new CellReference(cell).formatAsString();
+ switch (colIndex){
+ case 0:
+ // column A: default number format
+ cell.setCellValue(value++);
+ break;
+ case 1:
+ // column B: #,##0
+ cell.setCellValue(value++);
+ cell.setCellStyle(styles.get("#,##0.00"));
+ break;
+ case 2:
+ // column C: $#,##0.00
+ cell.setCellValue(value++);
+ cell.setCellStyle(styles.get("$#,##0.00"));
+ break;
+ case 3:
+ // column D: red bold text on yellow background
+ cell.setCellValue(address);
+ cell.setCellStyle(styles.get("red-bold"));
+ break;
+ case 4:
+ // column E: boolean
+ // TODO booleans are shown as 1/0 instead of TRUE/FALSE
+ cell.setCellValue(rowIndex % 2 == 0);
+ break;
+ case 5:
+ // column F: date / time
+ cell.setCellValue(calendar);
+ cell.setCellStyle(styles.get("m/d/yyyy"));
+ calendar.roll(Calendar.DAY_OF_YEAR, -1);
+ break;
+ case 6:
+ // column F: formula
+ // TODO formulas are not yet supported in SXSSF
+ //cell.setCellFormula("SUM(A" + (rowIndex+1) + ":E" + (rowIndex+1)+ ")");
+ //break;
+ default:
+ cell.setCellValue(value++);
+ break;
+ }
+ }
+ rowIndexInSheet++;
+ }
+ if (saveFile) {
+ String fileName = type + "_" + rows + "_" + cols + "." + getFileSuffix(args[0]);
+ try {
+ FileOutputStream out = new FileOutputStream(fileName);
+ workBook.write(out);
+ out.close();
+ } catch (IOException ioe) {
+ System.err.println("Error: failed to write to file \"" + fileName + "\", reason=" + ioe.getMessage());
+ }
+ }
+ long timeFinished = System.currentTimeMillis();
+ System.out.println("Elapsed " + (timeFinished-timeStarted)/1000 + " seconds");
+ }
+
+ static Map<String, CellStyle> createStyles(Workbook wb) {
+ Map<String, CellStyle> styles = new HashMap<String, CellStyle>();
+ CellStyle style;
+
+ Font headerFont = wb.createFont();
+ headerFont.setFontHeightInPoints((short) 14);
+ headerFont.setBoldweight(Font.BOLDWEIGHT_BOLD);
+ style = wb.createCellStyle();
+ style.setAlignment(CellStyle.ALIGN_CENTER);
+ style.setVerticalAlignment(CellStyle.VERTICAL_CENTER);
+ style.setFont(headerFont);
+ style.setFillForegroundColor(IndexedColors.LIGHT_CORNFLOWER_BLUE.getIndex());
+ style.setFillPattern(CellStyle.SOLID_FOREGROUND);
+ styles.put("header", style);
+
+ Font monthFont = wb.createFont();
+ monthFont.setFontHeightInPoints((short)12);
+ monthFont.setColor(IndexedColors.RED.getIndex());
+ monthFont.setBoldweight(Font.BOLDWEIGHT_BOLD);
+ style = wb.createCellStyle();
+ style.setAlignment(CellStyle.ALIGN_CENTER);
+ style.setVerticalAlignment(CellStyle.VERTICAL_CENTER);
+ style.setFillForegroundColor(IndexedColors.YELLOW.getIndex());
+ style.setFillPattern(CellStyle.SOLID_FOREGROUND);
+ style.setFont(monthFont);
+ styles.put("red-bold", style);
+
+ String[] nfmt = {"#,##0.00", "$#,##0.00", "m/d/yyyy"};
+ for(String fmt : nfmt){
+ style = wb.createCellStyle();
+ style.setDataFormat(wb.createDataFormat().getFormat(fmt));
+ styles.put(fmt, style);
+ }
+
+ return styles;
+ }
+
+
+ static void usage(String message) {
+ System.err.println(message);
+ System.err.println("usage: java SSPerformanceTest HSSF|XSSF|SXSSF rows cols saveFile (0|1)? ");
+ System.exit(1);
+ }
+
+ static Workbook createWorkbook(String type) {
+ if ("HSSF".equals(type))
+ return new HSSFWorkbook();
+ else if ("XSSF".equals(type))
+ return new XSSFWorkbook();
+ else if ("SXSSF".equals(type))
+ return new SXSSFWorkbook();
+ else
+ usage("Unknown type \"" + type + "\"");
+ return null;
+ }
+
+ static String getFileSuffix(String type) {
+ if ("HSSF".equals(type))
+ return "xls";
+ else if ("XSSF".equals(type))
+ return "xlsx";
+ else if ("SXSSF".equals(type))
+ return "xlsx";
+ return null;
+ }
+
+ static int parseInt(String value, String msg) {
+ try {
+ return Integer.parseInt(value);
+ } catch (NumberFormatException e) {
+ usage(msg);
+ }
+ return 0;
+ }
+}
--- /dev/null
+/* ====================================================================
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+==================================================================== */
+
+package org.apache.poi.xssf.streaming;
+
+import java.util.Calendar;
+import java.util.Date;
+
+import org.apache.poi.ss.usermodel.Cell;
+import org.apache.poi.ss.usermodel.CellStyle;
+import org.apache.poi.ss.usermodel.Sheet;
+import org.apache.poi.ss.usermodel.Row;
+import org.apache.poi.ss.usermodel.RichTextString;
+import org.apache.poi.ss.usermodel.Comment;
+import org.apache.poi.ss.usermodel.Hyperlink;
+import org.apache.poi.ss.usermodel.DateUtil;
+import org.apache.poi.ss.formula.FormulaParseException;
+import org.apache.poi.ss.util.CellRangeAddress;
+
+/**
+ * Streaming version of XSSFRow implementing the "BigGridDemo" strategy.
+ *
+ * @author Alex Geller, Four J's Development Tools
+*/
+public class SXSSFCell implements Cell
+{
+
+ SXSSFRow _row;
+ Value _value;
+ CellStyle _style;
+ Property _firstProperty;
+
+ public SXSSFCell(SXSSFRow row,int cellType)
+ {
+ _row=row;
+ setType(cellType);
+ }
+
+//start of interface implementation
+
+ /**
+ * Returns column index of this cell
+ *
+ * @return zero-based column index of a column in a sheet.
+ */
+ public int getColumnIndex()
+ {
+ return _row.getCellIndex(this);
+ }
+
+ /**
+ * Returns row index of a row in the sheet that contains this cell
+ *
+ * @return zero-based row index of a row in the sheet that contains this cell
+ */
+ public int getRowIndex()
+ {
+ return _row.getRowNum();
+ }
+
+ /**
+ * Returns the sheet this cell belongs to
+ *
+ * @return the sheet this cell belongs to
+ */
+ public Sheet getSheet()
+ {
+ return _row.getSheet();
+ }
+
+ /**
+ * Returns the Row this cell belongs to
+ *
+ * @return the Row that owns this cell
+ */
+ public Row getRow()
+ {
+ return _row;
+ }
+
+ /**
+ * Set the cells type (numeric, formula or string)
+ *
+ * @throws IllegalArgumentException if the specified cell type is invalid
+ * @see #CELL_TYPE_NUMERIC
+ * @see #CELL_TYPE_STRING
+ * @see #CELL_TYPE_FORMULA
+ * @see #CELL_TYPE_BLANK
+ * @see #CELL_TYPE_BOOLEAN
+ * @see #CELL_TYPE_ERROR
+ */
+ public void setCellType(int cellType)
+ {
+ ensureType(cellType);
+ }
+
+ /**
+ * Return the cell type.
+ *
+ * @return the cell type
+ * @see Cell#CELL_TYPE_BLANK
+ * @see Cell#CELL_TYPE_NUMERIC
+ * @see Cell#CELL_TYPE_STRING
+ * @see Cell#CELL_TYPE_FORMULA
+ * @see Cell#CELL_TYPE_BOOLEAN
+ * @see Cell#CELL_TYPE_ERROR
+ */
+ public int getCellType()
+ {
+ return _value.getType();
+ }
+
+ /**
+ * Only valid for formula cells
+ * @return one of ({@link #CELL_TYPE_NUMERIC}, {@link #CELL_TYPE_STRING},
+ * {@link #CELL_TYPE_BOOLEAN}, {@link #CELL_TYPE_ERROR}) depending
+ * on the cached value of the formula
+ */
+ public int getCachedFormulaResultType()
+ {
+//TODO: Implement this correctly
+ assert false;
+ return CELL_TYPE_NUMERIC;
+ }
+
+ /**
+ * Set a numeric value for the cell
+ *
+ * @param value the numeric value to set this cell to. For formulas we'll set the
+ * precalculated value, for numerics we'll set its value. For other types we
+ * will change the cell to a numeric cell and set its value.
+ */
+ public void setCellValue(double value)
+ {
+ ensureTypeOrFormulaType(CELL_TYPE_NUMERIC);
+ if(_value.getType()==CELL_TYPE_FORMULA)
+ ((NumericFormulaValue)_value).setPreEvaluatedValue(value);
+ else
+ ((NumericValue)_value).setValue(value);
+ }
+
+ /**
+ * Converts the supplied date to its equivalent Excel numeric value and sets
+ * that into the cell.
+ * <p/>
+ * <b>Note</b> - There is actually no 'DATE' cell type in Excel. In many
+ * cases (when entering date values), Excel automatically adjusts the
+ * <i>cell style</i> to some date format, creating the illusion that the cell
+ * data type is now something besides {@link Cell#CELL_TYPE_NUMERIC}. POI
+ * does not attempt to replicate this behaviour. To make a numeric cell
+ * display as a date, use {@link #setCellStyle(CellStyle)} etc.
+ *
+ * @param value the numeric value to set this cell to. For formulas we'll set the
+ * precalculated value, for numerics we'll set its value. For other types we
+ * will change the cell to a numerics cell and set its value.
+ */
+ public void setCellValue(Date value)
+ {
+//TODO: activate this when compiling against 3.7.
+ //boolean date1904 = getSheet().getXSSFWorkbook().isDate1904();
+ boolean date1904 = false;
+ setCellValue(DateUtil.getExcelDate(value, date1904));
+ }
+
+ /**
+ * Set a date value for the cell. Excel treats dates as numeric so you will need to format the cell as
+ * a date.
+ * <p>
+ * This will set the cell value based on the Calendar's timezone. As Excel
+ * does not support timezones this means that both 20:00+03:00 and
+ * 20:00-03:00 will be reported as the same value (20:00) even that there
+ * are 6 hours difference between the two times. This difference can be
+ * preserved by using <code>setCellValue(value.getTime())</code> which will
+ * automatically shift the times to the default timezone.
+ * </p>
+ *
+ * @param value the date value to set this cell to. For formulas we'll set the
+ * precalculated value, for numerics we'll set its value. For othertypes we
+ * will change the cell to a numeric cell and set its value.
+ */
+ public void setCellValue(Calendar value)
+ {
+//TODO: activate this when compiling against 3.7.
+ //boolean date1904 = getSheet().getXSSFWorkbook().isDate1904();
+ boolean date1904 = false;
+ setCellValue( DateUtil.getExcelDate(value, date1904 ));
+ }
+
+ /**
+ * Set a rich string value for the cell.
+ *
+ * @param value value to set the cell to. For formulas we'll set the formula
+ * string, for String cells we'll set its value. For other types we will
+ * change the cell to a string cell and set its value.
+ * If value is null then we will change the cell to a Blank cell.
+ */
+ public void setCellValue(RichTextString value)
+ {
+ ensureRichTextStringType();
+ ((RichTextValue)_value).setValue(value);
+ }
+
+ /**
+ * Set a string value for the cell.
+ *
+ * @param value value to set the cell to. For formulas we'll set the formula
+ * string, for String cells we'll set its value. For other types we will
+ * change the cell to a string cell and set its value.
+ * If value is null then we will change the cell to a Blank cell.
+ */
+ public void setCellValue(String value)
+ {
+ ensureTypeOrFormulaType(CELL_TYPE_STRING);
+ if(_value.getType()==CELL_TYPE_FORMULA)
+ ((StringFormulaValue)_value).setPreEvaluatedValue(value);
+ else
+ ((PlainStringValue)_value).setValue(value);
+ }
+
+ /**
+ * Sets formula for this cell.
+ * <p>
+ * Note, this method only sets the formula string and does not calculate the formula value.
+ * To set the precalculated value use {@link #setCellValue(double)} or {@link #setCellValue(String)}
+ * </p>
+ *
+ * @param formula the formula to set, e.g. <code>"SUM(C4:E4)"</code>.
+ * If the argument is <code>null</code> then the current formula is removed.
+ * @throws FormulaParseException if the formula has incorrect syntax or is otherwise invalid
+ */
+ public void setCellFormula(String formula) throws FormulaParseException
+ {
+ ensureFormulaType(computeTypeFromFormula(formula));
+ ((FormulaValue)_value).setValue(formula);
+ }
+ /**
+ * Return a formula for the cell, for example, <code>SUM(C4:E4)</code>
+ *
+ * @return a formula for the cell
+ * @throws IllegalStateException if the cell type returned by {@link #getCellType()} is not CELL_TYPE_FORMULA
+ */
+ public String getCellFormula()
+ {
+ if(_value.getType()!=CELL_TYPE_FORMULA)
+ throw typeMismatch(CELL_TYPE_FORMULA,_value.getType(),false);
+ return ((FormulaValue)_value).getValue();
+ }
+
+ /**
+ * Get the value of the cell as a number.
+ * <p>
+ * For strings we throw an exception. For blank cells we return a 0.
+ * For formulas or error cells we return the precalculated value;
+ * </p>
+ * @return the value of the cell as a number
+ * @throws IllegalStateException if the cell type returned by {@link #getCellType()} is CELL_TYPE_STRING
+ * @exception NumberFormatException if the cell value isn't a parsable <code>double</code>.
+ * @see org.apache.poi.ss.usermodel.DataFormatter for turning this number into a string similar to that which Excel would render this number as.
+ */
+ public double getNumericCellValue()
+ {
+ int cellType = getCellType();
+ switch(cellType)
+ {
+ case CELL_TYPE_BLANK:
+ return 0.0;
+ case CELL_TYPE_FORMULA:
+ {
+ FormulaValue fv=(FormulaValue)_value;
+ if(fv.getFormulaType()!=CELL_TYPE_NUMERIC)
+ throw typeMismatch(CELL_TYPE_NUMERIC, CELL_TYPE_FORMULA, false);
+ return ((NumericFormulaValue)_value).getPreEvaluatedValue();
+ }
+ case CELL_TYPE_NUMERIC:
+ return ((NumericValue)_value).getValue();
+ default:
+ throw typeMismatch(CELL_TYPE_NUMERIC, cellType, false);
+ }
+ }
+
+ /**
+ * Get the value of the cell as a date.
+ * <p>
+ * For strings we throw an exception. For blank cells we return a null.
+ * </p>
+ * @return the value of the cell as a date
+ * @throws IllegalStateException if the cell type returned by {@link #getCellType()} is CELL_TYPE_STRING
+ * @exception NumberFormatException if the cell value isn't a parsable <code>double</code>.
+ * @see org.apache.poi.ss.usermodel.DataFormatter for formatting this date into a string similar to how excel does.
+ */
+ public Date getDateCellValue()
+ {
+ int cellType = getCellType();
+ if (cellType == CELL_TYPE_BLANK)
+ {
+ return null;
+ }
+
+ double value = getNumericCellValue();
+//TODO: activate this when compiling against 3.7.
+ //boolean date1904 = getSheet().getXSSFWorkbook().isDate1904();
+ boolean date1904 = false;
+ return DateUtil.getJavaDate(value, date1904);
+ }
+
+ /**
+ * Get the value of the cell as a XSSFRichTextString
+ * <p>
+ * For numeric cells we throw an exception. For blank cells we return an empty string.
+ * For formula cells we return the pre-calculated value if a string, otherwise an exception.
+ * </p>
+ * @return the value of the cell as a XSSFRichTextString
+ */
+ public RichTextString getRichStringCellValue()
+ {
+ int cellType = getCellType();
+ if(!(getCellType()==CELL_TYPE_STRING&&((StringValue)_value).isRichText()))
+ throw typeMismatch(CELL_TYPE_STRING, cellType, false);
+ return ((RichTextValue)_value).getValue();
+ }
+
+
+ /**
+ * Get the value of the cell as a string
+ * <p>
+ * For numeric cells we throw an exception. For blank cells we return an empty string.
+ * For formulaCells that are not string Formulas, we throw an exception.
+ * </p>
+ * @return the value of the cell as a string
+ */
+ public String getStringCellValue()
+ {
+ int cellType = getCellType();
+ switch(cellType)
+ {
+ case CELL_TYPE_BLANK:
+ return "";
+ case CELL_TYPE_FORMULA:
+ {
+ FormulaValue fv=(FormulaValue)_value;
+ if(fv.getFormulaType()!=CELL_TYPE_STRING)
+ throw typeMismatch(CELL_TYPE_STRING, CELL_TYPE_FORMULA, false);
+ return ((StringFormulaValue)_value).getPreEvaluatedValue();
+ }
+ case CELL_TYPE_STRING:
+ {
+ if(((StringValue)_value).isRichText())
+ return ((RichTextValue)_value).getValue().getString();
+ else
+ return ((PlainStringValue)_value).getValue();
+ }
+ default:
+ throw typeMismatch(CELL_TYPE_STRING, cellType, false);
+ }
+ }
+
+ /**
+ * Set a boolean value for the cell
+ *
+ * @param value the boolean value to set this cell to. For formulas we'll set the
+ * precalculated value, for booleans we'll set its value. For other types we
+ * will change the cell to a boolean cell and set its value.
+ */
+ public void setCellValue(boolean value)
+ {
+ ensureTypeOrFormulaType(CELL_TYPE_BOOLEAN);
+ if(_value.getType()==CELL_TYPE_FORMULA)
+ ((BooleanFormulaValue)_value).setPreEvaluatedValue(value);
+ else
+ ((BooleanValue)_value).setValue(value);
+ }
+
+ /**
+ * Set a error value for the cell
+ *
+ * @param value the error value to set this cell to. For formulas we'll set the
+ * precalculated value , for errors we'll set
+ * its value. For other types we will change the cell to an error
+ * cell and set its value.
+ * @see org.apache.poi.ss.usermodel.FormulaError
+ */
+ public void setCellErrorValue(byte value)
+ {
+ ensureType(CELL_TYPE_ERROR);
+ if(_value.getType()==CELL_TYPE_FORMULA)
+ ((ErrorFormulaValue)_value).setPreEvaluatedValue(value);
+ else
+ ((ErrorValue)_value).setValue(value);
+ }
+
+ /**
+ * Get the value of the cell as a boolean.
+ * <p>
+ * For strings, numbers, and errors, we throw an exception. For blank cells we return a false.
+ * </p>
+ * @return the value of the cell as a boolean
+ * @throws IllegalStateException if the cell type returned by {@link #getCellType()}
+ * is not CELL_TYPE_BOOLEAN, CELL_TYPE_BLANK or CELL_TYPE_FORMULA
+ */
+ public boolean getBooleanCellValue()
+ {
+ int cellType = getCellType();
+ switch(cellType)
+ {
+ case CELL_TYPE_BLANK:
+ return false;
+ case CELL_TYPE_FORMULA:
+ {
+ FormulaValue fv=(FormulaValue)_value;
+ if(fv.getFormulaType()!=CELL_TYPE_BOOLEAN)
+ throw typeMismatch(CELL_TYPE_BOOLEAN, CELL_TYPE_FORMULA, false);
+ return ((BooleanFormulaValue)_value).getPreEvaluatedValue();
+ }
+ case CELL_TYPE_BOOLEAN:
+ {
+ return ((BooleanValue)_value).getValue();
+ }
+ default:
+ throw typeMismatch(CELL_TYPE_BOOLEAN, cellType, false);
+ }
+ }
+
+ /**
+ * Get the value of the cell as an error code.
+ * <p>
+ * For strings, numbers, and booleans, we throw an exception.
+ * For blank cells we return a 0.
+ * </p>
+ *
+ * @return the value of the cell as an error code
+ * @throws IllegalStateException if the cell type returned by {@link #getCellType()} isn't CELL_TYPE_ERROR
+ * @see org.apache.poi.ss.usermodel.FormulaError for error codes
+ */
+ public byte getErrorCellValue()
+ {
+ int cellType = getCellType();
+ switch(cellType)
+ {
+ case CELL_TYPE_BLANK:
+ return 0;
+ case CELL_TYPE_FORMULA:
+ {
+ FormulaValue fv=(FormulaValue)_value;
+ if(fv.getFormulaType()!=CELL_TYPE_ERROR)
+ throw typeMismatch(CELL_TYPE_ERROR, CELL_TYPE_FORMULA, false);
+ return ((ErrorFormulaValue)_value).getPreEvaluatedValue();
+ }
+ case CELL_TYPE_ERROR:
+ {
+ return ((ErrorValue)_value).getValue();
+ }
+ default:
+ throw typeMismatch(CELL_TYPE_ERROR, cellType, false);
+ }
+ }
+
+ /**
+ * Set the style for the cell. The style should be an CellStyle created/retreived from
+ * the Workbook.
+ *
+ * @param style reference contained in the workbook.
+ * If the value is null then the style information is removed causing the cell to used the default workbook style.
+ * @see org.apache.poi.ss.usermodel.Workbook#createCellStyle()
+ */
+ public void setCellStyle(CellStyle style)
+ {
+ _style=style;
+ }
+
+ /**
+ * Return the cell's style.
+ *
+ * @return the cell's style. Always not-null. Default cell style has zero index and can be obtained as
+ * <code>workbook.getCellStyleAt(0)</code>
+ * @see org.apache.poi.ss.usermodel.Workbook#getCellStyleAt(short)
+ */
+ public CellStyle getCellStyle()
+ {
+ return _style;
+ }
+
+ /**
+ * Sets this cell as the active cell for the worksheet
+ */
+ public void setAsActiveCell()
+ {
+//TODO: What needs to be done here? Is there a "the active cell" at the sheet or even the workbook level?
+ //getRow().setAsActiveCell(this);
+ }
+
+ /**
+ * Assign a comment to this cell
+ *
+ * @param comment comment associated with this cell
+ */
+ public void setCellComment(Comment comment)
+ {
+ setProperty(Property.COMMENT,comment);
+ }
+
+ /**
+ * Returns comment associated with this cell
+ *
+ * @return comment associated with this cell or <code>null</code> if not found
+ */
+ public Comment getCellComment()
+ {
+ return (Comment)getPropertyValue(Property.COMMENT);
+ }
+
+ /**
+ * Removes the comment for this cell, if there is one.
+ */
+ public void removeCellComment()
+ {
+ removeProperty(Property.COMMENT);
+ }
+
+ /**
+ * @return hyperlink associated with this cell or <code>null</code> if not found
+ */
+ public Hyperlink getHyperlink()
+ {
+ return (Hyperlink)getPropertyValue(Property.HYPERLINK);
+ }
+
+ /**
+ * Assign a hyperlink to this cell
+ *
+ * @param link hyperlink associated with this cell
+ */
+ public void setHyperlink(Hyperlink link)
+ {
+ setProperty(Property.HYPERLINK,link);
+ }
+
+ /**
+ * Only valid for array formula cells
+ *
+ * @return range of the array formula group that the cell belongs to.
+ */
+//TODO: What is this?
+ public CellRangeAddress getArrayFormulaRange()
+ {
+ return null;
+ }
+
+ /**
+ * @return <code>true</code> if this cell is part of group of cells having a common array formula.
+ */
+//TODO: What is this?
+ public boolean isPartOfArrayFormulaGroup()
+ {
+ return false;
+ }
+//end of interface implementation
+
+ void removeProperty(int type)
+ {
+ Property current=_firstProperty;
+ Property previous=null;
+ while(current!=null&¤t.getType()!=type)
+ {
+ previous=current;
+ current=current._next;
+ }
+ if(current!=null)
+ {
+ if(previous!=null)
+ {
+ previous._next=current._next;
+ }
+ else
+ {
+ _firstProperty=current._next;
+ }
+ }
+ }
+ void setProperty(int type,Object value)
+ {
+ Property current=_firstProperty;
+ Property previous=null;
+ while(current!=null&¤t.getType()!=type)
+ {
+ previous=current;
+ current=current._next;
+ }
+ if(current!=null)
+ {
+ current.setValue(value);
+ }
+ else
+ {
+ switch(type)
+ {
+ case Property.COMMENT:
+ {
+ current=new CommentProperty(value);
+ break;
+ }
+ case Property.HYPERLINK:
+ {
+ current=new HyperlinkProperty(value);
+ break;
+ }
+ }
+ if(previous!=null)
+ {
+ previous._next=current;
+ }
+ else
+ {
+ _firstProperty=current;
+ }
+ }
+ }
+ Object getPropertyValue(int type)
+ {
+ return getPropertyValue(type,null);
+ }
+ Object getPropertyValue(int type,String defaultValue)
+ {
+ Property current=_firstProperty;
+ while(current!=null&¤t.getType()!=type) current=current._next;
+ return current==null?defaultValue:current.getValue();
+ }
+ void ensurePlainStringType()
+ {
+ if(_value.getType()!=CELL_TYPE_STRING
+ ||((StringValue)_value).isRichText())
+ _value=new PlainStringValue();
+ }
+ void ensureRichTextStringType()
+ {
+ if(_value.getType()!=CELL_TYPE_STRING
+ ||!((StringValue)_value).isRichText())
+ _value=new RichTextValue();
+ }
+ void ensureType(int type)
+ {
+ if(_value.getType()!=type)
+ setType(type);
+ }
+ void ensureFormulaType(int type)
+ {
+ if(_value.getType()!=CELL_TYPE_FORMULA
+ ||((FormulaValue)_value).getFormulaType()!=type)
+ setFormulaType(type);
+ }
+ void ensureTypeOrFormulaType(int type)
+ {
+ assert type==CELL_TYPE_NUMERIC||
+ type==CELL_TYPE_STRING||
+ type==CELL_TYPE_BOOLEAN||
+ type==CELL_TYPE_ERROR;
+ if(_value.getType()==type)
+ {
+ if(type==CELL_TYPE_STRING&&((StringValue)_value).isRichText())
+ setType(CELL_TYPE_STRING);
+ return;
+ }
+ if(_value.getType()==CELL_TYPE_FORMULA)
+ {
+ if(((FormulaValue)_value).getFormulaType()==type)
+ return;
+ setFormulaType(type); // once a formula, always a formula
+ return;
+ }
+ setType(type);
+ }
+ void setType(int type)
+ {
+ switch(type)
+ {
+ case CELL_TYPE_NUMERIC:
+ {
+ _value=new NumericValue();
+ break;
+ }
+ case CELL_TYPE_STRING:
+ {
+ _value=new PlainStringValue();
+ break;
+ }
+ case CELL_TYPE_FORMULA:
+ {
+ _value=new NumericFormulaValue();
+ break;
+ }
+ case CELL_TYPE_BLANK:
+ {
+ _value=new BlankValue();
+ break;
+ }
+ case CELL_TYPE_BOOLEAN:
+ {
+ _value=new BooleanValue();
+ break;
+ }
+ case CELL_TYPE_ERROR:
+ {
+ _value=new ErrorValue();
+ break;
+ }
+ default:
+ {
+ throw new IllegalArgumentException("Illegal type " + type);
+ }
+ }
+ }
+ void setFormulaType(int type)
+ {
+ switch(type)
+ {
+ case CELL_TYPE_NUMERIC:
+ {
+ _value=new NumericFormulaValue();
+ break;
+ }
+ case CELL_TYPE_STRING:
+ {
+ _value=new StringFormulaValue();
+ break;
+ }
+ case CELL_TYPE_BOOLEAN:
+ {
+ _value=new BooleanFormulaValue();
+ break;
+ }
+ case CELL_TYPE_ERROR:
+ {
+ _value=new ErrorFormulaValue();
+ break;
+ }
+ default:
+ {
+ throw new IllegalArgumentException("Illegal type " + type);
+ }
+ }
+ }
+//TODO: implement this correctly
+ int computeTypeFromFormula(String formula)
+ {
+ return CELL_TYPE_NUMERIC;
+ }
+//COPIED FROM https://svn.apache.org/repos/asf/poi/trunk/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFCell.java since the functions are declared private there
+ /**
+ * Used to help format error messages
+ */
+ private static RuntimeException typeMismatch(int expectedTypeCode, int actualTypeCode, boolean isFormulaCell) {
+ String msg = "Cannot get a "
+ + getCellTypeName(expectedTypeCode) + " value from a "
+ + getCellTypeName(actualTypeCode) + " " + (isFormulaCell ? "formula " : "") + "cell";
+ return new IllegalStateException(msg);
+ }
+/**
+ * Used to help format error messages
+ */
+ private static String getCellTypeName(int cellTypeCode) {
+ switch (cellTypeCode) {
+ case CELL_TYPE_BLANK: return "blank";
+ case CELL_TYPE_STRING: return "text";
+ case CELL_TYPE_BOOLEAN: return "boolean";
+ case CELL_TYPE_ERROR: return "error";
+ case CELL_TYPE_NUMERIC: return "numeric";
+ case CELL_TYPE_FORMULA: return "formula";
+ }
+ return "#unknown cell type (" + cellTypeCode + ")#";
+ }
+//END OF COPIED CODE
+
+ static abstract class Property
+ {
+ final static int COMMENT=1;
+ final static int HYPERLINK=2;
+ Object _value;
+ Property _next;
+ public Property(Object value)
+ {
+ _value=value;
+ }
+ abstract int getType();
+ void setValue(Object value)
+ {
+ _value=value;
+ }
+ Object getValue()
+ {
+ return _value;
+ }
+ }
+ static class CommentProperty extends Property
+ {
+ public CommentProperty(Object value)
+ {
+ super(value);
+ }
+ public int getType()
+ {
+ return COMMENT;
+ }
+ }
+ static class HyperlinkProperty extends Property
+ {
+ public HyperlinkProperty(Object value)
+ {
+ super(value);
+ }
+ public int getType()
+ {
+ return HYPERLINK;
+ }
+ }
+ interface Value
+ {
+ int getType();
+ }
+ static class NumericValue implements Value
+ {
+ double _value;
+ public int getType()
+ {
+ return CELL_TYPE_NUMERIC;
+ }
+ void setValue(double value)
+ {
+ _value=value;
+ }
+ double getValue()
+ {
+ return _value;
+ }
+ }
+ static abstract class StringValue implements Value
+ {
+ public int getType()
+ {
+ return CELL_TYPE_STRING;
+ }
+//We cannot introduce a new type CELL_TYPE_RICH_TEXT because the types are public so we have to make rich text as a type of string
+ abstract boolean isRichText(); // using the POI style which seems to avoid "instanceof".
+ }
+ static class PlainStringValue extends StringValue
+ {
+ String _value;
+ void setValue(String value)
+ {
+ _value=value;
+ }
+ String getValue()
+ {
+ return _value;
+ }
+ boolean isRichText()
+ {
+ return false;
+ }
+ }
+ static class RichTextValue implements Value
+ {
+ RichTextString _value;
+ public int getType()
+ {
+ return CELL_TYPE_STRING;
+ }
+ void setValue(RichTextString value)
+ {
+ _value=value;
+ }
+ RichTextString getValue()
+ {
+ return _value;
+ }
+ boolean isRichText()
+ {
+ return true;
+ }
+ }
+ static abstract class FormulaValue implements Value
+ {
+ String _value;
+ public int getType()
+ {
+ return CELL_TYPE_FORMULA;
+ }
+ void setValue(String value)
+ {
+ _value=value;
+ }
+ String getValue()
+ {
+ return _value;
+ }
+ abstract int getFormulaType();
+ }
+ static class NumericFormulaValue extends FormulaValue
+ {
+ double _preEvaluatedValue;
+ int getFormulaType()
+ {
+ return CELL_TYPE_NUMERIC;
+ }
+ void setPreEvaluatedValue(double value)
+ {
+ _preEvaluatedValue=value;
+ }
+ double getPreEvaluatedValue()
+ {
+ return _preEvaluatedValue;
+ }
+ }
+ static class StringFormulaValue extends FormulaValue
+ {
+ String _preEvaluatedValue;
+ int getFormulaType()
+ {
+ return CELL_TYPE_STRING;
+ }
+ void setPreEvaluatedValue(String value)
+ {
+ _preEvaluatedValue=value;
+ }
+ String getPreEvaluatedValue()
+ {
+ return _preEvaluatedValue;
+ }
+ }
+ static class BooleanFormulaValue extends FormulaValue
+ {
+ boolean _preEvaluatedValue;
+ int getFormulaType()
+ {
+ return CELL_TYPE_BOOLEAN;
+ }
+ void setPreEvaluatedValue(boolean value)
+ {
+ _preEvaluatedValue=value;
+ }
+ boolean getPreEvaluatedValue()
+ {
+ return _preEvaluatedValue;
+ }
+ }
+ static class ErrorFormulaValue extends FormulaValue
+ {
+ byte _preEvaluatedValue;
+ int getFormulaType()
+ {
+ return CELL_TYPE_ERROR;
+ }
+ void setPreEvaluatedValue(byte value)
+ {
+ _preEvaluatedValue=value;
+ }
+ byte getPreEvaluatedValue()
+ {
+ return _preEvaluatedValue;
+ }
+ }
+ static class BlankValue implements Value
+ {
+ public int getType()
+ {
+ return CELL_TYPE_BLANK;
+ }
+ }
+ static class BooleanValue implements Value
+ {
+ boolean _value;
+ public int getType()
+ {
+ return CELL_TYPE_BOOLEAN;
+ }
+ void setValue(boolean value)
+ {
+ _value=value;
+ }
+ boolean getValue()
+ {
+ return _value;
+ }
+ }
+ static class ErrorValue implements Value
+ {
+ byte _value;
+ public int getType()
+ {
+ return CELL_TYPE_ERROR;
+ }
+ void setValue(byte value)
+ {
+ _value=value;
+ }
+ byte getValue()
+ {
+ return _value;
+ }
+ }
+}
--- /dev/null
+/* ====================================================================
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+==================================================================== */
+
+package org.apache.poi.xssf.streaming;
+
+import org.apache.poi.ss.usermodel.Cell;
+import org.apache.poi.ss.usermodel.Row;
+import org.apache.poi.ss.usermodel.Sheet;
+
+import java.util.Iterator;
+import java.util.NoSuchElementException;
+
+/**
+ * Streaming version of XSSFRow implementing the "BigGridDemo" strategy.
+ *
+ * @author Alex Geller, Four J's Development Tools
+*/
+public class SXSSFRow implements Row
+{
+ SXSSFSheet _sheet;
+ SXSSFCell[] _cells;
+ int _maxColumn=-1;
+ short _height=-1;
+//TODO: Need to set the correct default value for _zHeight
+ boolean _zHeight;
+
+ public SXSSFRow(SXSSFSheet sheet, int initialSize)
+ {
+ _sheet=sheet;
+ _cells=new SXSSFCell[initialSize];
+ }
+ public Iterator<Cell> allCellsIterator()
+ {
+ return new CellIterator();
+ }
+ public boolean hasCustomHeight()
+ {
+ return _height!=-1;
+ }
+//begin of interface implementation
+ public Iterator<Cell> iterator()
+ {
+ return new FilledCellIterator();
+ }
+
+ /**
+ * Use this to create new cells within the row and return it.
+ * <p>
+ * The cell that is returned is a {@link Cell#CELL_TYPE_BLANK}. The type can be changed
+ * either through calling <code>setCellValue</code> or <code>setCellType</code>.
+ *
+ * @param column - the column number this cell represents
+ * @return Cell a high level representation of the created cell.
+ * @throws IllegalArgumentException if columnIndex < 0 or greater than the maximum number of supported columns
+ * (255 for *.xls, 1048576 for *.xlsx)
+ */
+ public Cell createCell(int column)
+ {
+ return createCell(column,Cell.CELL_TYPE_BLANK);
+ }
+
+ /**
+ * Use this to create new cells within the row and return it.
+ * <p>
+ * The cell that is returned is a {@link Cell#CELL_TYPE_BLANK}. The type can be changed
+ * either through calling setCellValue or setCellType.
+ *
+ * @param column - the column number this cell represents
+ * @return Cell a high level representation of the created cell.
+ * @throws IllegalArgumentException if columnIndex < 0 or greate than a maximum number of supported columns
+ * (255 for *.xls, 1048576 for *.xlsx)
+ */
+ public Cell createCell(int column, int type)
+ {
+ if(column>=_cells.length)
+ {
+ SXSSFCell[] newCells=new SXSSFCell[Math.max(column+1,_cells.length*2)];
+ System.arraycopy(_cells,0,newCells,0,_cells.length);
+ _cells=newCells;
+ }
+ _cells[column]=new SXSSFCell(this,type);
+ if(column>_maxColumn) _maxColumn=column;
+ return _cells[column];
+ }
+
+ /**
+ * Remove the Cell from this row.
+ *
+ * @param cell the cell to remove
+ */
+ public void removeCell(Cell cell)
+ {
+ int index=getCellIndex(cell);
+ if(index>=0)
+ {
+ _cells[index]=null;
+ while(_maxColumn>=0&&_cells[_maxColumn]==null) _maxColumn--;
+ }
+ }
+
+ int getCellIndex(Cell cell)
+ {
+ for(int i=0;i<=_maxColumn;i++)
+ {
+ if(_cells[i]==cell) return i;
+ }
+ return -1;
+ }
+
+ /**
+ * Set the row number of this row.
+ *
+ * @param rowNum the row number (0-based)
+ * @throws IllegalArgumentException if rowNum < 0
+ */
+ public void setRowNum(int rowNum)
+ {
+ _sheet.changeRowNum(this,rowNum);
+ }
+
+ /**
+ * Get row number this row represents
+ *
+ * @return the row number (0 based)
+ */
+ public int getRowNum()
+ {
+ return _sheet.getRowNum(this);
+ }
+
+ /**
+ * Get the cell representing a given column (logical cell) 0-based. If you
+ * ask for a cell that is not defined....you get a null.
+ *
+ * @param cellnum 0 based column number
+ * @return Cell representing that column or null if undefined.
+ * @see #getCell(int, org.apache.poi.ss.usermodel.Row.MissingCellPolicy)
+ */
+ public Cell getCell(int cellnum)
+ {
+ return cellnum>_maxColumn?null:_cells[cellnum];
+ }
+
+ /**
+ * Returns the cell at the given (0 based) index, with the specified {@link org.apache.poi.ss.usermodel.Row.MissingCellPolicy}
+ *
+ * @return the cell at the given (0 based) index
+ * @throws IllegalArgumentException if cellnum < 0 or the specified MissingCellPolicy is invalid
+ * @see Row#RETURN_NULL_AND_BLANK
+ * @see Row#RETURN_BLANK_AS_NULL
+ * @see Row#CREATE_NULL_AS_BLANK
+ */
+ public Cell getCell(int cellnum, MissingCellPolicy policy)
+ {
+ assert false;
+ Cell cell = getCell(cellnum);
+ if(policy == RETURN_NULL_AND_BLANK)
+ {
+ return cell;
+ }
+ if(policy == RETURN_BLANK_AS_NULL)
+ {
+ if(cell == null) return cell;
+ if(cell.getCellType() == Cell.CELL_TYPE_BLANK)
+ {
+ return null;
+ }
+ return cell;
+ }
+ if(policy == CREATE_NULL_AS_BLANK)
+ {
+ if(cell == null)
+ {
+ return createCell(cellnum, Cell.CELL_TYPE_BLANK);
+ }
+ return cell;
+ }
+ throw new IllegalArgumentException("Illegal policy " + policy + " (" + policy.id + ")");
+ }
+
+ /**
+ * Get the number of the first cell contained in this row.
+ *
+ * @return short representing the first logical cell in the row,
+ * or -1 if the row does not contain any cells.
+ */
+ public short getFirstCellNum()
+ {
+ for(int i=0;i<=_maxColumn;i++)
+ if(_cells[i]!=null) return (short)i;
+ return -1;
+ }
+
+ /**
+ * Gets the index of the last cell contained in this row <b>PLUS ONE</b>. The result also
+ * happens to be the 1-based column number of the last cell. This value can be used as a
+ * standard upper bound when iterating over cells:
+ * <pre>
+ * short minColIx = row.getFirstCellNum();
+ * short maxColIx = row.getLastCellNum();
+ * for(short colIx=minColIx; colIx<maxColIx; colIx++) {
+ * Cell cell = row.getCell(colIx);
+ * if(cell == null) {
+ * continue;
+ * }
+ * //... do something with cell
+ * }
+ * </pre>
+ *
+ * @return short representing the last logical cell in the row <b>PLUS ONE</b>,
+ * or -1 if the row does not contain any cells.
+ */
+ public short getLastCellNum()
+ {
+ return (short)(_maxColumn+1);
+ }
+
+ /**
+ * Gets the number of defined cells (NOT number of cells in the actual row!).
+ * That is to say if only columns 0,4,5 have values then there would be 3.
+ *
+ * @return int representing the number of defined cells in the row.
+ */
+ public int getPhysicalNumberOfCells()
+ {
+ int count=0;
+ for(int i=0;i<=_maxColumn;i++)
+ {
+ if(_cells[i]!=null) count++;
+ }
+ return count;
+ }
+
+ /**
+ * Set the row's height or set to ff (-1) for undefined/default-height. Set the height in "twips" or
+ * 1/20th of a point.
+ *
+ * @param height rowheight or 0xff for undefined (use sheet default)
+ */
+ public void setHeight(short height)
+ {
+ _height=height;
+ }
+
+ /**
+ * Set whether or not to display this row with 0 height
+ *
+ * @param zHeight height is zero or not.
+ */
+ public void setZeroHeight(boolean zHeight)
+ {
+ _zHeight=zHeight;
+ }
+
+ /**
+ * Get whether or not to display this row with 0 height
+ *
+ * @return - zHeight height is zero or not.
+ */
+ public boolean getZeroHeight()
+ {
+ return _zHeight;
+ }
+
+ /**
+ * Set the row's height in points.
+ *
+ * @param height the height in points. <code>-1</code> resets to the default height
+ */
+ public void setHeightInPoints(float height)
+ {
+ if(height==-1)
+ _height=-1;
+ else
+ _height=(short)(height*20);
+ }
+
+ /**
+ * Get the row's height measured in twips (1/20th of a point). If the height is not set, the default worksheet value is returned,
+ * See {@link Sheet#getDefaultRowHeightInPoints()}
+ *
+ * @return row height measured in twips (1/20th of a point)
+ */
+ public short getHeight()
+ {
+ return (short)(_height==-1?getSheet().getDefaultRowHeightInPoints()*20:_height);
+ }
+
+ /**
+ * Returns row height measured in point size. If the height is not set, the default worksheet value is returned,
+ * See {@link Sheet#getDefaultRowHeightInPoints()}
+ *
+ * @return row height measured in point size
+ * @see Sheet#getDefaultRowHeightInPoints()
+ */
+ public float getHeightInPoints()
+ {
+ return (float)(_height==-1?getSheet().getDefaultRowHeightInPoints():(float)_height/20.0);
+ }
+
+ /**
+ * @return Cell iterator of the physically defined cells. Note element 4 may
+ * actually be row cell depending on how many are defined!
+ */
+ public Iterator<Cell> cellIterator()
+ {
+ return iterator();
+ }
+
+ /**
+ * Returns the Sheet this row belongs to
+ *
+ * @return the Sheet that owns this row
+ */
+ public Sheet getSheet()
+ {
+ return _sheet;
+ }
+//end of interface implementation
+
+
+/** returns all filled cells (created via Row.createCell())*/
+ public class FilledCellIterator implements Iterator<Cell>
+ {
+ int pos=0;
+ public boolean hasNext()
+ {
+ return pos <= _maxColumn;
+ }
+ void advanceToNext()
+ {
+ pos++;
+ while(pos<=_maxColumn&&_cells[pos]==null) pos++;
+ }
+ public Cell next() throws NoSuchElementException
+ {
+ if (hasNext())
+ {
+ Cell retval=_cells[pos];
+ advanceToNext();
+ return retval;
+ }
+ else
+ {
+ throw new NoSuchElementException();
+ }
+ }
+ public void remove()
+ {
+ throw new UnsupportedOperationException();
+ }
+ }
+/** returns all cells including empty cells in which case "null" is returned*/
+ public class CellIterator implements Iterator<Cell>
+ {
+ int pos=0;
+ public boolean hasNext()
+ {
+ return pos <= _maxColumn;
+ }
+ public Cell next() throws NoSuchElementException
+ {
+ if (hasNext())
+ return _cells[pos++];
+ else
+ throw new NoSuchElementException();
+ }
+ public void remove()
+ {
+ throw new UnsupportedOperationException();
+ }
+ }
+}
+
--- /dev/null
+/* ====================================================================
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+==================================================================== */
+
+package org.apache.poi.xssf.streaming;
+
+import java.util.Iterator;
+import java.util.TreeMap;
+import java.util.Map;
+import java.io.Writer;
+import java.io.File;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.FileInputStream;
+
+import org.apache.poi.ss.usermodel.Sheet;
+import org.apache.poi.ss.usermodel.Row;
+import org.apache.poi.ss.usermodel.Cell;
+import org.apache.poi.ss.usermodel.CellStyle;
+import org.apache.poi.ss.usermodel.PrintSetup;
+import org.apache.poi.ss.usermodel.Header;
+import org.apache.poi.ss.usermodel.Footer;
+import org.apache.poi.ss.usermodel.Comment;
+import org.apache.poi.ss.usermodel.Drawing;
+import org.apache.poi.ss.usermodel.Workbook;
+import org.apache.poi.ss.usermodel.DataValidation;
+import org.apache.poi.ss.usermodel.CellRange;
+import org.apache.poi.ss.usermodel.DataValidationHelper;
+import org.apache.poi.ss.usermodel.AutoFilter;
+import org.apache.poi.ss.util.CellReference;
+
+import org.apache.poi.xssf.usermodel.XSSFSheet;
+
+import org.apache.poi.hssf.util.PaneInformation;
+import org.apache.poi.ss.util.CellRangeAddress;
+
+/**
+ * Streaming version of XSSFSheet implementing the "BigGridDemo" strategy.
+ *
+ * @author Alex Geller, Four J's Development Tools
+*/
+public class SXSSFSheet implements Sheet, Cloneable
+{
+ SXSSFWorkbook _workbook;
+ XSSFSheet _sh;
+ TreeMap<Integer,SXSSFRow> _rows=new TreeMap<Integer,SXSSFRow>();
+ SheetDataWriter _writer;
+ int _randomAccessWindowSize=5000;
+
+ public SXSSFSheet(SXSSFWorkbook workbook,XSSFSheet xSheet) throws IOException
+ {
+ _workbook=workbook;
+ _sh=xSheet;
+ _writer=new SheetDataWriter();
+
+ }
+/* Gets "<sheetData>" document fragment*/
+ public InputStream getWorksheetXMLInputStream() throws IOException
+ {
+ flushRows(0);
+ return _writer.getWorksheetXMLInputStream();
+ }
+
+//start of interface implementation
+ public Iterator<Row> iterator()
+ {
+ return rowIterator();
+ }
+
+ /**
+ * Create a new row within the sheet and return the high level representation
+ *
+ * @param rownum row number
+ * @return high level Row object representing a row in the sheet
+ * @see #removeRow(Row)
+ */
+ public Row createRow(int rownum)
+ {
+//Make the initial allocation as big as the row above.
+ Row previousRow=rownum>0?getRow(rownum-1):null;
+ int initialAllocationSize=0;
+//have previous row in memory -> take that value.
+ if(previousRow!=null)
+ initialAllocationSize=previousRow.getLastCellNum();
+//are we called after a flush(0)? If yes, ask the writer for the value.
+ if(initialAllocationSize<=0&&_writer.getNumberOfFlushedRows()>0)
+ initialAllocationSize=_writer.getNumberOfCellsOfLastFlushedRow();
+//default to 10 on the first row.
+ if(initialAllocationSize<=0)
+ initialAllocationSize=10;
+ SXSSFRow newRow=new SXSSFRow(this,initialAllocationSize);
+ _rows.put(new Integer(rownum),newRow);
+ if(_randomAccessWindowSize>=0&&_rows.size()>_randomAccessWindowSize)
+ {
+ try
+ {
+ flushRows(_randomAccessWindowSize);
+ }
+ catch (IOException ioe)
+ {
+ throw new RuntimeException(ioe);
+ }
+ }
+ return newRow;
+ }
+
+ /**
+ * Remove a row from this sheet. All cells contained in the row are removed as well
+ *
+ * @param row representing a row to remove.
+ */
+ public void removeRow(Row row)
+ {
+ for(Iterator<Map.Entry<Integer,SXSSFRow>> iter=_rows.entrySet().iterator();iter.hasNext();)
+ {
+ Map.Entry<Integer,SXSSFRow> entry=iter.next();
+ if(entry.getValue()==row)
+ {
+ iter.remove();
+ return;
+ }
+ }
+ }
+
+ /**
+ * Returns the logical row (not physical) 0-based. If you ask for a row that is not
+ * defined you get a null. This is to say row 4 represents the fifth row on a sheet.
+ *
+ * @param rownum row to get (0-based)
+ * @return Row representing the rownumber or null if its not defined on the sheet
+ */
+ public Row getRow(int rownum)
+ {
+ return _rows.get(new Integer(rownum));
+ }
+
+ /**
+ * Returns the number of physically defined rows (NOT the number of rows in the sheet)
+ *
+ * @return the number of physically defined rows in this sheet
+ */
+ public int getPhysicalNumberOfRows()
+ {
+ return _rows.size()+_writer.getNumberOfFlushedRows();
+ }
+
+ /**
+ * Gets the first row on the sheet
+ *
+ * @return the number of the first logical row on the sheet (0-based)
+ */
+ public int getFirstRowNum()
+ {
+ if(_writer.getNumberOfFlushedRows()>0)
+ return _writer.getLowestIndexOfFlushedRows();
+ Integer firstKey=_rows.firstKey();
+ return firstKey==null?-1:firstKey.intValue();
+ }
+
+ /**
+ * Gets the last row on the sheet
+ *
+ * @return last row contained n this sheet (0-based)
+ */
+ public int getLastRowNum()
+ {
+ Integer lastKey=_rows.lastKey();
+ return lastKey==null?-1:lastKey.intValue();
+ }
+
+ /**
+ * Get the visibility state for a given column
+ *
+ * @param columnIndex - the column to get (0-based)
+ * @param hidden - the visiblity state of the column
+ */
+ public void setColumnHidden(int columnIndex, boolean hidden)
+ {
+ _sh.setColumnHidden(columnIndex,hidden);
+ }
+
+ /**
+ * Get the hidden state for a given column
+ *
+ * @param columnIndex - the column to set (0-based)
+ * @return hidden - <code>false</code> if the column is visible
+ */
+ public boolean isColumnHidden(int columnIndex)
+ {
+ return _sh.isColumnHidden(columnIndex);
+ }
+
+ /**
+ * Set the width (in units of 1/256th of a character width)
+ * <p>
+ * The maximum column width for an individual cell is 255 characters.
+ * This value represents the number of characters that can be displayed
+ * in a cell that is formatted with the standard font.
+ * </p>
+ *
+ * @param columnIndex - the column to set (0-based)
+ * @param width - the width in units of 1/256th of a character width
+ */
+ public void setColumnWidth(int columnIndex, int width)
+ {
+ _sh.setColumnWidth(columnIndex,width);
+ }
+
+ /**
+ * get the width (in units of 1/256th of a character width )
+ * @param columnIndex - the column to set (0-based)
+ * @return width - the width in units of 1/256th of a character width
+ */
+ public int getColumnWidth(int columnIndex)
+ {
+ return _sh.getColumnWidth(columnIndex);
+ }
+
+ /**
+ * Set the default column width for the sheet (if the columns do not define their own width)
+ * in characters
+ *
+ * @param width default column width measured in characters
+ */
+ public void setDefaultColumnWidth(int width)
+ {
+ _sh.setDefaultColumnWidth(width);
+ }
+
+ /**
+ * Get the default column width for the sheet (if the columns do not define their own width)
+ * in characters
+ *
+ * @return default column width measured in characters
+ */
+ public int getDefaultColumnWidth()
+ {
+ return _sh.getDefaultColumnWidth();
+ }
+
+
+ /**
+ * Get the default row height for the sheet (if the rows do not define their own height) in
+ * twips (1/20 of a point)
+ *
+ * @return default row height measured in twips (1/20 of a point)
+ */
+ public short getDefaultRowHeight()
+ {
+ return _sh.getDefaultRowHeight();
+ }
+
+ /**
+ * Get the default row height for the sheet (if the rows do not define their own height) in
+ * points.
+ *
+ * @return default row height in points
+ */
+ public float getDefaultRowHeightInPoints()
+ {
+ return _sh.getDefaultRowHeightInPoints();
+ }
+
+ /**
+ * Set the default row height for the sheet (if the rows do not define their own height) in
+ * twips (1/20 of a point)
+ *
+ * @param height default row height measured in twips (1/20 of a point)
+ */
+ public void setDefaultRowHeight(short height)
+ {
+ _sh.setDefaultRowHeight(height);
+ }
+
+ /**
+ * Set the default row height for the sheet (if the rows do not define their own height) in
+ * points
+ * @param height default row height
+ */
+ public void setDefaultRowHeightInPoints(float height)
+ {
+ _sh.setDefaultRowHeightInPoints(height);
+ }
+
+
+ /**
+ * Returns the CellStyle that applies to the given
+ * (0 based) column, or null if no style has been
+ * set for that column
+ */
+ public CellStyle getColumnStyle(int column)
+ {
+ return _sh.getColumnStyle(column);
+ }
+
+ /**
+ * Sets the CellStyle that applies to the given
+ * (0 based) column.
+ */
+// public CellStyle setColumnStyle(int column, CellStyle style);
+
+ /**
+ * Adds a merged region of cells (hence those cells form one)
+ *
+ * @param region (rowfrom/colfrom-rowto/colto) to merge
+ * @return index of this region
+ */
+ public int addMergedRegion(CellRangeAddress region)
+ {
+ return _sh.addMergedRegion(region);
+ }
+
+ /**
+ * Determines whether the output is vertically centered on the page.
+ *
+ * @param value true to vertically center, false otherwise.
+ */
+ public void setVerticallyCenter(boolean value)
+ {
+ _sh.setVerticallyCenter(value);
+ }
+
+ /**
+ * Determines whether the output is horizontally centered on the page.
+ *
+ * @param value true to horizontally center, false otherwise.
+ */
+ public void setHorizontallyCenter(boolean value)
+ {
+ _sh.setHorizontallyCenter(value);
+ }
+
+ /**
+ * Determine whether printed output for this sheet will be horizontally centered.
+ */
+
+ public boolean getHorizontallyCenter()
+ {
+ return _sh.getHorizontallyCenter();
+ }
+
+ /**
+ * Determine whether printed output for this sheet will be vertically centered.
+ */
+ public boolean getVerticallyCenter()
+ {
+ return _sh.getVerticallyCenter();
+ }
+
+ /**
+ * Removes a merged region of cells (hence letting them free)
+ *
+ * @param index of the region to unmerge
+ */
+ public void removeMergedRegion(int index)
+ {
+ _sh.removeMergedRegion(index);
+ }
+
+ /**
+ * Returns the number of merged regions
+ *
+ * @return number of merged regions
+ */
+ public int getNumMergedRegions()
+ {
+ return _sh.getNumMergedRegions();
+ }
+
+ /**
+ * Returns the merged region at the specified index
+ *
+ * @return the merged region at the specified index
+ */
+ public CellRangeAddress getMergedRegion(int index)
+ {
+ return _sh.getMergedRegion(index);
+ }
+
+ /**
+ * Returns an iterator of the physical rows
+ *
+ * @return an iterator of the PHYSICAL rows. Meaning the 3rd element may not
+ * be the third row if say for instance the second row is undefined.
+ */
+ public Iterator<Row> rowIterator()
+ {
+ @SuppressWarnings("unchecked")
+ Iterator<Row> result = (Iterator<Row>)(Iterator<? extends Row>)_rows.values().iterator();
+ return result;
+ }
+
+ /**
+ * Flag indicating whether the sheet displays Automatic Page Breaks.
+ *
+ * @param value <code>true</code> if the sheet displays Automatic Page Breaks.
+ */
+ public void setAutobreaks(boolean value)
+ {
+ _sh.setAutobreaks(value);
+ }
+
+ /**
+ * Set whether to display the guts or not
+ *
+ * @param value - guts or no guts
+ */
+ public void setDisplayGuts(boolean value)
+ {
+ _sh.setDisplayGuts(value);
+ }
+
+ /**
+ * Set whether the window should show 0 (zero) in cells containing zero value.
+ * When false, cells with zero value appear blank instead of showing the number zero.
+ *
+ * @param value whether to display or hide all zero values on the worksheet
+ */
+ public void setDisplayZeros(boolean value)
+ {
+ _sh.setDisplayZeros(value);
+ }
+
+
+ /**
+ * Gets the flag indicating whether the window should show 0 (zero) in cells containing zero value.
+ * When false, cells with zero value appear blank instead of showing the number zero.
+ *
+ * @return whether all zero values on the worksheet are displayed
+ */
+ public boolean isDisplayZeros()
+ {
+ return _sh.isDisplayZeros();
+ }
+
+ /**
+ * Flag indicating whether the Fit to Page print option is enabled.
+ *
+ * @param value <code>true</code> if the Fit to Page print option is enabled.
+ */
+ public void setFitToPage(boolean value)
+ {
+ _sh.setFitToPage(value);
+ }
+
+ /**
+ * Flag indicating whether summary rows appear below detail in an outline, when applying an outline.
+ *
+ * <p>
+ * When true a summary row is inserted below the detailed data being summarized and a
+ * new outline level is established on that row.
+ * </p>
+ * <p>
+ * When false a summary row is inserted above the detailed data being summarized and a new outline level
+ * is established on that row.
+ * </p>
+ * @param value <code>true</code> if row summaries appear below detail in the outline
+ */
+ public void setRowSumsBelow(boolean value)
+ {
+ _sh.setRowSumsBelow(value);
+ }
+
+ /**
+ * Flag indicating whether summary columns appear to the right of detail in an outline, when applying an outline.
+ *
+ * <p>
+ * When true a summary column is inserted to the right of the detailed data being summarized
+ * and a new outline level is established on that column.
+ * </p>
+ * <p>
+ * When false a summary column is inserted to the left of the detailed data being
+ * summarized and a new outline level is established on that column.
+ * </p>
+ * @param value <code>true</code> if col summaries appear right of the detail in the outline
+ */
+ public void setRowSumsRight(boolean value)
+ {
+ _sh.setRowSumsRight(value);
+ }
+
+ /**
+ * Flag indicating whether the sheet displays Automatic Page Breaks.
+ *
+ * @return <code>true</code> if the sheet displays Automatic Page Breaks.
+ */
+ public boolean getAutobreaks()
+ {
+ return _sh.getAutobreaks();
+ }
+
+ /**
+ * Get whether to display the guts or not,
+ * default value is true
+ *
+ * @return boolean - guts or no guts
+ */
+ public boolean getDisplayGuts()
+ {
+ return _sh.getDisplayGuts();
+ }
+
+ /**
+ * Flag indicating whether the Fit to Page print option is enabled.
+ *
+ * @return <code>true</code> if the Fit to Page print option is enabled.
+ */
+ public boolean getFitToPage()
+ {
+ return _sh.getFitToPage();
+ }
+
+ /**
+ * Flag indicating whether summary rows appear below detail in an outline, when applying an outline.
+ *
+ * <p>
+ * When true a summary row is inserted below the detailed data being summarized and a
+ * new outline level is established on that row.
+ * </p>
+ * <p>
+ * When false a summary row is inserted above the detailed data being summarized and a new outline level
+ * is established on that row.
+ * </p>
+ * @return <code>true</code> if row summaries appear below detail in the outline
+ */
+ public boolean getRowSumsBelow()
+ {
+ return _sh.getRowSumsBelow();
+ }
+
+ /**
+ * Flag indicating whether summary columns appear to the right of detail in an outline, when applying an outline.
+ *
+ * <p>
+ * When true a summary column is inserted to the right of the detailed data being summarized
+ * and a new outline level is established on that column.
+ * </p>
+ * <p>
+ * When false a summary column is inserted to the left of the detailed data being
+ * summarized and a new outline level is established on that column.
+ * </p>
+ * @return <code>true</code> if col summaries appear right of the detail in the outline
+ */
+ public boolean getRowSumsRight()
+ {
+ return _sh.getRowSumsRight();
+ }
+
+ /**
+ * Gets the flag indicating whether this sheet displays the lines
+ * between rows and columns to make editing and reading easier.
+ *
+ * @return <code>true</code> if this sheet displays gridlines.
+ * @see #isPrintGridlines() to check if printing of gridlines is turned on or off
+ */
+ public boolean isPrintGridlines()
+ {
+ return _sh.isPrintGridlines();
+ }
+
+ /**
+ * Sets the flag indicating whether this sheet should display the lines
+ * between rows and columns to make editing and reading easier.
+ * To turn printing of gridlines use {@link #setPrintGridlines(boolean)}
+ *
+ *
+ * @param show <code>true</code> if this sheet should display gridlines.
+ * @see #setPrintGridlines(boolean)
+ */
+ public void setPrintGridlines(boolean show)
+ {
+ _sh.setPrintGridlines(show);
+ }
+
+ /**
+ * Gets the print setup object.
+ *
+ * @return The user model for the print setup object.
+ */
+ public PrintSetup getPrintSetup()
+ {
+ return _sh.getPrintSetup();
+ }
+
+ /**
+ * Gets the user model for the default document header.
+ * <p/>
+ * Note that XSSF offers more kinds of document headers than HSSF does
+ * </p>
+ * @return the document header. Never <code>null</code>
+ */
+ public Header getHeader()
+ {
+ return _sh.getHeader();
+ }
+
+ /**
+ * Gets the user model for the default document footer.
+ * <p/>
+ * Note that XSSF offers more kinds of document footers than HSSF does.
+ *
+ * @return the document footer. Never <code>null</code>
+ */
+ public Footer getFooter()
+ {
+ return _sh.getFooter();
+ }
+
+ /**
+ * Sets a flag indicating whether this sheet is selected.
+ *<p>
+ * Note: multiple sheets can be selected, but only one sheet can be active at one time.
+ *</p>
+ * @param value <code>true</code> if this sheet is selected
+ * @see Workbook#setActiveSheet(int)
+ */
+ public void setSelected(boolean value)
+ {
+ _sh.setSelected(value);
+ }
+
+ /**
+ * Gets the size of the margin in inches.
+ *
+ * @param margin which margin to get
+ * @return the size of the margin
+ */
+ public double getMargin(short margin)
+ {
+ return _sh.getMargin(margin);
+ }
+
+ /**
+ * Sets the size of the margin in inches.
+ *
+ * @param margin which margin to get
+ * @param size the size of the margin
+ */
+ public void setMargin(short margin, double size)
+ {
+ _sh.setMargin(margin,size);
+ }
+
+ /**
+ * Answer whether protection is enabled or disabled
+ *
+ * @return true => protection enabled; false => protection disabled
+ */
+ public boolean getProtect()
+ {
+ return _sh.getProtect();
+ }
+
+ /**
+ * Sets the protection enabled as well as the password
+ * @param password to set for protection. Pass <code>null</code> to remove protection
+ */
+ public void protectSheet(String password)
+ {
+ _sh.protectSheet(password);
+ }
+
+ /**
+ * Answer whether scenario protection is enabled or disabled
+ *
+ * @return true => protection enabled; false => protection disabled
+ */
+ public boolean getScenarioProtect()
+ {
+ return _sh.getScenarioProtect();
+ }
+
+ /**
+ * Sets the zoom magnication for the sheet. The zoom is expressed as a
+ * fraction. For example to express a zoom of 75% use 3 for the numerator
+ * and 4 for the denominator.
+ *
+ * @param numerator The numerator for the zoom magnification.
+ * @param denominator The denominator for the zoom magnification.
+ */
+ public void setZoom(int numerator, int denominator)
+ {
+ _sh.setZoom(numerator,denominator);
+ }
+
+ /**
+ * The top row in the visible view when the sheet is
+ * first viewed after opening it in a viewer
+ *
+ * @return short indicating the rownum (0 based) of the top row
+ */
+ public short getTopRow()
+ {
+ return _sh.getTopRow();
+ }
+
+ /**
+ * The left col in the visible view when the sheet is
+ * first viewed after opening it in a viewer
+ *
+ * @return short indicating the rownum (0 based) of the top row
+ */
+ public short getLeftCol()
+ {
+ return _sh.getLeftCol();
+ }
+
+ /**
+ * Sets desktop window pane display area, when the
+ * file is first opened in a viewer.
+ *
+ * @param toprow the top row to show in desktop window pane
+ * @param leftcol the left column to show in desktop window pane
+ */
+ public void showInPane(short toprow, short leftcol)
+ {
+ _sh.showInPane(toprow, leftcol);
+ }
+
+ /**
+ * Control if Excel should be asked to recalculate all formulas when the
+ * workbook is opened, via the "sheetCalcPr fullCalcOnLoad" option.
+ * Calculating the formula values with {@link org.apache.poi.ss.usermodel.FormulaEvaluator} is the
+ * recommended solution, but this may be used for certain cases where
+ * evaluation in POI is not possible.
+ */
+ public void setForceFormulaRecalculation(boolean value) {
+ _sh.setForceFormulaRecalculation(value);
+ }
+
+ /**
+ * Whether Excel will be asked to recalculate all formulas when the
+ * workbook is opened.
+ */
+ public boolean getForceFormulaRecalculation() {
+ return _sh.getForceFormulaRecalculation();
+ }
+
+ /**
+ * Shifts rows between startRow and endRow n number of rows.
+ * If you use a negative number, it will shift rows up.
+ * Code ensures that rows don't wrap around.
+ *
+ * Calls shiftRows(startRow, endRow, n, false, false);
+ *
+ * <p>
+ * Additionally shifts merged regions that are completely defined in these
+ * rows (ie. merged 2 cells on a row to be shifted).
+ * @param startRow the row to start shifting
+ * @param endRow the row to end shifting
+ * @param n the number of rows to shift
+ */
+ public void shiftRows(int startRow, int endRow, int n)
+ {
+ throw new RuntimeException("NotImplemented");
+ }
+
+ /**
+ * Shifts rows between startRow and endRow n number of rows.
+ * If you use a negative number, it will shift rows up.
+ * Code ensures that rows don't wrap around
+ *
+ * <p>
+ * Additionally shifts merged regions that are completely defined in these
+ * rows (ie. merged 2 cells on a row to be shifted).
+ * <p>
+ * @param startRow the row to start shifting
+ * @param endRow the row to end shifting
+ * @param n the number of rows to shift
+ * @param copyRowHeight whether to copy the row height during the shift
+ * @param resetOriginalRowHeight whether to set the original row's height to the default
+ */
+ public void shiftRows(int startRow, int endRow, int n, boolean copyRowHeight, boolean resetOriginalRowHeight)
+ {
+ throw new RuntimeException("NotImplemented");
+ }
+
+ /**
+ * Creates a split (freezepane). Any existing freezepane or split pane is overwritten.
+ * @param colSplit Horizonatal position of split.
+ * @param rowSplit Vertical position of split.
+ * @param leftmostColumn Left column visible in right pane.
+ * @param topRow Top row visible in bottom pane
+ */
+ public void createFreezePane(int colSplit, int rowSplit, int leftmostColumn, int topRow)
+ {
+ _sh.createFreezePane(colSplit, rowSplit, leftmostColumn, topRow);
+ }
+
+ /**
+ * Creates a split (freezepane). Any existing freezepane or split pane is overwritten.
+ * @param colSplit Horizonatal position of split.
+ * @param rowSplit Vertical position of split.
+ */
+ public void createFreezePane(int colSplit, int rowSplit)
+ {
+ _sh.createFreezePane(colSplit,rowSplit);
+ }
+
+ /**
+ * Creates a split pane. Any existing freezepane or split pane is overwritten.
+ * @param xSplitPos Horizonatal position of split (in 1/20th of a point).
+ * @param ySplitPos Vertical position of split (in 1/20th of a point).
+ * @param topRow Top row visible in bottom pane
+ * @param leftmostColumn Left column visible in right pane.
+ * @param activePane Active pane. One of: PANE_LOWER_RIGHT,
+ * PANE_UPPER_RIGHT, PANE_LOWER_LEFT, PANE_UPPER_LEFT
+ * @see #PANE_LOWER_LEFT
+ * @see #PANE_LOWER_RIGHT
+ * @see #PANE_UPPER_LEFT
+ * @see #PANE_UPPER_RIGHT
+ */
+ public void createSplitPane(int xSplitPos, int ySplitPos, int leftmostColumn, int topRow, int activePane)
+ {
+ _sh.createSplitPane(xSplitPos, ySplitPos, leftmostColumn, topRow, activePane);
+ }
+
+ /**
+ * Returns the information regarding the currently configured pane (split or freeze)
+ *
+ * @return null if no pane configured, or the pane information.
+ */
+ public PaneInformation getPaneInformation()
+ {
+ return _sh.getPaneInformation();
+ }
+
+ /**
+ * Sets whether the gridlines are shown in a viewer
+ *
+ * @param show whether to show gridlines or not
+ */
+ public void setDisplayGridlines(boolean show)
+ {
+ _sh.setDisplayGridlines(show);
+ }
+
+ /**
+ * Returns if gridlines are displayed
+ *
+ * @return whether gridlines are displayed
+ */
+ public boolean isDisplayGridlines()
+ {
+ return _sh.isDisplayGridlines();
+ }
+
+ /**
+ * Sets whether the formulas are shown in a viewer
+ *
+ * @param show whether to show formulas or not
+ */
+ public void setDisplayFormulas(boolean show)
+ {
+ _sh.setDisplayFormulas(show);
+ }
+
+ /**
+ * Returns if formulas are displayed
+ *
+ * @return whether formulas are displayed
+ */
+ public boolean isDisplayFormulas()
+ {
+ return _sh.isDisplayFormulas();
+ }
+
+ /**
+ * Sets whether the RowColHeadings are shown in a viewer
+ *
+ * @param show whether to show RowColHeadings or not
+ */
+ public void setDisplayRowColHeadings(boolean show)
+ {
+ _sh.setDisplayRowColHeadings(show);
+ }
+
+ /**
+ * Returns if RowColHeadings are displayed.
+ * @return whether RowColHeadings are displayed
+ */
+ public boolean isDisplayRowColHeadings()
+ {
+ return _sh.isDisplayRowColHeadings();
+ }
+
+ /**
+ * Sets a page break at the indicated row
+ * @param row FIXME: Document this!
+ */
+ public void setRowBreak(int row)
+ {
+ _sh.setRowBreak(row);
+ }
+
+ /**
+ * Determines if there is a page break at the indicated row
+ * @param row FIXME: Document this!
+ * @return FIXME: Document this!
+ */
+ public boolean isRowBroken(int row)
+ {
+ return _sh.isRowBroken(row);
+ }
+
+ /**
+ * Removes the page break at the indicated row
+ * @param row
+ */
+ public void removeRowBreak(int row)
+ {
+ _sh.removeRowBreak(row);
+ }
+
+ /**
+ * Retrieves all the horizontal page breaks
+ * @return all the horizontal page breaks, or null if there are no row page breaks
+ */
+ public int[] getRowBreaks()
+ {
+ return _sh.getRowBreaks();
+ }
+
+ /**
+ * Retrieves all the vertical page breaks
+ * @return all the vertical page breaks, or null if there are no column page breaks
+ */
+ public int[] getColumnBreaks()
+ {
+ return _sh.getColumnBreaks();
+ }
+
+ /**
+ * Sets a page break at the indicated column
+ * @param column
+ */
+ public void setColumnBreak(int column)
+ {
+ _sh.setColumnBreak(column);
+ }
+
+ /**
+ * Determines if there is a page break at the indicated column
+ * @param column FIXME: Document this!
+ * @return FIXME: Document this!
+ */
+ public boolean isColumnBroken(int column)
+ {
+ return _sh.isColumnBroken(column);
+ }
+
+ /**
+ * Removes a page break at the indicated column
+ * @param column
+ */
+ public void removeColumnBreak(int column)
+ {
+ _sh.removeColumnBreak(column);
+ }
+
+ /**
+ * Expands or collapses a column group.
+ *
+ * @param columnNumber One of the columns in the group.
+ * @param collapsed true = collapse group, false = expand group.
+ */
+ public void setColumnGroupCollapsed(int columnNumber, boolean collapsed)
+ {
+ _sh.setColumnGroupCollapsed(columnNumber, collapsed);
+ }
+
+ /**
+ * Create an outline for the provided column range.
+ *
+ * @param fromColumn beginning of the column range.
+ * @param toColumn end of the column range.
+ */
+ public void groupColumn(int fromColumn, int toColumn)
+ {
+ _sh.groupColumn(fromColumn,toColumn);
+ }
+
+ /**
+ * Ungroup a range of columns that were previously groupped
+ *
+ * @param fromColumn start column (0-based)
+ * @param toColumn end column (0-based)
+ */
+ public void ungroupColumn(int fromColumn, int toColumn)
+ {
+ _sh.ungroupColumn(fromColumn, toColumn);
+ }
+
+ /**
+ * Tie a range of rows together so that they can be collapsed or expanded
+ *
+ * @param fromRow start row (0-based)
+ * @param toRow end row (0-based)
+ */
+ public void groupRow(int fromRow, int toRow)
+ {
+ _sh.groupRow(fromRow, toRow);
+ }
+
+ /**
+ * Ungroup a range of rows that were previously groupped
+ *
+ * @param fromRow start row (0-based)
+ * @param toRow end row (0-based)
+ */
+ public void ungroupRow(int fromRow, int toRow)
+ {
+ _sh.ungroupRow(fromRow, toRow);
+ }
+
+ /**
+ * Set view state of a groupped range of rows
+ *
+ * @param row start row of a groupped range of rows (0-based)
+ * @param collapse whether to expand/collapse the detail rows
+ */
+ public void setRowGroupCollapsed(int row, boolean collapse)
+ {
+ _sh.setRowGroupCollapsed(row, collapse);
+ }
+
+ /**
+ * Sets the default column style for a given column. POI will only apply this style to new cells added to the sheet.
+ *
+ * @param column the column index
+ * @param style the style to set
+ */
+ public void setDefaultColumnStyle(int column, CellStyle style)
+ {
+ _sh.setDefaultColumnStyle(column, style);
+ }
+
+ /**
+ * Adjusts the column width to fit the contents.
+ *
+ * <p>
+ * This process can be relatively slow on large sheets, so this should
+ * normally only be called once per column, at the end of your
+ * processing.
+ * </p>
+ * You can specify whether the content of merged cells should be considered or ignored.
+ * Default is to ignore merged cells.
+ *
+ * @param column the column index
+ */
+ public void autoSizeColumn(int column)
+ {
+ _sh.autoSizeColumn(column);
+ }
+
+ /**
+ * Adjusts the column width to fit the contents.
+ * <p>
+ * This process can be relatively slow on large sheets, so this should
+ * normally only be called once per column, at the end of your
+ * processing.
+ * </p>
+ * You can specify whether the content of merged cells should be considered or ignored.
+ * Default is to ignore merged cells.
+ *
+ * @param column the column index
+ * @param useMergedCells whether to use the contents of merged cells when calculating the width of the column
+ */
+ public void autoSizeColumn(int column, boolean useMergedCells)
+ {
+ _sh.autoSizeColumn(column, useMergedCells);
+ }
+
+ /**
+ * Returns cell comment for the specified row and column
+ *
+ * @return cell comment or <code>null</code> if not found
+ */
+ public Comment getCellComment(int row, int column)
+ {
+ return _sh.getCellComment(row, column);
+ }
+
+ /**
+ * Creates the top-level drawing patriarch.
+ *
+ * @return The new drawing patriarch.
+ */
+ public Drawing createDrawingPatriarch()
+ {
+ return _sh.createDrawingPatriarch();
+ }
+
+
+ /**
+ * Return the parent workbook
+ *
+ * @return the parent workbook
+ */
+ public Workbook getWorkbook()
+ {
+ return _workbook;
+ }
+
+ /**
+ * Returns the name of this sheet
+ *
+ * @return the name of this sheet
+ */
+ public String getSheetName()
+ {
+ return _sh.getSheetName();
+ }
+
+ /**
+ * Note - this is not the same as whether the sheet is focused (isActive)
+ * @return <code>true</code> if this sheet is currently selected
+ */
+ public boolean isSelected()
+ {
+ return _sh.isSelected();
+ }
+
+
+ /**
+ * Sets array formula to specified region for result.
+ *
+ * @param formula text representation of the formula
+ * @param range Region of array formula for result.
+ * @return the {@link CellRange} of cells affected by this change
+ */
+ public CellRange<? extends Cell> setArrayFormula(String formula, CellRangeAddress range)
+ {
+ return _sh.setArrayFormula(formula, range);
+ }
+
+ /**
+ * Remove a Array Formula from this sheet. All cells contained in the Array Formula range are removed as well
+ *
+ * @param cell any cell within Array Formula range
+ * @return the {@link CellRange} of cells affected by this change
+ */
+ public CellRange<? extends Cell> removeArrayFormula(Cell cell)
+ {
+ return _sh.removeArrayFormula(cell);
+ }
+
+ public DataValidationHelper getDataValidationHelper()
+ {
+ return _sh.getDataValidationHelper();
+ }
+
+ /**
+ * Creates a data validation object
+ * @param dataValidation The Data validation object settings
+ */
+ public void addValidationData(DataValidation dataValidation)
+ {
+ _sh.addValidationData(dataValidation);
+ }
+
+ /**
+ * Enable filtering for a range of cells
+ *
+ * @param range the range of cells to filter
+ */
+ public AutoFilter setAutoFilter(CellRangeAddress range)
+ {
+ return _sh.setAutoFilter(range);
+ }
+//end of interface implementation
+ /**
+ * Specifies how many rows can be accessed at most via getRow().
+ * When a new node is created via createRow() and the total number
+ * of unflushed records would exeed the specified value, then the
+ * row with the lowest index value is flushed and cannot be accessed
+ * via getRow() anymore.
+ * A value of -1 indicates unlimited access. In this case all
+ * records that have not been flushed by a call to flush() are available
+ * for random access.
+ * A value of 0 is not allowed because it would flush any newly created row
+ * without having a chance to specify any cells.
+ */
+ void setRandomAccessWindowSize(int value)
+ {
+ assert value!=0;
+ _randomAccessWindowSize=value;
+ }
+ /**
+ * Specifies how many rows can be accessed at most via getRow().
+ * The exeeding rows (if any) are flushed to the disk while rows
+ * with lower index values are flushed first.
+ */
+ void flushRows(int remaining) throws IOException
+ {
+ while(_rows.size()>remaining) flushOneRow();
+ }
+ private void flushOneRow() throws IOException
+ {
+ Map.Entry<Integer,SXSSFRow> firstEntry=_rows.firstEntry();
+ if(firstEntry!=null)
+ {
+
+ SXSSFRow row=firstEntry.getValue();
+ int rowIndex=firstEntry.getKey().intValue();
+ _writer.writeRow(rowIndex,row);
+ _rows.remove(firstEntry.getKey());
+ }
+ }
+ public void changeRowNum(SXSSFRow row, int newRowNum)
+ {
+
+ removeRow(row);
+ _rows.put(new Integer(newRowNum),row);
+ }
+
+ public int getRowNum(SXSSFRow row)
+ {
+ for(Iterator<Map.Entry<Integer,SXSSFRow>> iter=_rows.entrySet().iterator();iter.hasNext();)
+ {
+ Map.Entry<Integer,SXSSFRow> entry=iter.next();
+ if(entry.getValue()==row)
+ return entry.getKey().intValue();
+ }
+ assert false;
+ return -1;
+ }
+/*Initially copied from BigGridDemo "SpreadsheetWriter". Unlike the original code which wrote the entire document, this class only writes the "sheetData" document fragment so that it was renamed to "SheetDataWriter"*/
+ public class SheetDataWriter
+ {
+ private final File _fd;
+ private final Writer _out;
+ private int _rownum;
+ private boolean _rowContainedNullCells=false;
+ int _numberOfFlushedRows;
+ int _lowestIndexOfFlushedRows; // meaningful only of _numberOfFlushedRows>0
+ int _numberOfCellsOfLastFlushedRow; // meaningful only of _numberOfFlushedRows>0
+
+ public SheetDataWriter() throws IOException
+ {
+ _fd = File.createTempFile("sheet", ".xml");
+ _fd.deleteOnExit();
+ _out = new FileWriter(_fd);
+ _out.write("<sheetData>\n");
+ }
+ public int getNumberOfFlushedRows()
+ {
+ return _numberOfFlushedRows;
+ }
+ public int getNumberOfCellsOfLastFlushedRow()
+ {
+ return _numberOfCellsOfLastFlushedRow;
+ }
+ public int getLowestIndexOfFlushedRows()
+ {
+ return _lowestIndexOfFlushedRows;
+ }
+ protected void finalize() throws Throwable
+ {
+ _fd.delete();
+ }
+ public InputStream getWorksheetXMLInputStream() throws IOException
+ {
+ _out.write("</sheetData>");
+ _out.close();
+ return new FileInputStream(_fd);
+ }
+
+ /**
+ * Write a row to the file
+ *
+ * @param rownum 0-based row number
+ * @param row a row
+ */
+ public void writeRow(int rownum,SXSSFRow row) throws IOException
+ {
+ if(_numberOfFlushedRows==0)
+ _lowestIndexOfFlushedRows=rownum;
+ _numberOfCellsOfLastFlushedRow=row.getLastCellNum();
+ _numberOfFlushedRows++;
+ beginRow(rownum,row);
+ Iterator<Cell> cells=row.allCellsIterator();
+ int columnIndex=0;
+ while(cells.hasNext())
+ {
+ writeCell(columnIndex++,cells.next());
+ }
+ endRow();
+ }
+ void beginRow(int rownum,SXSSFRow row) throws IOException
+ {
+ _out.write("<row r=\""+(rownum+1)+"\"");
+ if(row.hasCustomHeight())
+ _out.write(" customHeight=\"true\" ht=\""+row.getHeightInPoints()+"\"");
+ _out.write(">\n");
+ this._rownum = rownum;
+ _rowContainedNullCells=false;
+ }
+
+ void endRow() throws IOException
+ {
+ _out.write("</row>\n");
+ }
+
+ public void writeCell(int columnIndex,Cell cell) throws IOException
+ {
+ if(cell==null)
+ {
+ _rowContainedNullCells=true;
+ return;
+ }
+ String ref = new CellReference(_rownum, columnIndex).formatAsString();
+ _out.write("<c r=\""+ref+"\"");
+ CellStyle cellStyle=cell.getCellStyle();
+ if(cellStyle!=null) _out.write(" s=\""+cellStyle.getIndex()+"\"");
+ int cellType=cell.getCellType();
+ switch(cellType)
+ {
+ case Cell.CELL_TYPE_BLANK:
+ {
+//TODO: What needs to be done here?
+ }
+ case Cell.CELL_TYPE_FORMULA:
+ {
+//TODO: What needs to be done here?
+ }
+ case Cell.CELL_TYPE_STRING:
+ {
+ _out.write(" t=\"inlineStr\">");
+ _out.write("<is><t>");
+ outputQuotedString(cell.getStringCellValue());
+ _out.write("</t></is>");
+ break;
+ }
+ case Cell.CELL_TYPE_NUMERIC:
+ {
+ _out.write(" t=\"n\">");
+ _out.write("<v>"+cell.getNumericCellValue()+"</v>");
+ break;
+ }
+ case Cell.CELL_TYPE_BOOLEAN:
+ {
+ _out.write(" t=\"n\">");
+ _out.write("<v>"+(cell.getBooleanCellValue()?"1":"0")+"</v>");
+ break;
+ }
+ case Cell.CELL_TYPE_ERROR:
+ {
+//TODO: What needs to be done here?
+ _out.write(" t=\"inlineStr\">");
+ _out.write("<is><t></t></is>");
+ break;
+ }
+ default:
+ {
+ assert false;
+ throw new RuntimeException("Huh?");
+ }
+ }
+ _out.write("</c>");
+ }
+//Taken from jdk1.3/src/javax/swing/text/html/HTMLWriter.java
+ protected void outputQuotedString(String s) throws IOException
+ {
+ char[] chars=s.toCharArray();
+ int last = 0;
+ int length=s.length();
+ for(int counter = 0; counter < length; counter++)
+ {
+ char c = chars[counter];
+ switch(c)
+ {
+ case '<':
+ if(counter>last)
+ {
+ _out.write(chars,last,counter-last);
+ }
+ last=counter+1;
+ _out.write("<");
+ break;
+ case '>':
+ if(counter > last)
+ {
+ _out.write(chars,last,counter-last);
+ }
+ last=counter+1;
+ _out.write(">");
+ break;
+ case '&':
+ if(counter>last)
+ {
+ _out.write(chars,last,counter-last);
+ }
+ last=counter+1;
+ _out.write("&");
+ break;
+ case '"':
+ if (counter>last)
+ {
+ _out.write(chars,last,counter-last);
+ }
+ last=counter+1;
+ _out.write(""");
+ break;
+ // Special characters
+ case '\n':
+ if(counter>last)
+ {
+ _out.write(chars,last,counter-last);
+ }
+ _out.write("
");
+ last=counter+1;
+ break;
+ case '\t':
+ if(counter>last)
+ {
+ _out.write(chars,last,counter-last);
+ }
+ _out.write("	");
+ last=counter+1;
+ break;
+ case '\r':
+ if(counter>last)
+ {
+ _out.write(chars,last,counter-last);
+ }
+ _out.write("
");
+ last=counter+1;
+ break;
+ case 0xa0:
+ if(counter>last)
+ {
+ _out.write(chars,last,counter-last);
+ }
+ _out.write(" ");
+ last=counter+1;
+ break;
+ default:
+ if(c<' '||c>127)
+ {
+ if(counter>last)
+ {
+ _out.write(chars,last,counter-last);
+ }
+ last=counter+1;
+ // If the character is outside of ascii, write the
+ // numeric value.
+ _out.write("&#");
+ _out.write(String.valueOf((int)c));
+ _out.write(";");
+ }
+ break;
+ }
+ }
+ if (last<length)
+ {
+ _out.write(chars,last,length-last);
+ }
+ }
+ }
+}
--- /dev/null
+/* ====================================================================
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+==================================================================== */
+
+package org.apache.poi.xssf.streaming;
+
+import org.apache.poi.ss.usermodel.Workbook;
+import org.apache.poi.ss.usermodel.Sheet;
+import org.apache.poi.ss.usermodel.Font;
+import org.apache.poi.ss.usermodel.CellStyle;
+import org.apache.poi.ss.usermodel.Name;
+import org.apache.poi.ss.usermodel.DataFormat;
+import org.apache.poi.ss.usermodel.PictureData;
+import org.apache.poi.ss.usermodel.CreationHelper;
+import org.apache.poi.xssf.usermodel.XSSFWorkbook;
+import org.apache.poi.xssf.usermodel.XSSFSheet;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+import java.io.FileOutputStream;
+import java.io.File;
+import java.util.List;
+import java.util.Hashtable;
+import java.util.Enumeration;
+import java.util.zip.ZipFile;
+import java.util.zip.ZipOutputStream;
+import java.util.zip.ZipEntry;
+
+import org.apache.poi.ss.formula.udf.UDFFinder;
+import org.apache.poi.ss.usermodel.Row.MissingCellPolicy;
+
+/**
+ * Streaming version of XSSFWorkbook implementing the "BigGridDemo" strategy.
+ *
+ * @author Alex Geller, Four J's Development Tools
+*/
+public class SXSSFWorkbook implements Workbook
+{
+ XSSFWorkbook _wb=new XSSFWorkbook();
+
+ Hashtable<SXSSFSheet,XSSFSheet> _sxFromXHash=new Hashtable<SXSSFSheet,XSSFSheet>();
+ Hashtable<XSSFSheet,SXSSFSheet> _xFromSxHash=new Hashtable<XSSFSheet,SXSSFSheet>();
+
+ XSSFSheet getXSSFSheet(SXSSFSheet sheet)
+ {
+ XSSFSheet result=_sxFromXHash.get(sheet);
+ assert result!=null;
+ return result;
+ }
+
+ SXSSFSheet getSXSSFSheet(XSSFSheet sheet)
+ {
+ SXSSFSheet result=_xFromSxHash.get(sheet);
+ assert result!=null;
+ return result;
+ }
+
+ void registerSheetMapping(SXSSFSheet sxSheet,XSSFSheet xSheet)
+ {
+ _sxFromXHash.put(sxSheet,xSheet);
+ _xFromSxHash.put(xSheet,sxSheet);
+ }
+ void deregisterSheetMapping(XSSFSheet xSheet)
+ {
+ SXSSFSheet sxSheet=getSXSSFSheet(xSheet);
+ _sxFromXHash.remove(sxSheet);
+ _xFromSxHash.remove(xSheet);
+ }
+ private XSSFSheet getSheetFromZipEntryName(String sheetRef)
+ {
+ Enumeration<XSSFSheet> sheets=_sxFromXHash.elements();
+ while(sheets.hasMoreElements())
+ {
+ XSSFSheet sheet=sheets.nextElement();
+ if(sheetRef.equals(sheet.getPackagePart().getPartName().getName().substring(1))) return sheet;
+ }
+ return null;
+ }
+ private void injectData(File zipfile, OutputStream out) throws IOException
+ {
+ ZipFile zip = new ZipFile(zipfile);
+
+ ZipOutputStream zos = new ZipOutputStream(out);
+
+ @SuppressWarnings("unchecked")
+ Enumeration<ZipEntry> en = (Enumeration<ZipEntry>) zip.entries();
+ while (en.hasMoreElements())
+ {
+ ZipEntry ze = en.nextElement();
+ zos.putNextEntry(new ZipEntry(ze.getName()));
+ InputStream is = zip.getInputStream(ze);
+ XSSFSheet xSheet=getSheetFromZipEntryName(ze.getName());
+ if(xSheet!=null)
+ {
+ SXSSFSheet sxSheet=getSXSSFSheet(xSheet);
+ copyStreamAndInjectWorksheet(is,zos,sxSheet.getWorksheetXMLInputStream());
+ }
+ else
+ {
+ copyStream(is, zos);
+ }
+ is.close();
+ }
+
+ zos.close();
+ }
+ private static void copyStream(InputStream in, OutputStream out) throws IOException {
+ byte[] chunk = new byte[1024];
+ int count;
+ while ((count = in.read(chunk)) >=0 ) {
+ out.write(chunk,0,count);
+ }
+ }
+ private static void copyStreamAndInjectWorksheet(InputStream in, OutputStream out,InputStream worksheetData) throws IOException {
+ InputStreamReader inReader=new InputStreamReader(in,"UTF-8"); //TODO: Is it always UTF-8 or do we need to read the xml encoding declaration in the file? If not, we should perhaps use a SAX reader instead.
+ OutputStreamWriter outWriter=new OutputStreamWriter(out,"UTF-8");
+ int c;
+ int pos=0;
+ String s="<sheetData/>";
+ int n=s.length();
+//Copy from "in" to "out" up to the string "<sheetData/>" (excluding).
+ while(((c=inReader.read())!=-1))
+ {
+ if(c==s.charAt(pos))
+ {
+ pos++;
+ if(pos==n) break;
+ }
+ else
+ {
+ if(pos>0) outWriter.write(s,0,pos);
+ if(c==s.charAt(0))
+ {
+ pos=1;
+ }
+ else
+ {
+ outWriter.write(c);
+ pos=0;
+ }
+ }
+ }
+ outWriter.flush();
+//Copy the worksheet data to "out".
+ copyStream(worksheetData,out);
+//Copy the rest of "in" to "out".
+ while(((c=inReader.read())!=-1))
+ outWriter.write(c);
+ outWriter.flush();
+ }
+
+ public XSSFWorkbook getXSSFWorkbook()
+ {
+ return _wb;
+ }
+
+//start of interface implementation
+
+ /**
+ * Convenience method to get the active sheet. The active sheet is is the sheet
+ * which is currently displayed when the workbook is viewed in Excel.
+ * 'Selected' sheet(s) is a distinct concept.
+ *
+ * @return the index of the active sheet (0-based)
+ */
+ public int getActiveSheetIndex()
+ {
+ return _wb.getActiveSheetIndex();
+ }
+
+ /**
+ * Convenience method to set the active sheet. The active sheet is is the sheet
+ * which is currently displayed when the workbook is viewed in Excel.
+ * 'Selected' sheet(s) is a distinct concept.
+ *
+ * @param sheetIndex index of the active sheet (0-based)
+ */
+ public void setActiveSheet(int sheetIndex)
+ {
+ _wb.setActiveSheet(sheetIndex);
+ }
+
+ /**
+ * Gets the first tab that is displayed in the list of tabs in excel.
+ *
+ * @return the first tab that to display in the list of tabs (0-based).
+ */
+ public int getFirstVisibleTab()
+ {
+ return _wb.getFirstVisibleTab();
+ }
+
+ /**
+ * Sets the first tab that is displayed in the list of tabs in excel.
+ *
+ * @param sheetIndex the first tab that to display in the list of tabs (0-based)
+ */
+ public void setFirstVisibleTab(int sheetIndex)
+ {
+ _wb.setFirstVisibleTab(sheetIndex);
+ }
+
+ /**
+ * Sets the order of appearance for a given sheet.
+ *
+ * @param sheetname the name of the sheet to reorder
+ * @param pos the position that we want to insert the sheet into (0 based)
+ */
+ public void setSheetOrder(String sheetname, int pos)
+ {
+ _wb.setSheetOrder(sheetname,pos);
+ }
+
+ /**
+ * Sets the tab whose data is actually seen when the sheet is opened.
+ * This may be different from the "selected sheet" since excel seems to
+ * allow you to show the data of one sheet when another is seen "selected"
+ * in the tabs (at the bottom).
+ *
+ * @see Sheet#setSelected(boolean)
+ * @param index the index of the sheet to select (0 based)
+ */
+ public void setSelectedTab(int index)
+ {
+ _wb.setSelectedTab(index);
+ }
+
+ /**
+ * Set the sheet name.
+ *
+ * @param sheet number (0 based)
+ * @throws IllegalArgumentException if the name is greater than 31 chars or contains <code>/\?*[]</code>
+ */
+ public void setSheetName(int sheet, String name)
+ {
+ _wb.setSheetName(sheet,name);
+ }
+
+ /**
+ * Set the sheet name
+ *
+ * @param sheet sheet number (0 based)
+ * @return Sheet name
+ */
+ public String getSheetName(int sheet)
+ {
+ return _wb.getSheetName(sheet);
+ }
+
+ /**
+ * Returns the index of the sheet by his name
+ *
+ * @param name the sheet name
+ * @return index of the sheet (0 based)
+ */
+ public int getSheetIndex(String name)
+ {
+ return _wb.getSheetIndex(name);
+ }
+
+ /**
+ * Returns the index of the given sheet
+ *
+ * @param sheet the sheet to look up
+ * @return index of the sheet (0 based)
+ */
+ public int getSheetIndex(Sheet sheet)
+ {
+ assert sheet instanceof SXSSFSheet;
+ return _wb.getSheetIndex(getXSSFSheet((SXSSFSheet)sheet));
+ }
+
+ /**
+ * Sreate an Sheet for this Workbook, adds it to the sheets and returns
+ * the high level representation. Use this to create new sheets.
+ *
+ * @return Sheet representing the new sheet.
+ */
+ public Sheet createSheet()
+ {
+ return createAndRegisterSXSSFSheet(_wb.createSheet());
+ }
+ SXSSFSheet createAndRegisterSXSSFSheet(XSSFSheet xSheet)
+ {
+ SXSSFSheet sxSheet=null;
+ try
+ {
+ sxSheet=new SXSSFSheet(this,xSheet);
+ }
+ catch (IOException ioe)
+ {
+ throw new RuntimeException(ioe);
+ }
+ registerSheetMapping(sxSheet,xSheet);
+ return sxSheet;
+ }
+
+ /**
+ * Create an Sheet for this Workbook, adds it to the sheets and returns
+ * the high level representation. Use this to create new sheets.
+ *
+ * @param sheetname sheetname to set for the sheet.
+ * @return Sheet representing the new sheet.
+ * @throws IllegalArgumentException if the name is greater than 31 chars or contains <code>/\?*[]</code>
+ */
+ public Sheet createSheet(String sheetname)
+ {
+ return createAndRegisterSXSSFSheet(_wb.createSheet(sheetname));
+ }
+
+ /**
+ * Create an Sheet from an existing sheet in the Workbook.
+ *
+ * @return Sheet representing the cloned sheet.
+ */
+ public Sheet cloneSheet(int sheetNum)
+ {
+ return createAndRegisterSXSSFSheet(_wb.cloneSheet(sheetNum));
+ }
+
+
+ /**
+ * Get the number of spreadsheets in the workbook
+ *
+ * @return the number of sheets
+ */
+ public int getNumberOfSheets()
+ {
+ return _wb.getNumberOfSheets();
+ }
+
+ /**
+ * Get the Sheet object at the given index.
+ *
+ * @param index of the sheet number (0-based physical & logical)
+ * @return Sheet at the provided index
+ */
+ public Sheet getSheetAt(int index)
+ {
+ return getSXSSFSheet(_wb.getSheetAt(index));
+ }
+
+ /**
+ * Get sheet with the given name
+ *
+ * @param name of the sheet
+ * @return Sheet with the name provided or <code>null</code> if it does not exist
+ */
+ public Sheet getSheet(String name)
+ {
+ return getSXSSFSheet(_wb.getSheet(name));
+ }
+
+ /**
+ * Removes sheet at the given index
+ *
+ * @param index of the sheet to remove (0-based)
+ */
+ public void removeSheetAt(int index)
+ {
+ XSSFSheet xSheet=_wb.getSheetAt(index);
+ _wb.removeSheetAt(index);
+ deregisterSheetMapping(xSheet);
+ }
+
+ /**
+ * Sets the repeating rows and columns for a sheet (as found in
+ * File->PageSetup->Sheet). This is function is included in the workbook
+ * because it creates/modifies name records which are stored at the
+ * workbook level.
+ * <p>
+ * To set just repeating columns:
+ * <pre>
+ * workbook.setRepeatingRowsAndColumns(0,0,1,-1-1);
+ * </pre>
+ * To set just repeating rows:
+ * <pre>
+ * workbook.setRepeatingRowsAndColumns(0,-1,-1,0,4);
+ * </pre>
+ * To remove all repeating rows and columns for a sheet.
+ * <pre>
+ * workbook.setRepeatingRowsAndColumns(0,-1,-1,-1,-1);
+ * </pre>
+ *
+ * @param sheetIndex 0 based index to sheet.
+ * @param startColumn 0 based start of repeating columns.
+ * @param endColumn 0 based end of repeating columns.
+ * @param startRow 0 based start of repeating rows.
+ * @param endRow 0 based end of repeating rows.
+ */
+ public void setRepeatingRowsAndColumns(int sheetIndex, int startColumn, int endColumn, int startRow, int endRow)
+ {
+ _wb.setRepeatingRowsAndColumns(sheetIndex,startColumn,endColumn,startRow,endRow);
+ }
+
+ /**
+ * Create a new Font and add it to the workbook's font table
+ *
+ * @return new font object
+ */
+ public Font createFont()
+ {
+ return _wb.createFont();
+ }
+
+ /**
+ * Finds a font that matches the one with the supplied attributes
+ *
+ * @return the font with the matched attributes or <code>null</code>
+ */
+ public Font findFont(short boldWeight, short color, short fontHeight, String name, boolean italic, boolean strikeout, short typeOffset, byte underline)
+ {
+ return _wb.findFont(boldWeight, color, fontHeight, name, italic, strikeout, typeOffset, underline);
+ }
+
+
+ /**
+ * Get the number of fonts in the font table
+ *
+ * @return number of fonts
+ */
+ public short getNumberOfFonts()
+ {
+ return _wb.getNumberOfFonts();
+ }
+
+ /**
+ * Get the font at the given index number
+ *
+ * @param idx index number (0-based)
+ * @return font at the index
+ */
+ public Font getFontAt(short idx)
+ {
+ return _wb.getFontAt(idx);
+ }
+
+ /**
+ * Create a new Cell style and add it to the workbook's style table
+ *
+ * @return the new Cell Style object
+ */
+ public CellStyle createCellStyle()
+ {
+ return _wb.createCellStyle();
+ }
+
+ /**
+ * Get the number of styles the workbook contains
+ *
+ * @return count of cell styles
+ */
+ public short getNumCellStyles()
+ {
+ return _wb.getNumCellStyles();
+ }
+
+ /**
+ * Get the cell style object at the given index
+ *
+ * @param idx index within the set of styles (0-based)
+ * @return CellStyle object at the index
+ */
+ public CellStyle getCellStyleAt(short idx)
+ {
+ return _wb.getCellStyleAt(idx);
+ }
+
+ /**
+ * Write out this workbook to an Outputstream.
+ *
+ * @param stream - the java OutputStream you wish to write to
+ * @exception IOException if anything can't be written.
+ */
+ public void write(OutputStream stream) throws IOException
+ {
+ //Save the template
+ File tmplFile = File.createTempFile("template", ".xlsx");
+ FileOutputStream os = new FileOutputStream(tmplFile);
+ _wb.write(os);
+ os.close();
+
+ //Substitute the template entries with the generated sheet data files
+ injectData(tmplFile, stream);
+ tmplFile.delete();
+ }
+
+ /**
+ * @return the total number of defined names in this workbook
+ */
+ public int getNumberOfNames()
+ {
+ return _wb.getNumberOfNames();
+ }
+
+ /**
+ * @param name the name of the defined name
+ * @return the defined name with the specified name. <code>null</code> if not found.
+ */
+ public Name getName(String name)
+ {
+ return _wb.getName(name);
+ }
+ /**
+ * @param nameIndex position of the named range (0-based)
+ * @return the defined name at the specified index
+ * @throws IllegalArgumentException if the supplied index is invalid
+ */
+ public Name getNameAt(int nameIndex)
+ {
+ return _wb.getNameAt(nameIndex);
+ }
+
+ /**
+ * Creates a new (uninitialised) defined name in this workbook
+ *
+ * @return new defined name object
+ */
+ public Name createName()
+ {
+ return _wb.createName();
+ }
+
+ /**
+ * Gets the defined name index by name<br/>
+ * <i>Note:</i> Excel defined names are case-insensitive and
+ * this method performs a case-insensitive search.
+ *
+ * @param name the name of the defined name
+ * @return zero based index of the defined name. <tt>-1</tt> if not found.
+ */
+ public int getNameIndex(String name)
+ {
+ return _wb.getNameIndex(name);
+ }
+
+ /**
+ * Remove the defined name at the specified index
+ *
+ * @param index named range index (0 based)
+ */
+ public void removeName(int index)
+ {
+ _wb.removeName(index);
+ }
+
+ /**
+ * Remove a defined name by name
+ *
+ * @param name the name of the defined name
+ */
+ public void removeName(String name)
+ {
+ _wb.removeName(name);
+ }
+
+ /**
+ * Sets the printarea for the sheet provided
+ * <p>
+ * i.e. Reference = $A$1:$B$2
+ * @param sheetIndex Zero-based sheet index (0 Represents the first sheet to keep consistent with java)
+ * @param reference Valid name Reference for the Print Area
+ */
+ public void setPrintArea(int sheetIndex, String reference)
+ {
+ _wb.setPrintArea(sheetIndex,reference);
+ }
+
+ /**
+ * For the Convenience of Java Programmers maintaining pointers.
+ * @see #setPrintArea(int, String)
+ * @param sheetIndex Zero-based sheet index (0 = First Sheet)
+ * @param startColumn Column to begin printarea
+ * @param endColumn Column to end the printarea
+ * @param startRow Row to begin the printarea
+ * @param endRow Row to end the printarea
+ */
+ public void setPrintArea(int sheetIndex, int startColumn, int endColumn, int startRow, int endRow)
+ {
+ _wb.setPrintArea(sheetIndex, startColumn, endColumn, startRow, endRow);
+ }
+
+ /**
+ * Retrieves the reference for the printarea of the specified sheet,
+ * the sheet name is appended to the reference even if it was not specified.
+ *
+ * @param sheetIndex Zero-based sheet index (0 Represents the first sheet to keep consistent with java)
+ * @return String Null if no print area has been defined
+ */
+ public String getPrintArea(int sheetIndex)
+ {
+ return _wb.getPrintArea(sheetIndex);
+ }
+
+ /**
+ * Delete the printarea for the sheet specified
+ *
+ * @param sheetIndex Zero-based sheet index (0 = First Sheet)
+ */
+ public void removePrintArea(int sheetIndex)
+ {
+ _wb.removePrintArea(sheetIndex);
+ }
+
+ /**
+ * Retrieves the current policy on what to do when
+ * getting missing or blank cells from a row.
+ * <p>
+ * The default is to return blank and null cells.
+ * {@link MissingCellPolicy}
+ * </p>
+ */
+ public MissingCellPolicy getMissingCellPolicy()
+ {
+ return _wb.getMissingCellPolicy();
+ }
+
+ /**
+ * Sets the policy on what to do when
+ * getting missing or blank cells from a row.
+ *
+ * This will then apply to all calls to
+ * {@link org.apache.poi.ss.usermodel.Row#getCell(int)}. See
+ * {@link MissingCellPolicy}
+ */
+ public void setMissingCellPolicy(MissingCellPolicy missingCellPolicy)
+ {
+ _wb.setMissingCellPolicy(missingCellPolicy);
+ }
+
+ /**
+ * Returns the instance of DataFormat for this workbook.
+ *
+ * @return the DataFormat object
+ */
+ public DataFormat createDataFormat()
+ {
+ return _wb.createDataFormat();
+ }
+
+ /**
+ * Adds a picture to the workbook.
+ *
+ * @param pictureData The bytes of the picture
+ * @param format The format of the picture.
+ *
+ * @return the index to this picture (1 based).
+ * @see #PICTURE_TYPE_EMF
+ * @see #PICTURE_TYPE_WMF
+ * @see #PICTURE_TYPE_PICT
+ * @see #PICTURE_TYPE_JPEG
+ * @see #PICTURE_TYPE_PNG
+ * @see #PICTURE_TYPE_DIB
+ */
+ public int addPicture(byte[] pictureData, int format)
+ {
+ return _wb.addPicture(pictureData,format);
+ }
+
+ /**
+ * Gets all pictures from the Workbook.
+ *
+ * @return the list of pictures (a list of {@link PictureData} objects.)
+ */
+ public List<? extends PictureData> getAllPictures()
+ {
+ return _wb.getAllPictures();
+ }
+
+ /**
+ * Returns an object that handles instantiating concrete
+ * classes of the various instances one needs for HSSF and XSSF.
+ */
+ public CreationHelper getCreationHelper()
+ {
+ return _wb.getCreationHelper();
+ }
+
+ /**
+ * @return <code>false</code> if this workbook is not visible in the GUI
+ */
+ public boolean isHidden()
+ {
+ return _wb.isHidden();
+ }
+
+ /**
+ * @param hiddenFlag pass <code>false</code> to make the workbook visible in the GUI
+ */
+ public void setHidden(boolean hiddenFlag)
+ {
+ _wb.setHidden(hiddenFlag);
+ }
+
+ /**
+ * Check whether a sheet is hidden.
+ * <p>
+ * Note that a sheet could instead be set to be very hidden, which is different
+ * ({@link #isSheetVeryHidden(int)})
+ * </p>
+ * @param sheetIx Number
+ * @return <code>true</code> if sheet is hidden
+ */
+ public boolean isSheetHidden(int sheetIx)
+ {
+ return _wb.isSheetHidden(sheetIx);
+ }
+
+ /**
+ * Check whether a sheet is very hidden.
+ * <p>
+ * This is different from the normal hidden status
+ * ({@link #isSheetHidden(int)})
+ * </p>
+ * @param sheetIx sheet index to check
+ * @return <code>true</code> if sheet is very hidden
+ */
+ public boolean isSheetVeryHidden(int sheetIx)
+ {
+ return _wb.isSheetVeryHidden(sheetIx);
+ }
+
+ /**
+ * Hide or unhide a sheet
+ *
+ * @param sheetIx the sheet index (0-based)
+ * @param hidden True to mark the sheet as hidden, false otherwise
+ */
+ public void setSheetHidden(int sheetIx, boolean hidden)
+ {
+ _wb.setSheetHidden(sheetIx,hidden);
+ }
+
+ /**
+ * Hide or unhide a sheet.
+ *
+ * <ul>
+ * <li>0 - visible. </li>
+ * <li>1 - hidden. </li>
+ * <li>2 - very hidden.</li>
+ * </ul>
+ * @param sheetIx the sheet index (0-based)
+ * @param hidden one of the following <code>Workbook</code> constants:
+ * <code>Workbook.SHEET_STATE_VISIBLE</code>,
+ * <code>Workbook.SHEET_STATE_HIDDEN</code>, or
+ * <code>Workbook.SHEET_STATE_VERY_HIDDEN</code>.
+ * @throws IllegalArgumentException if the supplied sheet index or state is invalid
+ */
+ public void setSheetHidden(int sheetIx, int hidden)
+ {
+ _wb.setSheetHidden(sheetIx,hidden);
+ }
+ /**
+ * Register a new toolpack in this workbook.
+ *
+ * @param toopack the toolpack to register
+ */
+ public void addToolPack(UDFFinder toopack)
+ {
+ _wb.addToolPack(toopack);
+ }
+//end of interface implementation
+}