2008-01-16 11:08:22 -05:00
|
|
|
/* ====================================================================
|
|
|
|
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.usermodel;
|
|
|
|
|
|
|
|
import java.util.Calendar;
|
|
|
|
import java.util.Date;
|
|
|
|
|
|
|
|
import org.apache.poi.hssf.usermodel.HSSFDateUtil;
|
|
|
|
import org.apache.poi.ss.usermodel.Cell;
|
|
|
|
import org.apache.poi.ss.usermodel.CellStyle;
|
|
|
|
import org.apache.poi.ss.usermodel.Comment;
|
2008-04-05 17:43:53 -04:00
|
|
|
import org.apache.poi.ss.usermodel.Hyperlink;
|
2008-01-16 11:08:22 -05:00
|
|
|
import org.apache.poi.ss.usermodel.RichTextString;
|
|
|
|
import org.apache.poi.ss.usermodel.SharedStringSource;
|
2008-03-16 20:10:17 -04:00
|
|
|
import org.apache.poi.ss.usermodel.StylesSource;
|
2008-03-30 12:25:52 -04:00
|
|
|
import org.apache.poi.util.POILogFactory;
|
|
|
|
import org.apache.poi.util.POILogger;
|
2008-04-05 13:42:10 -04:00
|
|
|
import org.apache.poi.ss.util.CellReference;
|
2008-01-16 11:08:22 -05:00
|
|
|
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTCell;
|
|
|
|
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTCellFormula;
|
|
|
|
import org.openxmlformats.schemas.spreadsheetml.x2006.main.STCellType;
|
|
|
|
|
|
|
|
|
|
|
|
public class XSSFCell implements Cell {
|
|
|
|
|
|
|
|
private static final String FALSE_AS_STRING = "0";
|
|
|
|
private static final String TRUE_AS_STRING = "1";
|
|
|
|
private final CTCell cell;
|
|
|
|
private final XSSFRow row;
|
2008-03-29 18:45:11 -04:00
|
|
|
private int cellNum;
|
2008-02-13 08:43:42 -05:00
|
|
|
private SharedStringSource sharedStringSource;
|
2008-03-16 20:10:17 -04:00
|
|
|
private StylesSource stylesSource;
|
2008-01-16 11:08:22 -05:00
|
|
|
|
2008-03-30 12:25:52 -04:00
|
|
|
private POILogger logger = POILogFactory.getLogger(XSSFCell.class);
|
|
|
|
|
2008-01-16 11:08:22 -05:00
|
|
|
/**
|
|
|
|
* Create a new XSSFCell. This method is protected to be used only by
|
|
|
|
* tests.
|
|
|
|
*/
|
|
|
|
protected XSSFCell(XSSFRow row) {
|
|
|
|
this(row, CTCell.Factory.newInstance());
|
|
|
|
}
|
|
|
|
|
|
|
|
public XSSFCell(XSSFRow row, CTCell cell) {
|
|
|
|
this.cell = cell;
|
|
|
|
this.row = row;
|
2008-02-07 10:44:32 -05:00
|
|
|
if (cell.getR() != null) {
|
|
|
|
this.cellNum = parseCellNum(cell.getR());
|
|
|
|
}
|
2008-02-13 08:43:42 -05:00
|
|
|
this.sharedStringSource = row.getSheet().getWorkbook().getSharedStringSource();
|
2008-03-16 20:10:17 -04:00
|
|
|
this.stylesSource = row.getSheet().getWorkbook().getStylesSource();
|
2008-01-16 11:08:22 -05:00
|
|
|
}
|
2008-02-13 08:43:42 -05:00
|
|
|
|
|
|
|
protected SharedStringSource getSharedStringSource() {
|
|
|
|
return this.sharedStringSource;
|
2008-01-16 11:08:22 -05:00
|
|
|
}
|
2008-03-16 20:10:17 -04:00
|
|
|
protected StylesSource getStylesSource() {
|
|
|
|
return this.stylesSource;
|
|
|
|
}
|
2008-01-16 11:08:22 -05:00
|
|
|
|
|
|
|
public boolean getBooleanCellValue() {
|
|
|
|
if (STCellType.B != cell.getT()) {
|
|
|
|
throw new NumberFormatException("You cannot get a boolean value from a non-boolean cell");
|
|
|
|
}
|
|
|
|
if (cell.isSetV()) {
|
|
|
|
return (TRUE_AS_STRING.equals(this.cell.getV()));
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
public Comment getCellComment() {
|
2008-03-08 06:19:23 -05:00
|
|
|
return row.getSheet().getCellComment(row.getRowNum(), getCellNum());
|
2008-01-16 11:08:22 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
public String getCellFormula() {
|
2008-03-08 13:06:41 -05:00
|
|
|
if(this.cell.getF() == null) {
|
2008-01-16 11:08:22 -05:00
|
|
|
throw new NumberFormatException("You cannot get a formula from a non-formula cell");
|
|
|
|
}
|
|
|
|
return this.cell.getF().getStringValue();
|
|
|
|
}
|
|
|
|
|
|
|
|
public short getCellNum() {
|
2008-03-29 18:45:11 -04:00
|
|
|
return (short)this.cellNum;
|
2008-01-16 11:08:22 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
public CellStyle getCellStyle() {
|
2008-03-22 11:09:37 -04:00
|
|
|
// Zero is the empty default
|
2008-03-16 20:10:17 -04:00
|
|
|
if(this.cell.getS() > 0) {
|
|
|
|
return stylesSource.getStyleAt(this.cell.getS());
|
|
|
|
}
|
|
|
|
return null;
|
2008-01-16 11:08:22 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
public int getCellType() {
|
2008-03-08 13:06:41 -05:00
|
|
|
// Detecting formulas is quite pesky,
|
|
|
|
// as they don't get their type set
|
|
|
|
if(this.cell.getF() != null) {
|
|
|
|
return CELL_TYPE_FORMULA;
|
|
|
|
}
|
|
|
|
|
2008-01-16 11:08:22 -05:00
|
|
|
switch (this.cell.getT().intValue()) {
|
|
|
|
case STCellType.INT_B:
|
|
|
|
return CELL_TYPE_BOOLEAN;
|
|
|
|
case STCellType.INT_N:
|
|
|
|
return CELL_TYPE_NUMERIC;
|
|
|
|
case STCellType.INT_E:
|
|
|
|
return CELL_TYPE_ERROR;
|
|
|
|
case STCellType.INT_S: // String is in shared strings
|
|
|
|
case STCellType.INT_INLINE_STR: // String is inline in cell
|
|
|
|
return CELL_TYPE_STRING;
|
|
|
|
case STCellType.INT_STR:
|
|
|
|
return CELL_TYPE_FORMULA;
|
|
|
|
default:
|
|
|
|
throw new IllegalStateException("Illegal cell type: " + this.cell.getT());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public Date getDateCellValue() {
|
|
|
|
if (STCellType.N == this.cell.getT() || STCellType.STR == this.cell.getT()) {
|
|
|
|
double value = this.getNumericCellValue();
|
|
|
|
if (false /* book.isUsing1904DateWindowing() */) { // FIXME
|
|
|
|
return HSSFDateUtil.getJavaDate(value,true);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
return HSSFDateUtil.getJavaDate(value,false);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
throw new NumberFormatException("You cannot get a date value from a cell of type " + this.cell.getT());
|
|
|
|
}
|
|
|
|
|
2008-03-30 10:16:22 -04:00
|
|
|
/**
|
|
|
|
* Returns the error message, such as #VALUE!
|
|
|
|
*/
|
|
|
|
public String getErrorCellString() {
|
|
|
|
if (STCellType.E != cell.getT()) {
|
|
|
|
throw new NumberFormatException("You cannot get a error value from a non-error cell");
|
|
|
|
}
|
|
|
|
if (this.cell.isSetV()) {
|
|
|
|
return this.cell.getV();
|
|
|
|
}
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
/**
|
|
|
|
* Returns the error type, in the same way that
|
2008-03-30 12:25:52 -04:00
|
|
|
* HSSFCell does. See {@link Cell} for details
|
2008-03-30 10:16:22 -04:00
|
|
|
*/
|
2008-01-16 11:08:22 -05:00
|
|
|
public byte getErrorCellValue() {
|
|
|
|
if (STCellType.E != cell.getT()) {
|
|
|
|
throw new NumberFormatException("You cannot get a error value from a non-error cell");
|
|
|
|
}
|
|
|
|
if (this.cell.isSetV()) {
|
2008-03-30 10:16:22 -04:00
|
|
|
String errS = this.cell.getV();
|
2008-03-30 12:25:52 -04:00
|
|
|
if(errS.equals(Cell.ERROR_NULL.getStringRepr())) {
|
|
|
|
return Cell.ERROR_NULL.getType();
|
2008-03-30 10:16:22 -04:00
|
|
|
}
|
2008-03-30 12:25:52 -04:00
|
|
|
if(errS.equals(Cell.ERROR_DIV0.getStringRepr())) {
|
|
|
|
return Cell.ERROR_DIV0.getType();
|
2008-03-30 10:16:22 -04:00
|
|
|
}
|
2008-03-30 12:25:52 -04:00
|
|
|
if(errS.equals(Cell.ERROR_VALUE.getStringRepr())) {
|
|
|
|
return Cell.ERROR_VALUE.getType();
|
2008-03-30 10:16:22 -04:00
|
|
|
}
|
2008-03-30 12:25:52 -04:00
|
|
|
if(errS.equals(Cell.ERROR_REF.getStringRepr())) {
|
|
|
|
return Cell.ERROR_REF.getType();
|
2008-03-30 10:16:22 -04:00
|
|
|
}
|
2008-03-30 12:25:52 -04:00
|
|
|
if(errS.equals(Cell.ERROR_NAME.getStringRepr())) {
|
|
|
|
return Cell.ERROR_NAME.getType();
|
2008-03-30 10:16:22 -04:00
|
|
|
}
|
2008-03-30 12:25:52 -04:00
|
|
|
if(errS.equals(Cell.ERROR_NUM.getStringRepr())) {
|
|
|
|
return Cell.ERROR_NUM.getType();
|
2008-03-30 10:16:22 -04:00
|
|
|
}
|
2008-03-30 12:25:52 -04:00
|
|
|
return Cell.ERROR_NA.getType();
|
2008-01-16 11:08:22 -05:00
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
public double getNumericCellValue() {
|
|
|
|
if (STCellType.N != cell.getT() && STCellType.STR != cell.getT()) {
|
|
|
|
throw new NumberFormatException("You cannot get a numeric value from a non-numeric cell");
|
|
|
|
}
|
|
|
|
if (this.cell.isSetV()) {
|
|
|
|
return Double.parseDouble(this.cell.getV());
|
|
|
|
}
|
|
|
|
return Double.NaN;
|
|
|
|
}
|
|
|
|
|
|
|
|
public RichTextString getRichStringCellValue() {
|
|
|
|
if(this.cell.getT() == STCellType.INLINE_STR) {
|
|
|
|
if(this.cell.isSetV()) {
|
|
|
|
return new XSSFRichTextString(this.cell.getV());
|
|
|
|
} else {
|
|
|
|
return new XSSFRichTextString("");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if(this.cell.getT() == STCellType.S) {
|
|
|
|
if(this.cell.isSetV()) {
|
|
|
|
int sRef = Integer.parseInt(this.cell.getV());
|
2008-02-13 08:43:42 -05:00
|
|
|
return new XSSFRichTextString(getSharedStringSource().getSharedStringAt(sRef));
|
2008-01-16 11:08:22 -05:00
|
|
|
} else {
|
|
|
|
return new XSSFRichTextString("");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
throw new NumberFormatException("You cannot get a string value from a non-string cell");
|
|
|
|
}
|
|
|
|
|
|
|
|
public void setAsActiveCell() {
|
2008-03-08 06:19:23 -05:00
|
|
|
row.getSheet().setActiveCell(cell.getR());
|
2008-01-16 11:08:22 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
public void setCellComment(Comment comment) {
|
2008-04-05 13:42:10 -04:00
|
|
|
String cellRef =
|
|
|
|
new CellReference(row.getRowNum(), getCellNum()).formatAsString();
|
2008-03-08 06:19:23 -05:00
|
|
|
row.getSheet().setCellComment(cellRef, (XSSFComment)comment);
|
2008-01-16 11:08:22 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
public void setCellErrorValue(byte value) {
|
2008-03-30 12:25:52 -04:00
|
|
|
if(value == Cell.ERROR_DIV0.getType()) {
|
|
|
|
setCellErrorValue(Cell.ERROR_DIV0);
|
|
|
|
} else if(value == Cell.ERROR_NA.getType()) {
|
|
|
|
setCellErrorValue(Cell.ERROR_NA);
|
|
|
|
} else if(value == Cell.ERROR_NAME.getType()) {
|
|
|
|
setCellErrorValue(Cell.ERROR_NAME);
|
|
|
|
} else if(value == Cell.ERROR_NULL.getType()) {
|
|
|
|
setCellErrorValue(Cell.ERROR_NULL);
|
|
|
|
} else if(value == Cell.ERROR_NUM.getType()) {
|
|
|
|
setCellErrorValue(Cell.ERROR_NUM);
|
|
|
|
} else if(value == Cell.ERROR_REF.getType()) {
|
|
|
|
setCellErrorValue(Cell.ERROR_REF);
|
|
|
|
} else if(value == Cell.ERROR_VALUE.getType()) {
|
|
|
|
setCellErrorValue(Cell.ERROR_VALUE);
|
|
|
|
} else {
|
|
|
|
logger.log(POILogger.WARN, "Unknown error type " + value + " specified, treating as #N/A");
|
|
|
|
setCellErrorValue(Cell.ERROR_NA);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
public void setCellErrorValue(CELL_ERROR_TYPE errorType) {
|
2008-01-16 11:08:22 -05:00
|
|
|
if ((this.cell.getT() != STCellType.E) && (this.cell.getT() != STCellType.STR))
|
|
|
|
{
|
|
|
|
this.cell.setT(STCellType.E);
|
|
|
|
}
|
2008-03-30 12:25:52 -04:00
|
|
|
this.cell.setV( errorType.getStringRepr() );
|
2008-01-16 11:08:22 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public void setCellFormula(String formula) {
|
|
|
|
if (this.cell.getT() != STCellType.STR)
|
|
|
|
{
|
|
|
|
this.cell.setT(STCellType.STR);
|
|
|
|
}
|
|
|
|
CTCellFormula f = CTCellFormula.Factory.newInstance();
|
|
|
|
f.setStringValue(formula);
|
|
|
|
this.cell.setF(f);
|
|
|
|
// XXX: is this correct? Should we recompute the value when the formula changes?
|
|
|
|
if (this.cell.isSetV()) {
|
|
|
|
this.cell.unsetV();
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2008-03-29 18:45:11 -04:00
|
|
|
public void setCellNum(int num) {
|
|
|
|
setCellNum((short)num);
|
|
|
|
}
|
2008-01-16 11:08:22 -05:00
|
|
|
public void setCellNum(short num) {
|
2008-02-07 10:44:32 -05:00
|
|
|
checkBounds(num);
|
2008-01-16 11:08:22 -05:00
|
|
|
this.cellNum = num;
|
2008-02-07 10:44:32 -05:00
|
|
|
this.cell.setR(formatPosition());
|
|
|
|
}
|
|
|
|
|
|
|
|
protected static short parseCellNum(String r) {
|
|
|
|
r = r.split("\\d+")[0];
|
|
|
|
if (r.length() == 1) {
|
|
|
|
return (short) (r.charAt(0) - 'A');
|
|
|
|
} else {
|
|
|
|
return (short) (r.charAt(1) - 'A' + 26 * (r.charAt(0) - '@'));
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
protected String formatPosition() {
|
|
|
|
int col = this.getCellNum();
|
|
|
|
String result = Character.valueOf((char) (col % 26 + 'A')).toString();
|
|
|
|
if (col >= 26){
|
|
|
|
col = col / 26;
|
|
|
|
result = Character.valueOf((char) (col + '@')) + result;
|
|
|
|
}
|
|
|
|
result = result + String.valueOf(row.getRowNum() + 1);
|
|
|
|
return result;
|
2008-01-16 11:08:22 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
public void setCellStyle(CellStyle style) {
|
2008-03-22 10:38:43 -04:00
|
|
|
if(style == null) {
|
|
|
|
this.cell.setS(0);
|
|
|
|
} else {
|
|
|
|
this.cell.setS(
|
|
|
|
row.getSheet().getWorkbook().getStylesSource().putStyle(style)
|
|
|
|
);
|
|
|
|
}
|
2008-01-16 11:08:22 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
public void setCellType(int cellType) {
|
|
|
|
switch (cellType) {
|
|
|
|
case CELL_TYPE_BOOLEAN:
|
|
|
|
this.cell.setT(STCellType.B);
|
|
|
|
break;
|
|
|
|
case CELL_TYPE_NUMERIC:
|
|
|
|
this.cell.setT(STCellType.N);
|
|
|
|
break;
|
|
|
|
case CELL_TYPE_ERROR:
|
|
|
|
this.cell.setT(STCellType.E);
|
|
|
|
break;
|
|
|
|
case CELL_TYPE_STRING:
|
|
|
|
this.cell.setT(STCellType.S);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
throw new IllegalArgumentException("Illegal type: " + cellType);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public void setCellValue(double value) {
|
|
|
|
if ((this.cell.getT() != STCellType.N) && (this.cell.getT() != STCellType.STR))
|
|
|
|
{
|
|
|
|
this.cell.setT(STCellType.N);
|
|
|
|
}
|
|
|
|
this.cell.setV(String.valueOf(value));
|
|
|
|
}
|
|
|
|
|
|
|
|
public void setCellValue(Date value) {
|
|
|
|
setCellValue(HSSFDateUtil.getExcelDate(value, false /*this.book.isUsing1904DateWindowing()*/)); // FIXME
|
|
|
|
}
|
|
|
|
|
|
|
|
public void setCellValue(Calendar value) {
|
|
|
|
// TODO Auto-generated method stub
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
public void setCellValue(RichTextString value) {
|
|
|
|
if(this.cell.getT() == STCellType.INLINE_STR) {
|
|
|
|
this.cell.setV(value.getString());
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if(this.cell.getT() != STCellType.S) {
|
|
|
|
this.cell.setT(STCellType.S);
|
|
|
|
}
|
2008-02-13 08:43:42 -05:00
|
|
|
int sRef = getSharedStringSource().putSharedString(value.getString());
|
2008-01-16 11:08:22 -05:00
|
|
|
this.cell.setV(Integer.toString(sRef));
|
|
|
|
}
|
|
|
|
|
|
|
|
public void setCellValue(boolean value) {
|
|
|
|
if ((this.cell.getT() != STCellType.B) && (this.cell.getT() != STCellType.STR))
|
|
|
|
{
|
|
|
|
this.cell.setT(STCellType.B);
|
|
|
|
}
|
|
|
|
this.cell.setV(value ? TRUE_AS_STRING : FALSE_AS_STRING);
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public String toString() {
|
|
|
|
return "[" + this.row.getRowNum() + "," + this.getCellNum() + "] " + this.cell.getV();
|
|
|
|
}
|
2008-03-08 13:06:41 -05:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Returns the raw, underlying ooxml value for the cell
|
|
|
|
*/
|
|
|
|
public String getRawValue() {
|
|
|
|
return this.cell.getV();
|
|
|
|
}
|
2008-01-16 11:08:22 -05:00
|
|
|
|
2008-02-07 10:44:32 -05:00
|
|
|
/**
|
|
|
|
* @throws RuntimeException if the bounds are exceeded.
|
|
|
|
*/
|
|
|
|
private void checkBounds(int cellNum) {
|
|
|
|
if (cellNum > 255) {
|
|
|
|
throw new RuntimeException("You cannot have more than 255 columns "+
|
|
|
|
"in a given row (IV). Because Excel can't handle it");
|
|
|
|
}
|
|
|
|
else if (cellNum < 0) {
|
|
|
|
throw new RuntimeException("You cannot reference columns with an index of less then 0.");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-03-16 12:24:23 -04:00
|
|
|
/**
|
|
|
|
* Creates an XSSFRichTextString for you.
|
|
|
|
*/
|
|
|
|
public RichTextString createRichTextString(String text) {
|
|
|
|
return new XSSFRichTextString(text);
|
|
|
|
}
|
2008-04-05 17:43:53 -04:00
|
|
|
|
|
|
|
public Hyperlink getHyperlink() {
|
|
|
|
return row.getSheet().getHyperlink(row.getRowNum(), cellNum);
|
|
|
|
}
|
|
|
|
public void setHyperlink(Hyperlink hyperlink) {
|
|
|
|
row.getSheet().setCellHyperlink((XSSFHyperlink)hyperlink);
|
|
|
|
}
|
2008-01-16 11:08:22 -05:00
|
|
|
}
|