Fix cell.getRichStringCellValue() for formula cells with string results
[poi.git] / src / java / org / apache / poi / hssf / usermodel / HSSFCell.java
blobdd1770f56d287ebc70b08bfe41666b988707ad30
1 /* ====================================================================
2 Licensed to the Apache Software Foundation (ASF) under one or more
3 contributor license agreements. See the NOTICE file distributed with
4 this work for additional information regarding copyright ownership.
5 The ASF licenses this file to You under the Apache License, Version 2.0
6 (the "License"); you may not use this file except in compliance with
7 the License. You may obtain a copy of the License at
9 http://www.apache.org/licenses/LICENSE-2.0
11 Unless required by applicable law or agreed to in writing, software
12 distributed under the License is distributed on an "AS IS" BASIS,
13 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 See the License for the specific language governing permissions and
15 limitations under the License.
16 ==================================================================== */
21 * Cell.java
23 * Created on September 30, 2001, 3:46 PM
25 package org.apache.poi.hssf.usermodel;
27 import java.text.DateFormat;
28 import java.text.SimpleDateFormat;
29 import java.util.Calendar;
30 import java.util.Date;
31 import java.util.HashMap;
32 import java.util.Iterator;
34 import org.apache.poi.hssf.model.FormulaParser;
35 import org.apache.poi.hssf.model.Sheet;
36 import org.apache.poi.hssf.model.Workbook;
37 import org.apache.poi.hssf.record.*;
38 import org.apache.poi.hssf.record.aggregates.FormulaRecordAggregate;
39 import org.apache.poi.hssf.record.formula.Ptg;
41 /**
42 * High level representation of a cell in a row of a spreadsheet.
43 * Cells can be numeric, formula-based or string-based (text). The cell type
44 * specifies this. String cells cannot conatin numbers and numeric cells cannot
45 * contain strings (at least according to our model). Client apps should do the
46 * conversions themselves. Formula cells have the formula string, as well as
47 * the formula result, which can be numeric or string.
48 * <p>
49 * Cells should have their number (0 based) before being added to a row. Only
50 * cells that have values should be added.
51 * <p>
53 * @author Andrew C. Oliver (acoliver at apache dot org)
54 * @author Dan Sherman (dsherman at isisph.com)
55 * @author Brian Sanders (kestrel at burdell dot org) Active Cell support
56 * @author Yegor Kozlov cell comments support
57 * @version 1.0-pre
60 public class HSSFCell
63 /**
64 * Numeric Cell type (0)
65 * @see #setCellType(int)
66 * @see #getCellType()
69 public final static int CELL_TYPE_NUMERIC = 0;
71 /**
72 * String Cell type (1)
73 * @see #setCellType(int)
74 * @see #getCellType()
77 public final static int CELL_TYPE_STRING = 1;
79 /**
80 * Formula Cell type (2)
81 * @see #setCellType(int)
82 * @see #getCellType()
85 public final static int CELL_TYPE_FORMULA = 2;
87 /**
88 * Blank Cell type (3)
89 * @see #setCellType(int)
90 * @see #getCellType()
93 public final static int CELL_TYPE_BLANK = 3;
95 /**
96 * Boolean Cell type (4)
97 * @see #setCellType(int)
98 * @see #getCellType()
101 public final static int CELL_TYPE_BOOLEAN = 4;
104 * Error Cell type (5)
105 * @see #setCellType(int)
106 * @see #getCellType()
109 public final static int CELL_TYPE_ERROR = 5;
110 public final static short ENCODING_UNCHANGED = -1;
111 public final static short ENCODING_COMPRESSED_UNICODE = 0;
112 public final static short ENCODING_UTF_16 = 1;
113 private int cellType;
114 private HSSFRichTextString stringValue;
115 private short encoding = ENCODING_UNCHANGED;
116 private HSSFWorkbook book;
117 private Sheet sheet;
118 private CellValueRecordInterface record;
119 private HSSFComment comment;
122 * Creates new Cell - Should only be called by HSSFRow. This creates a cell
123 * from scratch.
124 * <p>
125 * When the cell is initially created it is set to CELL_TYPE_BLANK. Cell types
126 * can be changed/overwritten by calling setCellValue with the appropriate
127 * type as a parameter although conversions from one type to another may be
128 * prohibited.
130 * @param book - Workbook record of the workbook containing this cell
131 * @param sheet - Sheet record of the sheet containing this cell
132 * @param row - the row of this cell
133 * @param col - the column for this cell
135 * @see org.apache.poi.hssf.usermodel.HSSFRow#createCell(short)
138 //protected HSSFCell(Workbook book, Sheet sheet, short row, short col)
139 protected HSSFCell(HSSFWorkbook book, Sheet sheet, int row, short col)
141 checkBounds(col);
142 stringValue = null;
143 this.book = book;
144 this.sheet = sheet;
146 // Relying on the fact that by default the cellType is set to 0 which
147 // is different to CELL_TYPE_BLANK hence the following method call correctly
148 // creates a new blank cell.
149 short xfindex = sheet.getXFIndexForColAt(col);
150 setCellType(CELL_TYPE_BLANK, false, row, col,xfindex);
154 * Creates new Cell - Should only be called by HSSFRow. This creates a cell
155 * from scratch.
157 * @param book - Workbook record of the workbook containing this cell
158 * @param sheet - Sheet record of the sheet containing this cell
159 * @param row - the row of this cell
160 * @param col - the column for this cell
161 * @param type - CELL_TYPE_NUMERIC, CELL_TYPE_STRING, CELL_TYPE_FORMULA, CELL_TYPE_BLANK,
162 * CELL_TYPE_BOOLEAN, CELL_TYPE_ERROR
163 * Type of cell
164 * @see org.apache.poi.hssf.usermodel.HSSFRow#createCell(short,int)
167 //protected HSSFCell(Workbook book, Sheet sheet, short row, short col,
168 protected HSSFCell(HSSFWorkbook book, Sheet sheet, int row, short col,
169 int type)
171 checkBounds(col);
172 cellType = -1; // Force 'setCellType' to create a first Record
173 stringValue = null;
174 this.book = book;
175 this.sheet = sheet;
177 short xfindex = sheet.getXFIndexForColAt(col);
178 setCellType(type,false,row,col,xfindex);
182 * Creates an HSSFCell from a CellValueRecordInterface. HSSFSheet uses this when
183 * reading in cells from an existing sheet.
185 * @param book - Workbook record of the workbook containing this cell
186 * @param sheet - Sheet record of the sheet containing this cell
187 * @param cval - the Cell Value Record we wish to represent
190 //protected HSSFCell(Workbook book, Sheet sheet, short row,
191 protected HSSFCell(HSSFWorkbook book, Sheet sheet, int row,
192 CellValueRecordInterface cval)
194 record = cval;
195 cellType = determineType(cval);
196 stringValue = null;
197 this.book = book;
198 this.sheet = sheet;
199 switch (cellType)
201 case CELL_TYPE_STRING :
202 stringValue = new HSSFRichTextString(book.getWorkbook(), (LabelSSTRecord ) cval);
203 break;
205 case CELL_TYPE_BLANK :
206 break;
208 case CELL_TYPE_FORMULA :
209 stringValue=new HSSFRichTextString(((FormulaRecordAggregate) cval).getStringValue());
210 break;
212 ExtendedFormatRecord xf = book.getWorkbook().getExFormatAt(cval.getXFIndex());
214 setCellStyle(new HSSFCellStyle(( short ) cval.getXFIndex(), xf, book));
218 * private constructor to prevent blank construction
220 private HSSFCell()
225 * used internally -- given a cell value record, figure out its type
227 private int determineType(CellValueRecordInterface cval)
229 Record record = ( Record ) cval;
230 int sid = record.getSid();
231 int retval = 0;
233 switch (sid)
236 case NumberRecord.sid :
237 retval = HSSFCell.CELL_TYPE_NUMERIC;
238 break;
240 case BlankRecord.sid :
241 retval = HSSFCell.CELL_TYPE_BLANK;
242 break;
244 case LabelSSTRecord.sid :
245 retval = HSSFCell.CELL_TYPE_STRING;
246 break;
248 case FormulaRecordAggregate.sid :
249 retval = HSSFCell.CELL_TYPE_FORMULA;
250 break;
252 case BoolErrRecord.sid :
253 BoolErrRecord boolErrRecord = ( BoolErrRecord ) record;
255 retval = (boolErrRecord.isBoolean())
256 ? HSSFCell.CELL_TYPE_BOOLEAN
257 : HSSFCell.CELL_TYPE_ERROR;
258 break;
260 return retval;
264 * Returns the Workbook that this Cell is bound to
265 * @return
267 protected Workbook getBoundWorkbook() {
268 return book.getWorkbook();
272 * Set the cell's number within the row (0 based).
273 * @param num short the cell number
274 * @deprecated Doesn't update the row's idea of what cell this is, use {@link HSSFRow#moveCell(HSSFCell, short)} instead
276 public void setCellNum(short num)
278 record.setColumn(num);
282 * Updates the cell record's idea of what
283 * column it belongs in (0 based)
284 * @param num the new cell number
286 protected void updateCellNum(short num)
288 record.setColumn(num);
292 * get the cell's number within the row
293 * @return short reperesenting the column number (logical!)
296 public short getCellNum()
298 return record.getColumn();
302 * set the cells type (numeric, formula or string)
303 * @see #CELL_TYPE_NUMERIC
304 * @see #CELL_TYPE_STRING
305 * @see #CELL_TYPE_FORMULA
306 * @see #CELL_TYPE_BLANK
307 * @see #CELL_TYPE_BOOLEAN
308 * @see #CELL_TYPE_ERROR
311 public void setCellType(int cellType)
313 int row=record.getRow();
314 short col=record.getColumn();
315 short styleIndex=record.getXFIndex();
316 setCellType(cellType, true, row, col, styleIndex);
320 * sets the cell type. The setValue flag indicates whether to bother about
321 * trying to preserve the current value in the new record if one is created.
322 * <p>
323 * The @see #setCellValue method will call this method with false in setValue
324 * since it will overwrite the cell value later
328 private void setCellType(int cellType, boolean setValue, int row,short col, short styleIndex)
331 // if (cellType == CELL_TYPE_FORMULA)
332 // {
333 // throw new RuntimeException(
334 // "Formulas have not been implemented in this release");
335 // }
336 if (cellType > CELL_TYPE_ERROR)
338 throw new RuntimeException("I have no idea what type that is!");
340 switch (cellType)
343 case CELL_TYPE_FORMULA :
344 FormulaRecordAggregate frec = null;
346 if (cellType != this.cellType)
348 frec = new FormulaRecordAggregate(new FormulaRecord(),null);
350 else
352 frec = ( FormulaRecordAggregate ) record;
354 frec.setColumn(col);
355 if (setValue)
357 frec.getFormulaRecord().setValue(getNumericCellValue());
359 frec.setXFIndex(styleIndex);
360 frec.setRow(row);
361 record = frec;
362 break;
364 case CELL_TYPE_NUMERIC :
365 NumberRecord nrec = null;
367 if (cellType != this.cellType)
369 nrec = new NumberRecord();
371 else
373 nrec = ( NumberRecord ) record;
375 nrec.setColumn(col);
376 if (setValue)
378 nrec.setValue(getNumericCellValue());
380 nrec.setXFIndex(styleIndex);
381 nrec.setRow(row);
382 record = nrec;
383 break;
385 case CELL_TYPE_STRING :
386 LabelSSTRecord lrec = null;
388 if (cellType != this.cellType)
390 lrec = new LabelSSTRecord();
392 else
394 lrec = ( LabelSSTRecord ) record;
396 lrec.setColumn(col);
397 lrec.setRow(row);
398 lrec.setXFIndex(styleIndex);
399 if (setValue)
401 if ((getStringCellValue() != null)
402 && (!getStringCellValue().equals("")))
404 int sst = 0;
406 UnicodeString str = getRichStringCellValue().getUnicodeString();
407 //jmh if (encoding == ENCODING_COMPRESSED_UNICODE)
408 //jmh {
409 // jmh str.setCompressedUnicode();
410 // jmh } else if (encoding == ENCODING_UTF_16)
411 // jmh {
412 // jmh str.setUncompressedUnicode();
413 // jmh }
414 sst = book.getWorkbook().addSSTString(str);
415 lrec.setSSTIndex(sst);
416 getRichStringCellValue().setUnicodeString(book.getWorkbook().getSSTString(sst));
419 record = lrec;
420 break;
422 case CELL_TYPE_BLANK :
423 BlankRecord brec = null;
425 if (cellType != this.cellType)
427 brec = new BlankRecord();
429 else
431 brec = ( BlankRecord ) record;
433 brec.setColumn(col);
435 // During construction the cellStyle may be null for a Blank cell.
436 brec.setXFIndex(styleIndex);
437 brec.setRow(row);
438 record = brec;
439 break;
441 case CELL_TYPE_BOOLEAN :
442 BoolErrRecord boolRec = null;
444 if (cellType != this.cellType)
446 boolRec = new BoolErrRecord();
448 else
450 boolRec = ( BoolErrRecord ) record;
452 boolRec.setColumn(col);
453 if (setValue)
455 boolRec.setValue(convertCellValueToBoolean());
457 boolRec.setXFIndex(styleIndex);
458 boolRec.setRow(row);
459 record = boolRec;
460 break;
462 case CELL_TYPE_ERROR :
463 BoolErrRecord errRec = null;
465 if (cellType != this.cellType)
467 errRec = new BoolErrRecord();
469 else
471 errRec = ( BoolErrRecord ) record;
473 errRec.setColumn(col);
474 if (setValue)
476 errRec.setValue(getErrorCellValue());
478 errRec.setXFIndex(styleIndex);
479 errRec.setRow(row);
480 record = errRec;
481 break;
483 if (cellType != this.cellType &&
484 this.cellType!=-1 ) // Special Value to indicate an uninitialized Cell
486 int loc = sheet.getLoc();
488 sheet.replaceValueRecord(record);
489 sheet.setLoc(loc);
491 this.cellType = cellType;
495 * get the cells type (numeric, formula or string)
496 * @see #CELL_TYPE_STRING
497 * @see #CELL_TYPE_NUMERIC
498 * @see #CELL_TYPE_FORMULA
499 * @see #CELL_TYPE_BOOLEAN
500 * @see #CELL_TYPE_ERROR
503 public int getCellType()
505 return cellType;
509 * set a numeric value for the cell
511 * @param value the numeric value to set this cell to. For formulas we'll set the
512 * precalculated value, for numerics we'll set its value. For other types we
513 * will change the cell to a numeric cell and set its value.
515 public void setCellValue(double value)
517 int row=record.getRow();
518 short col=record.getColumn();
519 short styleIndex=record.getXFIndex();
520 if ((cellType != CELL_TYPE_NUMERIC) && (cellType != CELL_TYPE_FORMULA))
522 setCellType(CELL_TYPE_NUMERIC, false, row, col, styleIndex);
525 // Save into the apropriate record
526 if(record instanceof FormulaRecordAggregate) {
527 (( FormulaRecordAggregate ) record).getFormulaRecord().setValue(value);
528 } else {
529 (( NumberRecord ) record).setValue(value);
534 * set a date value for the cell. Excel treats dates as numeric so you will need to format the cell as
535 * a date.
537 * @param value the date value to set this cell to. For formulas we'll set the
538 * precalculated value, for numerics we'll set its value. For other types we
539 * will change the cell to a numeric cell and set its value.
541 public void setCellValue(Date value)
543 setCellValue(HSSFDateUtil.getExcelDate(value, this.book.getWorkbook().isUsing1904DateWindowing()));
547 * set a date value for the cell. Excel treats dates as numeric so you will need to format the cell as
548 * a date.
550 * This will set the cell value based on the Calendar's timezone. As Excel
551 * does not support timezones this means that both 20:00+03:00 and
552 * 20:00-03:00 will be reported as the same value (20:00) even that there
553 * are 6 hours difference between the two times. This difference can be
554 * preserved by using <code>setCellValue(value.getTime())</code> which will
555 * automatically shift the times to the default timezone.
557 * @param value the date value to set this cell to. For formulas we'll set the
558 * precalculated value, for numerics we'll set its value. For othertypes we
559 * will change the cell to a numeric cell and set its value.
561 public void setCellValue(Calendar value)
563 setCellValue( HSSFDateUtil.getExcelDate(value, this.book.getWorkbook().isUsing1904DateWindowing()) );
567 * set a string value for the cell. Please note that if you are using
568 * full 16 bit unicode you should call <code>setEncoding()</code> first.
570 * @param value value to set the cell to. For formulas we'll set the formula
571 * string, for String cells we'll set its value. For other types we will
572 * change the cell to a string cell and set its value.
573 * If value is null then we will change the cell to a Blank cell.
574 * @deprecated Use setCellValue(HSSFRichTextString) instead.
577 public void setCellValue(String value)
579 HSSFRichTextString str = new HSSFRichTextString(value);
580 setCellValue(str);
584 * set a string value for the cell. Please note that if you are using
585 * full 16 bit unicode you should call <code>setEncoding()</code> first.
587 * @param value value to set the cell to. For formulas we'll set the formula
588 * string, for String cells we'll set its value. For other types we will
589 * change the cell to a string cell and set its value.
590 * If value is null then we will change the cell to a Blank cell.
592 public void setCellValue(HSSFRichTextString value) {
593 int row=record.getRow();
594 short col=record.getColumn();
595 short styleIndex=record.getXFIndex();
596 if (value == null) {
597 setCellType(CELL_TYPE_BLANK, false, row, col, styleIndex);
598 return;
600 if (cellType == CELL_TYPE_FORMULA) {
601 // Set the 'pre-evaluated result' for the formula
602 // note - formulas do not preserve text formatting.
603 FormulaRecordAggregate fr = (FormulaRecordAggregate) record;
605 // Save the string into a String Record, creating
606 // one if required
607 StringRecord sr = fr.getStringRecord();
608 if(sr == null) {
609 // Wasn't a string before, need a new one
610 sr = new StringRecord();
611 fr.setStringRecord(sr);
614 // Save, loosing the formatting
615 sr.setString(value.getString());
616 // Update our local cache to the un-formatted version
617 stringValue = new HSSFRichTextString(sr.getString());
619 // All done
620 return;
623 // If we get here, we're not dealing with a formula,
624 // so handle things as a normal rich text cell
626 if (cellType != CELL_TYPE_STRING) {
627 setCellType(CELL_TYPE_STRING, false, row, col, styleIndex);
629 int index = 0;
631 UnicodeString str = value.getUnicodeString();
632 index = book.getWorkbook().addSSTString(str);
633 (( LabelSSTRecord ) record).setSSTIndex(index);
634 stringValue = value;
635 stringValue.setWorkbookReferences(book.getWorkbook(), (( LabelSSTRecord ) record));
636 stringValue.setUnicodeString(book.getWorkbook().getSSTString(index));
639 public void setCellFormula(String formula) {
640 int row=record.getRow();
641 short col=record.getColumn();
642 short styleIndex=record.getXFIndex();
643 //Workbook.currentBook=book;
644 if (formula==null) {
645 setCellType(CELL_TYPE_BLANK,false,row,col,styleIndex);
646 } else {
647 setCellType(CELL_TYPE_FORMULA,false,row,col,styleIndex);
648 FormulaRecordAggregate rec = (FormulaRecordAggregate) record;
649 FormulaRecord frec = rec.getFormulaRecord();
650 frec.setOptions(( short ) 2);
651 frec.setValue(0);
653 //only set to default if there is no extended format index already set
654 if (rec.getXFIndex() == (short)0) rec.setXFIndex(( short ) 0x0f);
655 FormulaParser fp = new FormulaParser(formula, book);
656 fp.parse();
657 Ptg[] ptg = fp.getRPNPtg();
658 int size = 0;
660 // clear the Ptg Stack
661 for (int i=0, iSize=frec.getNumberOfExpressionTokens(); i<iSize; i++) {
662 frec.popExpressionToken();
665 // fill the Ptg Stack with Ptgs of new formula
666 for (int k = 0; k < ptg.length; k++) {
667 size += ptg[ k ].getSize();
668 frec.pushExpressionToken(ptg[ k ]);
670 rec.getFormulaRecord().setExpressionLength(( short ) size);
671 //Workbook.currentBook = null;
675 public String getCellFormula() {
676 //Workbook.currentBook=book;
677 String retval = FormulaParser.toFormulaString(book, ((FormulaRecordAggregate)record).getFormulaRecord().getParsedExpression());
678 //Workbook.currentBook=null;
679 return retval;
684 * get the value of the cell as a number. For strings we throw an exception.
685 * For blank cells we return a 0.
688 public double getNumericCellValue()
690 if (cellType == CELL_TYPE_BLANK)
692 return 0;
694 if (cellType == CELL_TYPE_STRING)
696 throw new NumberFormatException(
697 "You cannot get a numeric value from a String based cell");
699 if (cellType == CELL_TYPE_BOOLEAN)
701 throw new NumberFormatException(
702 "You cannot get a numeric value from a boolean cell");
704 if (cellType == CELL_TYPE_ERROR)
706 throw new NumberFormatException(
707 "You cannot get a numeric value from an error cell");
709 if(cellType == CELL_TYPE_NUMERIC)
711 return ((NumberRecord)record).getValue();
713 if(cellType == CELL_TYPE_FORMULA)
715 return ((FormulaRecordAggregate)record).getFormulaRecord().getValue();
717 throw new NumberFormatException("Unknown Record Type in Cell:"+cellType);
721 * get the value of the cell as a date. For strings we throw an exception.
722 * For blank cells we return a null.
724 public Date getDateCellValue()
726 if (cellType == CELL_TYPE_BLANK)
728 return null;
730 if (cellType == CELL_TYPE_STRING)
732 throw new NumberFormatException(
733 "You cannot get a date value from a String based cell");
735 if (cellType == CELL_TYPE_BOOLEAN)
737 throw new NumberFormatException(
738 "You cannot get a date value from a boolean cell");
740 if (cellType == CELL_TYPE_ERROR)
742 throw new NumberFormatException(
743 "You cannot get a date value from an error cell");
745 double value=this.getNumericCellValue();
746 if (book.getWorkbook().isUsing1904DateWindowing()) {
747 return HSSFDateUtil.getJavaDate(value,true);
749 else {
750 return HSSFDateUtil.getJavaDate(value,false);
755 * get the value of the cell as a string - for numeric cells we throw an exception.
756 * For blank cells we return an empty string.
757 * For formulaCells that are not string Formulas, we return empty String
758 * @deprecated Use the HSSFRichTextString return
761 public String getStringCellValue()
763 HSSFRichTextString str = getRichStringCellValue();
764 return str.getString();
768 * get the value of the cell as a string - for numeric cells we throw an exception.
769 * For blank cells we return an empty string.
770 * For formulaCells that are not string Formulas, we return empty String
773 public HSSFRichTextString getRichStringCellValue()
775 if (cellType == CELL_TYPE_BLANK)
777 return new HSSFRichTextString("");
779 if (cellType == CELL_TYPE_NUMERIC)
781 throw new NumberFormatException(
782 "You cannot get a string value from a numeric cell");
784 if (cellType == CELL_TYPE_BOOLEAN)
786 throw new NumberFormatException(
787 "You cannot get a string value from a boolean cell");
789 if (cellType == CELL_TYPE_ERROR)
791 throw new NumberFormatException(
792 "You cannot get a string value from an error cell");
794 if (cellType == CELL_TYPE_FORMULA)
796 if (stringValue==null) return new HSSFRichTextString("");
798 return stringValue;
802 * set a boolean value for the cell
804 * @param value the boolean value to set this cell to. For formulas we'll set the
805 * precalculated value, for booleans we'll set its value. For other types we
806 * will change the cell to a boolean cell and set its value.
809 public void setCellValue(boolean value)
811 int row=record.getRow();
812 short col=record.getColumn();
813 short styleIndex=record.getXFIndex();
814 if ((cellType != CELL_TYPE_BOOLEAN ) && ( cellType != CELL_TYPE_FORMULA))
816 setCellType(CELL_TYPE_BOOLEAN, false, row, col, styleIndex);
818 (( BoolErrRecord ) record).setValue(value);
822 * set a error value for the cell
824 * @param value the error value to set this cell to. For formulas we'll set the
825 * precalculated value ??? IS THIS RIGHT??? , for errors we'll set
826 * its value. For other types we will change the cell to an error
827 * cell and set its value.
830 public void setCellErrorValue(byte value)
832 int row=record.getRow();
833 short col=record.getColumn();
834 short styleIndex=record.getXFIndex();
835 if (cellType != CELL_TYPE_ERROR) {
836 setCellType(CELL_TYPE_ERROR, false, row, col, styleIndex);
838 (( BoolErrRecord ) record).setValue(value);
841 * Chooses a new boolean value for the cell when its type is changing.<p/>
843 * Usually the caller is calling setCellType() with the intention of calling
844 * setCellValue(boolean) straight afterwards. This method only exists to give
845 * the cell a somewhat reasonable value until the setCellValue() call (if at all).
846 * TODO - perhaps a method like setCellTypeAndValue(int, Object) should be introduced to avoid this
848 private boolean convertCellValueToBoolean() {
850 switch (cellType) {
851 case CELL_TYPE_BOOLEAN:
852 return (( BoolErrRecord ) record).getBooleanValue();
853 case CELL_TYPE_STRING:
854 return Boolean.valueOf(((StringRecord)record).getString()).booleanValue();
855 case CELL_TYPE_NUMERIC:
856 return ((NumberRecord)record).getValue() != 0;
858 // All other cases convert to false
859 // These choices are not well justified.
860 case CELL_TYPE_FORMULA:
861 // should really evaluate, but HSSFCell can't call HSSFFormulaEvaluator
862 case CELL_TYPE_ERROR:
863 case CELL_TYPE_BLANK:
864 return false;
866 throw new RuntimeException("Unexpected cell type (" + cellType + ")");
870 * get the value of the cell as a boolean. For strings, numbers, and errors, we throw an exception.
871 * For blank cells we return a false.
874 public boolean getBooleanCellValue()
876 if (cellType == CELL_TYPE_BOOLEAN)
878 return (( BoolErrRecord ) record).getBooleanValue();
880 if (cellType == CELL_TYPE_BLANK)
882 return false;
884 throw new NumberFormatException(
885 "You cannot get a boolean value from a non-boolean cell");
889 * get the value of the cell as an error code. For strings, numbers, and booleans, we throw an exception.
890 * For blank cells we return a 0.
893 public byte getErrorCellValue()
895 if (cellType == CELL_TYPE_ERROR)
897 return (( BoolErrRecord ) record).getErrorValue();
899 if (cellType == CELL_TYPE_BLANK)
901 return ( byte ) 0;
903 throw new NumberFormatException(
904 "You cannot get an error value from a non-error cell");
908 * set the style for the cell. The style should be an HSSFCellStyle created/retreived from
909 * the HSSFWorkbook.
911 * @param style reference contained in the workbook
912 * @see org.apache.poi.hssf.usermodel.HSSFWorkbook#createCellStyle()
913 * @see org.apache.poi.hssf.usermodel.HSSFWorkbook#getCellStyleAt(short)
916 public void setCellStyle(HSSFCellStyle style)
918 record.setXFIndex(style.getIndex());
922 * get the style for the cell. This is a reference to a cell style contained in the workbook
923 * object.
924 * @see org.apache.poi.hssf.usermodel.HSSFWorkbook#getCellStyleAt(short)
927 public HSSFCellStyle getCellStyle()
929 short styleIndex=record.getXFIndex();
930 ExtendedFormatRecord xf = book.getWorkbook().getExFormatAt(styleIndex);
931 return new HSSFCellStyle(styleIndex, xf, book);
935 * used for internationalization, currently -1 for unchanged, 0 for compressed unicode or 1 for 16-bit
937 * @see #ENCODING_UNCHANGED
938 * @see #ENCODING_COMPRESSED_UNICODE
939 * @see #ENCODING_UTF_16
941 * @return -1, 1 or 0 for unchanged, compressed or uncompressed (used only with String type)
943 * @deprecated As of 3-Jan-06 POI now automatically handles Unicode without forcing the encoding.
945 public short getEncoding()
947 return encoding;
951 * set the encoding to either 8 or 16 bit. (US/UK use 8-bit, rest of the western world use 16bit)
953 * @see #ENCODING_UNCHANGED
954 * @see #ENCODING_COMPRESSED_UNICODE
955 * @see #ENCODING_UTF_16
957 * @param encoding either ENCODING_COMPRESSED_UNICODE (0) or ENCODING_UTF_16 (1)
958 * @deprecated As of 3-Jan-06 POI now automatically handles Unicode without forcing the encoding.
961 public void setEncoding(short encoding)
963 this.encoding = encoding;
967 * Should only be used by HSSFSheet and friends. Returns the low level CellValueRecordInterface record
969 * @return CellValueRecordInterface representing the cell via the low level api.
972 protected CellValueRecordInterface getCellValueRecord()
974 return record;
978 * @throws RuntimeException if the bounds are exceeded.
980 private void checkBounds(int cellNum) {
981 if (cellNum > 255) {
982 throw new RuntimeException("You cannot have more than 255 columns "+
983 "in a given row (IV). Because Excel can't handle it");
985 else if (cellNum < 0) {
986 throw new RuntimeException("You cannot reference columns with an index of less then 0.");
991 * Sets this cell as the active cell for the worksheet
993 public void setAsActiveCell()
995 int row=record.getRow();
996 short col=record.getColumn();
997 this.sheet.setActiveCellRow(row);
998 this.sheet.setActiveCellCol(col);
1002 * Returns a string representation of the cell
1004 * This method returns a simple representation,
1005 * anthing more complex should be in user code, with
1006 * knowledge of the semantics of the sheet being processed.
1008 * Formula cells return the formula string,
1009 * rather than the formula result.
1010 * Dates are displayed in dd-MMM-yyyy format
1011 * Errors are displayed as #ERR&lt;errIdx&gt;
1013 public String toString() {
1014 switch (getCellType()) {
1015 case CELL_TYPE_BLANK:
1016 return "";
1017 case CELL_TYPE_BOOLEAN:
1018 return getBooleanCellValue()?"TRUE":"FALSE";
1019 case CELL_TYPE_ERROR:
1020 return "#ERR"+getErrorCellValue();
1021 case CELL_TYPE_FORMULA:
1022 return getCellFormula();
1023 case CELL_TYPE_NUMERIC:
1024 //TODO apply the dataformat for this cell
1025 if (HSSFDateUtil.isCellDateFormatted(this)) {
1026 DateFormat sdf = new SimpleDateFormat("dd-MMM-yyyy");
1027 return sdf.format(getDateCellValue());
1028 }else {
1029 return getNumericCellValue() + "";
1031 case CELL_TYPE_STRING:
1032 return getStringCellValue();
1033 default:
1034 return "Unknown Cell Type: " + getCellType();
1039 * Assign a comment to this cell
1041 * @param comment comment associated with this cell
1043 public void setCellComment(HSSFComment comment){
1044 comment.setRow((short)record.getRow());
1045 comment.setColumn(record.getColumn());
1046 this.comment = comment;
1050 * Returns comment associated with this cell
1052 * @return comment associated with this cell
1054 public HSSFComment getCellComment(){
1055 if (comment == null) {
1056 comment = findCellComment(sheet, record.getRow(), record.getColumn());
1058 return comment;
1062 * Cell comment finder.
1063 * Returns cell comment for the specified sheet, row and column.
1065 * @return cell comment or <code>null</code> if not found
1067 protected static HSSFComment findCellComment(Sheet sheet, int row, int column){
1068 HSSFComment comment = null;
1069 HashMap txshapes = new HashMap(); //map shapeId and TextObjectRecord
1070 for (Iterator it = sheet.getRecords().iterator(); it.hasNext(); ) {
1071 Record rec = ( Record ) it.next();
1072 if (rec instanceof NoteRecord){
1073 NoteRecord note = (NoteRecord)rec;
1074 if (note.getRow() == row && note.getColumn() == column){
1075 TextObjectRecord txo = (TextObjectRecord)txshapes.get(new Integer(note.getShapeId()));
1076 comment = new HSSFComment(note, txo);
1077 comment.setRow(note.getRow());
1078 comment.setColumn(note.getColumn());
1079 comment.setAuthor(note.getAuthor());
1080 comment.setVisible(note.getFlags() == NoteRecord.NOTE_VISIBLE);
1081 comment.setString(txo.getStr());
1082 break;
1084 } else if (rec instanceof ObjRecord){
1085 ObjRecord obj = (ObjRecord)rec;
1086 SubRecord sub = (SubRecord)obj.getSubRecords().get(0);
1087 if (sub instanceof CommonObjectDataSubRecord){
1088 CommonObjectDataSubRecord cmo = (CommonObjectDataSubRecord)sub;
1089 if (cmo.getObjectType() == CommonObjectDataSubRecord.OBJECT_TYPE_COMMENT){
1090 //find the nearest TextObjectRecord which holds comment's text and map it to its shapeId
1091 while(it.hasNext()) {
1092 rec = ( Record ) it.next();
1093 if (rec instanceof TextObjectRecord) {
1094 txshapes.put(new Integer(cmo.getObjectId()), rec);
1095 break;
1103 return comment;
1107 * Returns hyperlink associated with this cell
1109 * @return hyperlink associated with this cell or null if not found
1111 public HSSFHyperlink getHyperlink(){
1112 for (Iterator it = sheet.getRecords().iterator(); it.hasNext(); ) {
1113 Record rec = ( Record ) it.next();
1114 if (rec instanceof HyperlinkRecord){
1115 HyperlinkRecord link = (HyperlinkRecord)rec;
1116 if(link.getFirstColumn() == record.getColumn() && link.getFirstRow() == record.getRow()){
1117 return new HSSFHyperlink(link);
1121 return null;
1125 * Assign a hypelrink to this cell
1127 * @param link hypelrink associated with this cell
1129 public void setHyperlink(HSSFHyperlink link){
1130 link.setFirstRow(record.getRow());
1131 link.setLastRow(record.getRow());
1132 link.setFirstColumn(record.getColumn());
1133 link.setLastColumn(record.getColumn());
1135 switch(link.getType()){
1136 case HSSFHyperlink.LINK_EMAIL:
1137 case HSSFHyperlink.LINK_URL:
1138 link.setLabel("url");
1139 break;
1140 case HSSFHyperlink.LINK_FILE:
1141 link.setLabel("file");
1142 break;
1143 case HSSFHyperlink.LINK_DOCUMENT:
1144 link.setLabel("place");
1145 break;
1148 int eofLoc = sheet.findFirstRecordLocBySid( EOFRecord.sid );
1149 sheet.getRecords().add( eofLoc, link.record );