1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255 |
- /* ====================================================================
- 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.hssf.usermodel;
-
- import java.text.SimpleDateFormat;
- import java.time.LocalDateTime;
- import java.util.Calendar;
- import java.util.Date;
- import java.util.Iterator;
- import java.util.List;
-
- import org.apache.poi.hssf.model.HSSFFormulaParser;
- import org.apache.poi.hssf.model.InternalWorkbook;
- import org.apache.poi.hssf.record.BlankRecord;
- import org.apache.poi.hssf.record.BoolErrRecord;
- import org.apache.poi.hssf.record.CellValueRecordInterface;
- import org.apache.poi.hssf.record.ExtendedFormatRecord;
- import org.apache.poi.hssf.record.FormulaRecord;
- import org.apache.poi.hssf.record.HyperlinkRecord;
- import org.apache.poi.hssf.record.LabelSSTRecord;
- import org.apache.poi.hssf.record.NumberRecord;
- import org.apache.poi.hssf.record.Record;
- import org.apache.poi.hssf.record.RecordBase;
- import org.apache.poi.hssf.record.aggregates.FormulaRecordAggregate;
- import org.apache.poi.hssf.record.common.UnicodeString;
- import org.apache.poi.ss.SpreadsheetVersion;
- import org.apache.poi.ss.formula.FormulaType;
- import org.apache.poi.ss.formula.eval.ErrorEval;
- import org.apache.poi.ss.formula.ptg.ExpPtg;
- import org.apache.poi.ss.formula.ptg.Ptg;
- import org.apache.poi.ss.usermodel.CellBase;
- import org.apache.poi.ss.usermodel.CellStyle;
- import org.apache.poi.ss.usermodel.CellType;
- import org.apache.poi.ss.usermodel.CellValue;
- import org.apache.poi.ss.usermodel.Comment;
- import org.apache.poi.ss.usermodel.DateUtil;
- import org.apache.poi.ss.usermodel.FormulaError;
- import org.apache.poi.ss.usermodel.Hyperlink;
- import org.apache.poi.ss.usermodel.RichTextString;
- import org.apache.poi.ss.util.CellRangeAddress;
- import org.apache.poi.ss.util.CellReference;
- import org.apache.poi.ss.util.NumberToTextConverter;
- import org.apache.poi.util.LocaleUtil;
- import org.apache.poi.util.Removal;
-
- /**
- * High level representation of a cell in a row of a spreadsheet.
- * Cells can be numeric, formula-based or string-based (text). The cell type
- * specifies this. String cells cannot contain numbers and numeric cells cannot
- * contain strings (at least according to our model). Client apps should do the
- * conversions themselves. Formula cells have the formula string, as well as
- * the formula result, which can be numeric or string.
- * <p>
- * Cells should have their number (0 based) before being added to a row. Only
- * cells that have values should be added.
- * <p>
- */
- public class HSSFCell extends CellBase {
- private static final String FILE_FORMAT_NAME = "BIFF8";
- /**
- * The maximum number of columns in BIFF8
- */
- public static final int LAST_COLUMN_NUMBER = SpreadsheetVersion.EXCEL97.getLastColumnIndex(); // 2^8 - 1
- private static final String LAST_COLUMN_NAME = SpreadsheetVersion.EXCEL97.getLastColumnName();
-
- public static final short ENCODING_UNCHANGED = -1;
- public static final short ENCODING_COMPRESSED_UNICODE = 0;
- public static final short ENCODING_UTF_16 = 1;
-
- private final HSSFWorkbook _book;
- private final HSSFSheet _sheet;
- private CellType _cellType;
- private HSSFRichTextString _stringValue;
- private CellValueRecordInterface _record;
- private HSSFComment _comment;
-
- /**
- * Creates new Cell - Should only be called by HSSFRow. This creates a cell
- * from scratch.
- * <p>
- * When the cell is initially created it is set to {@link CellType#BLANK}. Cell types
- * can be changed/overwritten by calling setCellValue with the appropriate
- * type as a parameter although conversions from one type to another may be
- * prohibited.
- *
- * @param book - Workbook record of the workbook containing this cell
- * @param sheet - Sheet record of the sheet containing this cell
- * @param row - the row of this cell
- * @param col - the column for this cell
- *
- * @see org.apache.poi.hssf.usermodel.HSSFRow#createCell(int)
- */
- protected HSSFCell(HSSFWorkbook book, HSSFSheet sheet, int row, short col)
- {
- checkBounds(col);
- _stringValue = null;
- _book = book;
- _sheet = sheet;
-
- // Relying on the fact that by default the cellType is set to 0 which
- // is different to {@link CellType#BLANK} hence the following method call correctly
- // creates a new blank cell.
- short xfindex = sheet.getSheet().getXFIndexForColAt(col);
- setCellType(CellType.BLANK, false, row, col,xfindex);
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- protected SpreadsheetVersion getSpreadsheetVersion() {
- return SpreadsheetVersion.EXCEL97;
- }
-
- /**
- * Returns the HSSFSheet this cell belongs to
- *
- * @return the HSSFSheet that owns this cell
- */
- public HSSFSheet getSheet() {
- return _sheet;
- }
-
- /**
- * Returns the HSSFRow this cell belongs to
- *
- * @return the HSSFRow that owns this cell
- */
- public HSSFRow getRow() {
- int rowIndex = getRowIndex();
- return _sheet.getRow(rowIndex);
- }
-
- /**
- * Creates new Cell - Should only be called by HSSFRow. This creates a cell
- * from scratch.
- *
- * @param book - Workbook record of the workbook containing this cell
- * @param sheet - Sheet record of the sheet containing this cell
- * @param row - the row of this cell
- * @param col - the column for this cell
- * @param type - Type of cell
- * @see org.apache.poi.hssf.usermodel.HSSFRow#createCell(int,CellType)
- */
- protected HSSFCell(HSSFWorkbook book, HSSFSheet sheet, int row, short col,
- CellType type)
- {
- checkBounds(col);
- _cellType = CellType._NONE; // Force 'setCellType' to create a first Record
- _stringValue = null;
- _book = book;
- _sheet = sheet;
-
- short xfindex = sheet.getSheet().getXFIndexForColAt(col);
- setCellType(type,false,row,col,xfindex);
- }
-
- /**
- * Creates an HSSFCell from a CellValueRecordInterface. HSSFSheet uses this when
- * reading in cells from an existing sheet.
- *
- * @param book - Workbook record of the workbook containing this cell
- * @param sheet - Sheet record of the sheet containing this cell
- * @param cval - the Cell Value Record we wish to represent
- */
- protected HSSFCell(HSSFWorkbook book, HSSFSheet sheet, CellValueRecordInterface cval) {
- _record = cval;
- _cellType = determineType(cval);
- _stringValue = null;
- _book = book;
- _sheet = sheet;
- switch (_cellType)
- {
- case STRING :
- _stringValue = new HSSFRichTextString(book.getWorkbook(), (LabelSSTRecord ) cval);
- break;
-
- case BLANK :
- break;
-
- case FORMULA :
- _stringValue=new HSSFRichTextString(((FormulaRecordAggregate) cval).getStringValue());
- break;
-
- default :
- break;
- }
- }
-
-
- /**
- * used internally -- given a cell value record, figure out its type
- */
- private static CellType determineType(CellValueRecordInterface cval) {
- if (cval instanceof FormulaRecordAggregate) {
- return CellType.FORMULA;
- }
- // all others are plain BIFF records
- Record record = ( Record ) cval;
- switch (record.getSid()) {
-
- case NumberRecord.sid : return CellType.NUMERIC;
- case BlankRecord.sid : return CellType.BLANK;
- case LabelSSTRecord.sid : return CellType.STRING;
- case BoolErrRecord.sid :
- BoolErrRecord boolErrRecord = ( BoolErrRecord ) record;
-
- return boolErrRecord.isBoolean()
- ? CellType.BOOLEAN
- : CellType.ERROR;
- }
- throw new RuntimeException("Bad cell value rec (" + cval.getClass().getName() + ")");
- }
-
- /**
- * Returns the Workbook that this Cell is bound to
- */
- protected InternalWorkbook getBoundWorkbook() {
- return _book.getWorkbook();
- }
-
- /**
- * @return the (zero based) index of the row containing this cell
- */
- @Override
- public int getRowIndex() {
- return _record.getRow();
- }
-
- /**
- * Updates the cell record's idea of what
- * column it belongs in (0 based)
- * @param num the new cell number
- */
- protected void updateCellNum(short num)
- {
- _record.setColumn(num);
- }
-
- @Override
- public int getColumnIndex() {
- return _record.getColumn() & 0xFFFF;
- }
-
- @Override
- protected void setCellTypeImpl(CellType cellType) {
- notifyFormulaChanging();
-
- int row=_record.getRow();
- short col=_record.getColumn();
- short styleIndex=_record.getXFIndex();
- setCellType(cellType, true, row, col, styleIndex);
- }
-
- /**
- * sets the cell type. The setValue flag indicates whether to bother about
- * trying to preserve the current value in the new record if one is created.
- * <p>
- * The @see #setCellValue method will call this method with false in setValue
- * since it will overwrite the cell value later
- *
- */
-
- private void setCellType(CellType cellType, boolean setValue, int row,short col, short styleIndex)
- {
- switch (cellType)
- {
-
- case FORMULA :
- FormulaRecordAggregate frec;
-
- if (cellType != _cellType) {
- frec = _sheet.getSheet().getRowsAggregate().createFormula(row, col);
- } else {
- frec = (FormulaRecordAggregate) _record;
- frec.setRow(row);
- frec.setColumn(col);
- }
- if (getCellType() == CellType.BLANK) {
- frec.getFormulaRecord().setValue(0);
- }
- frec.setXFIndex(styleIndex);
- _record = frec;
- break;
-
- case NUMERIC :
- NumberRecord nrec;
-
- if (cellType != _cellType)
- {
- nrec = new NumberRecord();
- }
- else
- {
- nrec = ( NumberRecord ) _record;
- }
- nrec.setColumn(col);
- if (setValue)
- {
- nrec.setValue(getNumericCellValue());
- }
- nrec.setXFIndex(styleIndex);
- nrec.setRow(row);
- _record = nrec;
- break;
-
- case STRING :
- LabelSSTRecord lrec;
-
- if (cellType == _cellType) {
- lrec = (LabelSSTRecord) _record;
- } else {
- lrec = new LabelSSTRecord();
- lrec.setColumn(col);
- lrec.setRow(row);
- lrec.setXFIndex(styleIndex);
- }
- if (setValue) {
- String str = convertCellValueToString();
- if(str == null) {
- // bug 55668: don't try to store null-string when formula
- // results in empty/null value
- setCellType(CellType.BLANK, false, row, col, styleIndex);
- return;
- } else {
- int sstIndex = _book.getWorkbook().addSSTString(new UnicodeString(str));
- lrec.setSSTIndex(sstIndex);
- UnicodeString us = _book.getWorkbook().getSSTString(sstIndex);
- _stringValue = new HSSFRichTextString();
- _stringValue.setUnicodeString(us);
- }
- }
- _record = lrec;
- break;
-
- case BLANK :
- BlankRecord brec;
-
- if (cellType != _cellType)
- {
- brec = new BlankRecord();
- }
- else
- {
- brec = ( BlankRecord ) _record;
- }
- brec.setColumn(col);
-
- // During construction the cellStyle may be null for a Blank cell.
- brec.setXFIndex(styleIndex);
- brec.setRow(row);
- _record = brec;
- break;
-
- case BOOLEAN :
- BoolErrRecord boolRec;
-
- if (cellType != _cellType)
- {
- boolRec = new BoolErrRecord();
- }
- else
- {
- boolRec = ( BoolErrRecord ) _record;
- }
- boolRec.setColumn(col);
- if (setValue)
- {
- boolRec.setValue(convertCellValueToBoolean());
- }
- boolRec.setXFIndex(styleIndex);
- boolRec.setRow(row);
- _record = boolRec;
- break;
-
- case ERROR :
- BoolErrRecord errRec;
-
- if (cellType != _cellType)
- {
- errRec = new BoolErrRecord();
- }
- else
- {
- errRec = ( BoolErrRecord ) _record;
- }
- errRec.setColumn(col);
- if (setValue)
- {
- errRec.setValue(FormulaError.VALUE.getCode());
- }
- errRec.setXFIndex(styleIndex);
- errRec.setRow(row);
- _record = errRec;
- break;
- default :
- throw new IllegalStateException("Invalid cell type: " + cellType);
- }
- if (cellType != _cellType &&
- _cellType != CellType._NONE ) // Special Value to indicate an uninitialized Cell
- {
- _sheet.getSheet().replaceValueRecord(_record);
- }
- _cellType = cellType;
- }
-
- /**
- * get the cells type (numeric, formula or string)
- */
- @Override
- public CellType getCellType()
- {
- return _cellType;
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- @SuppressWarnings("fallthrough")
- protected void setCellValueImpl(double value) {
- switch (_cellType) {
- default:
- setCellType(CellType.NUMERIC,
- false,
- _record.getRow(),
- _record.getColumn(),
- _record.getXFIndex());
- // fall through
- case NUMERIC:
- ((NumberRecord)_record).setValue(value);
- break;
- case FORMULA:
- ((FormulaRecordAggregate)_record).setCachedDoubleResult(value);
- break;
- }
- }
-
- /**
- * {@inheritDoc}
- *
- * <p>In HSSF, only the number of days is stored. The fractional part is ignored.</p>
- * @see DateUtil
- * @see org.apache.poi.ss.usermodel.DateUtil
- */
- protected void setCellValueImpl(Date value) {
- setCellValue(DateUtil.getExcelDate(value, _book.getWorkbook().isUsing1904DateWindowing()));
- }
-
- /**
- * {@inheritDoc}
- *
- * <p>In HSSF, only the number of days is stored. The fractional part is ignored.</p>
- * @see DateUtil
- * @see org.apache.poi.ss.usermodel.DateUtil
- */
- protected void setCellValueImpl(LocalDateTime value) {
- setCellValue(DateUtil.getExcelDate(value, _book.getWorkbook().isUsing1904DateWindowing()));
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- protected void setCellValueImpl(Calendar value) {
- setCellValue( DateUtil.getExcelDate(value, _book.getWorkbook().isUsing1904DateWindowing()) );
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- protected void setCellValueImpl(String value) {
- setCellValueImpl(new HSSFRichTextString(value));
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- protected void setCellValueImpl(RichTextString value) {
- if (_cellType == CellType.FORMULA) {
- // Set the 'pre-evaluated result' for the formula
- // note - formulas do not preserve text formatting.
- FormulaRecordAggregate fr = (FormulaRecordAggregate) _record;
- fr.setCachedStringResult(value.getString());
- // Update our local cache to the un-formatted version
- _stringValue = new HSSFRichTextString(value.getString());
-
- // All done
- return;
- }
-
- // If we get here, we're not dealing with a formula,
- // so handle things as a normal rich text cell
-
- if (_cellType != CellType.STRING) {
- int row=_record.getRow();
- short col=_record.getColumn();
- short styleIndex=_record.getXFIndex();
- setCellType(CellType.STRING, false, row, col, styleIndex);
- }
- int index;
-
- HSSFRichTextString hvalue = (HSSFRichTextString) value;
- UnicodeString str = hvalue.getUnicodeString();
- index = _book.getWorkbook().addSSTString(str);
- (( LabelSSTRecord ) _record).setSSTIndex(index);
- _stringValue = hvalue;
- _stringValue.setWorkbookReferences(_book.getWorkbook(), (( LabelSSTRecord ) _record));
- _stringValue.setUnicodeString(_book.getWorkbook().getSSTString(index));
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- protected void setCellFormulaImpl(String formula) {
- // formula cells always have a value. If the cell is blank (either initially or after removing an
- // array formula), set value to 0
- if (getValueType() == CellType.BLANK) {
- setCellValue(0);
- }
-
- assert formula != null;
-
- int row=_record.getRow();
- short col=_record.getColumn();
- short styleIndex=_record.getXFIndex();
-
- final CellValue savedValue = readValue();
- int sheetIndex = _book.getSheetIndex(_sheet);
- Ptg[] ptgs = HSSFFormulaParser.parse(formula, _book, FormulaType.CELL, sheetIndex);
- setCellType(CellType.FORMULA, false, row, col, styleIndex);
- FormulaRecordAggregate agg = (FormulaRecordAggregate) _record;
- FormulaRecord frec = agg.getFormulaRecord();
- frec.setOptions((short) 2);
-
- //only set to default if there is no extended format index already set
- if (agg.getXFIndex() == (short)0) {
- agg.setXFIndex((short) 0x0f);
- }
- agg.setParsedExpression(ptgs);
-
- restoreValue(savedValue);
- }
-
- private CellValue readValue() {
- final CellType valueType = getCellType() == CellType.FORMULA ? getCachedFormulaResultType() : getCellType();
- switch (valueType) {
- case NUMERIC:
- return new CellValue(getNumericCellValue());
- case STRING:
- return new CellValue(getStringCellValue());
- case BOOLEAN:
- return CellValue.valueOf(getBooleanCellValue());
- case ERROR:
- return CellValue.getError(getErrorCellValue());
- default:
- throw new IllegalStateException("Unexpected cell-type " + valueType);
- }
- }
-
- private void restoreValue(CellValue value) {
- switch (value.getCellType()) {
- case NUMERIC:
- setCellValue(value.getNumberValue());
- break;
- case STRING:
- setCellValue(value.getStringValue());
- break;
- case BOOLEAN:
- setCellValue(value.getBooleanValue());
- break;
- case ERROR:
- setCellErrorValue(FormulaError.forInt(value.getErrorValue()));
- break;
- default:
- throw new IllegalStateException("Unexpected cell-type " + value.getCellType() + " for cell-value: " + value);
- }
- }
-
- @Override
- protected void removeFormulaImpl() {
- assert getCellType() == CellType.FORMULA;
-
- notifyFormulaChanging();
-
- switch (getCachedFormulaResultType()) {
- case NUMERIC:
- double numericValue = ((FormulaRecordAggregate)_record).getFormulaRecord().getValue();
- _record = new NumberRecord();
- ((NumberRecord)_record).setValue(numericValue);
- _cellType = CellType.NUMERIC;
- break;
- case STRING:
- _record = new NumberRecord();
- ((NumberRecord)_record).setValue(0);
- _cellType = CellType.STRING;
- break;
- case BOOLEAN:
- boolean booleanValue = ((FormulaRecordAggregate)_record).getFormulaRecord().getCachedBooleanValue();
- _record = new BoolErrRecord();
- ((BoolErrRecord)_record).setValue(booleanValue);
- _cellType = CellType.BOOLEAN;
- break;
- case ERROR:
- byte errorValue = (byte) ((FormulaRecordAggregate)_record).getFormulaRecord().getCachedErrorValue();
- _record = new BoolErrRecord();
- ((BoolErrRecord)_record).setValue(errorValue);
- _cellType = CellType.ERROR;
- break;
- default:
- throw new AssertionError();
- }
- }
-
- /**
- * Should be called any time that a formula could potentially be deleted.
- * Does nothing if this cell currently does not hold a formula
- */
- private void notifyFormulaChanging() {
- if (_record instanceof FormulaRecordAggregate) {
- ((FormulaRecordAggregate)_record).notifyFormulaChanging();
- }
- }
-
- public String getCellFormula() {
- if (!(_record instanceof FormulaRecordAggregate)) {
- throw typeMismatch(CellType.FORMULA, _cellType, true);
- }
- return HSSFFormulaParser.toFormulaString(_book, ((FormulaRecordAggregate)_record).getFormulaTokens());
- }
-
- private static RuntimeException typeMismatch(CellType expectedTypeCode, CellType actualTypeCode, boolean isFormulaCell) {
- String msg = "Cannot get a " + expectedTypeCode + " value from a " + actualTypeCode
- + " " + (isFormulaCell ? "formula " : "") + "cell";
- return new IllegalStateException(msg);
- }
-
- private static void checkFormulaCachedValueType(CellType expectedTypeCode, FormulaRecord fr) {
- CellType cachedValueType = fr.getCachedResultTypeEnum();
- if (cachedValueType != expectedTypeCode) {
- throw typeMismatch(expectedTypeCode, cachedValueType, true);
- }
- }
-
- /**
- * Get the value of the cell as a number.
- * For strings we throw an exception.
- * For blank cells we return a 0.
- * See {@link HSSFDataFormatter} for turning this
- * number into a string similar to that which
- * Excel would render this number as.
- */
- public double getNumericCellValue() {
-
- switch(_cellType) {
- case BLANK:
- return 0.0;
- case NUMERIC:
- return ((NumberRecord)_record).getValue();
- default:
- throw typeMismatch(CellType.NUMERIC, _cellType, false);
- case FORMULA:
- break;
- }
- FormulaRecord fr = ((FormulaRecordAggregate)_record).getFormulaRecord();
- checkFormulaCachedValueType(CellType.NUMERIC, fr);
- return fr.getValue();
- }
-
- /**
- * Get the value of the cell as a date.
- * For strings we throw an exception.
- * For blank cells we return a null.
- * See {@link HSSFDataFormatter} for formatting
- * this date into a string similar to how excel does.
- */
- public Date getDateCellValue() {
-
- if (_cellType == CellType.BLANK) {
- return null;
- }
- double value = getNumericCellValue();
- if (_book.getWorkbook().isUsing1904DateWindowing()) {
- return DateUtil.getJavaDate(value, true);
- }
- return DateUtil.getJavaDate(value, false);
- }
-
- /**
- * Get the value of the cell as a LocalDateTime.
- * For strings we throw an exception.
- * For blank cells we return a null.
- * See {@link HSSFDataFormatter} for formatting
- * this date into a string similar to how excel does.
- */
- public LocalDateTime getLocalDateTimeCellValue() {
-
- if (_cellType == CellType.BLANK) {
- return null;
- }
- double value = getNumericCellValue();
- if (_book.getWorkbook().isUsing1904DateWindowing()) {
- return DateUtil.getLocalDateTime(value, true);
- }
- return DateUtil.getLocalDateTime(value, false);
- }
-
- /**
- * get the value of the cell as a string - 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
- */
- public String getStringCellValue()
- {
- HSSFRichTextString str = getRichStringCellValue();
- return str.getString();
- }
-
- /**
- * get the value of the cell as a string - 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
- */
- public HSSFRichTextString getRichStringCellValue() {
-
- switch(_cellType) {
- case BLANK:
- return new HSSFRichTextString("");
- case STRING:
- return _stringValue;
- default:
- throw typeMismatch(CellType.STRING, _cellType, false);
- case FORMULA:
- break;
- }
- FormulaRecordAggregate fra = ((FormulaRecordAggregate)_record);
- checkFormulaCachedValueType(CellType.STRING, fra.getFormulaRecord());
- String strVal = fra.getStringValue();
- return new HSSFRichTextString(strVal == null ? "" : strVal);
- }
-
- /**
- * 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.
- */
- @SuppressWarnings("fallthrough")
- public void setCellValue(boolean value) {
- int row=_record.getRow();
- short col=_record.getColumn();
- short styleIndex=_record.getXFIndex();
-
- switch (_cellType) {
- default:
- setCellType(CellType.BOOLEAN, false, row, col, styleIndex);
- // fall through
- case BOOLEAN:
- (( BoolErrRecord ) _record).setValue(value);
- break;
- case FORMULA:
- ((FormulaRecordAggregate)_record).setCachedBooleanResult(value);
- break;
- }
- }
-
- /**
- * set a error value for the cell
- *
- * @param errorCode 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.
- * For error code byte, see {@link FormulaError}.
- * @deprecated 3.15 beta 2. Use {@link #setCellErrorValue(FormulaError)} instead.
- */
- public void setCellErrorValue(byte errorCode) {
- FormulaError error = FormulaError.forInt(errorCode);
- setCellErrorValue(error);
- }
- /**
- * set a error value for the cell
- *
- * @param error 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.
- */
- @SuppressWarnings("fallthrough")
- public void setCellErrorValue(FormulaError error) {
- int row=_record.getRow();
- short col=_record.getColumn();
- short styleIndex=_record.getXFIndex();
- switch (_cellType) {
- default:
- setCellType(CellType.ERROR, false, row, col, styleIndex);
- // fall through
- case ERROR:
- (( BoolErrRecord ) _record).setValue(error);
- break;
- case FORMULA:
- ((FormulaRecordAggregate)_record).setCachedErrorResult(error.getCode());
- break;
- }
- }
-
-
- /**
- * Chooses a new boolean value for the cell when its type is changing.<p>
- *
- * Usually the caller is calling setCellType() with the intention of calling
- * setCellValue(boolean) straight afterwards. This method only exists to give
- * the cell a somewhat reasonable value until the setCellValue() call (if at all).
- * TODO - perhaps a method like setCellTypeAndValue(int, Object) should be introduced to avoid this
- * @throws IllegalStateException if cell type cannot be converted to boolean
- */
- private boolean convertCellValueToBoolean() {
-
- switch (_cellType) {
- case BOOLEAN:
- return (( BoolErrRecord ) _record).getBooleanValue();
- case STRING:
- int sstIndex = ((LabelSSTRecord)_record).getSSTIndex();
- String text = _book.getWorkbook().getSSTString(sstIndex).getString();
- return Boolean.parseBoolean(text);
- case NUMERIC:
- return ((NumberRecord)_record).getValue() != 0;
-
- case FORMULA:
- // use cached formula result if it's the right type:
- FormulaRecord fr = ((FormulaRecordAggregate)_record).getFormulaRecord();
- checkFormulaCachedValueType(CellType.BOOLEAN, fr);
- return fr.getCachedBooleanValue();
- // Other cases convert to false
- // These choices are not well justified.
- case ERROR:
- case BLANK:
- return false;
- }
- throw new IllegalStateException("Unexpected cell type (" + _cellType + ")");
- }
-
- private String convertCellValueToString() {
-
- switch (_cellType) {
- case BLANK:
- return "";
- case BOOLEAN:
- return ((BoolErrRecord) _record).getBooleanValue() ? "TRUE" : "FALSE";
- case STRING:
- int sstIndex = ((LabelSSTRecord)_record).getSSTIndex();
- return _book.getWorkbook().getSSTString(sstIndex).getString();
- case NUMERIC:
- return NumberToTextConverter.toText(((NumberRecord)_record).getValue());
- case ERROR:
- return FormulaError.forInt(((BoolErrRecord)_record).getErrorValue()).getString();
- case FORMULA:
- // should really evaluate, but HSSFCell can't call HSSFFormulaEvaluator
- // just use cached formula result instead
- break;
- default:
- throw new IllegalStateException("Unexpected cell type (" + _cellType + ")");
- }
- FormulaRecordAggregate fra = ((FormulaRecordAggregate)_record);
- FormulaRecord fr = fra.getFormulaRecord();
- switch (fr.getCachedResultTypeEnum()) {
- case BOOLEAN:
- return fr.getCachedBooleanValue() ? "TRUE" : "FALSE";
- case STRING:
- return fra.getStringValue();
- case NUMERIC:
- return NumberToTextConverter.toText(fr.getValue());
- case ERROR:
- return FormulaError.forInt(fr.getCachedErrorValue()).getString();
- default:
- throw new IllegalStateException("Unexpected formula result type (" + _cellType + ")");
- }
-
- }
-
- /**
- * get the value of the cell as a boolean. For strings, numbers, and errors, we throw an exception.
- * For blank cells we return a false.
- */
- @Override
- public boolean getBooleanCellValue() {
-
- switch(_cellType) {
- case BLANK:
- return false;
- case BOOLEAN:
- return (( BoolErrRecord ) _record).getBooleanValue();
- case FORMULA:
- break;
- default:
- throw typeMismatch(CellType.BOOLEAN, _cellType, false);
- }
- FormulaRecord fr = ((FormulaRecordAggregate)_record).getFormulaRecord();
- checkFormulaCachedValueType(CellType.BOOLEAN, fr);
- return fr.getCachedBooleanValue();
- }
-
- /**
- * get the value of the cell as an error code. For strings, numbers, and booleans, we throw an exception.
- * For blank cells we return a 0.
- */
- @Override
- public byte getErrorCellValue() {
- switch(_cellType) {
- case ERROR:
- return (( BoolErrRecord ) _record).getErrorValue();
- case FORMULA:
- FormulaRecord fr = ((FormulaRecordAggregate)_record).getFormulaRecord();
- checkFormulaCachedValueType(CellType.ERROR, fr);
- return (byte) fr.getCachedErrorValue();
- default:
- throw typeMismatch(CellType.ERROR, _cellType, false);
- }
- }
-
- /**
- * <p>Set the style for the cell. The style should be an HSSFCellStyle created/retreived from
- * the HSSFWorkbook.</p>
- *
- * <p>To change the style of a cell without affecting other cells that use the same style,
- * use {@link org.apache.poi.ss.util.CellUtil#setCellStyleProperties(org.apache.poi.ss.usermodel.Cell, java.util.Map)}</p>
- *
- * @param style reference contained in the workbook
- * @see org.apache.poi.hssf.usermodel.HSSFWorkbook#createCellStyle()
- * @see org.apache.poi.hssf.usermodel.HSSFWorkbook#getCellStyleAt(int)
- */
- public void setCellStyle(CellStyle style) {
- setCellStyle( (HSSFCellStyle)style );
- }
- public void setCellStyle(HSSFCellStyle style) {
- // A style of null means resetting back to the default style
- if (style == null) {
- _record.setXFIndex((short)0xf);
- return;
- }
-
- // Verify the style really does belong to our workbook
- style.verifyBelongsToWorkbook(_book);
-
- short styleIndex;
- if(style.getUserStyleName() != null) {
- styleIndex = applyUserCellStyle(style);
- } else {
- styleIndex = style.getIndex();
- }
-
- // Change our cell record to use this style
- _record.setXFIndex(styleIndex);
- }
-
- /**
- * get the style for the cell. This is a reference to a cell style contained in the workbook
- * object.
- * @see org.apache.poi.hssf.usermodel.HSSFWorkbook#getCellStyleAt(int)
- */
- public HSSFCellStyle getCellStyle()
- {
- short styleIndex=_record.getXFIndex();
- ExtendedFormatRecord xf = _book.getWorkbook().getExFormatAt(styleIndex);
- return new HSSFCellStyle(styleIndex, xf, _book);
- }
-
- /**
- * Should only be used by HSSFSheet and friends. Returns the low level CellValueRecordInterface record
- *
- * @return CellValueRecordInterface representing the cell via the low level api.
- */
-
- protected CellValueRecordInterface getCellValueRecord()
- {
- return _record;
- }
-
- /**
- * @throws RuntimeException if the bounds are exceeded.
- */
- private static void checkBounds(int cellIndex) {
- if (cellIndex < 0 || cellIndex > LAST_COLUMN_NUMBER) {
- throw new IllegalArgumentException("Invalid column index (" + cellIndex
- + "). Allowable column range for " + FILE_FORMAT_NAME + " is (0.."
- + LAST_COLUMN_NUMBER + ") or ('A'..'" + LAST_COLUMN_NAME + "')");
- }
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public void setAsActiveCell()
- {
- int row=_record.getRow();
- short col=_record.getColumn();
- _sheet.getSheet().setActiveCellRow(row);
- _sheet.getSheet().setActiveCellCol(col);
- }
-
- /**
- * Returns a string representation of the cell
- *
- * This method returns a simple representation,
- * anything more complex should be in user code, with
- * knowledge of the semantics of the sheet being processed.
- *
- * Formula cells return the formula string,
- * rather than the formula result.
- * Dates are displayed in dd-MMM-yyyy format
- * Errors are displayed as #ERR<errIdx>
- */
- public String toString() {
- switch (getCellType()) {
- case BLANK:
- return "";
- case BOOLEAN:
- return getBooleanCellValue()?"TRUE":"FALSE";
- case ERROR:
- return ErrorEval.getText((( BoolErrRecord ) _record).getErrorValue());
- case FORMULA:
- return getCellFormula();
- case NUMERIC:
- //TODO apply the dataformat for this cell
- if (DateUtil.isCellDateFormatted(this)) {
- SimpleDateFormat sdf = new SimpleDateFormat("dd-MMM-yyyy", LocaleUtil.getUserLocale());
- sdf.setTimeZone(LocaleUtil.getUserTimeZone());
- return sdf.format(getDateCellValue());
- }
- return String.valueOf(getNumericCellValue());
- case STRING:
- return getStringCellValue();
- default:
- return "Unknown Cell Type: " + getCellType();
- }
- }
-
- /**
- * Assign a comment to this cell. If the supplied
- * comment is null, the comment for this cell
- * will be removed.
- *
- * @param comment comment associated with this cell
- */
- public void setCellComment(Comment comment){
- if(comment == null) {
- removeCellComment();
- return;
- }
-
- comment.setRow(_record.getRow());
- comment.setColumn(_record.getColumn());
- _comment = (HSSFComment)comment;
- }
-
- /**
- * Returns comment associated with this cell
- *
- * @return comment associated with this cell
- */
- public HSSFComment getCellComment(){
- if (_comment == null) {
- _comment = _sheet.findCellComment(_record.getRow(), _record.getColumn());
- }
- return _comment;
- }
-
- /**
- * Removes the comment for this cell, if
- * there is one.
- * WARNING - some versions of excel will loose
- * all comments after performing this action!
- */
- public void removeCellComment() {
- HSSFComment comment = _sheet.findCellComment(_record.getRow(), _record.getColumn());
- _comment = null;
- if (null == comment){
- return;
- }
- _sheet.getDrawingPatriarch().removeShape(comment);
- }
-
- /**
- * @return hyperlink associated with this cell or <code>null</code> if not found
- */
- @Override
- public HSSFHyperlink getHyperlink(){
- return _sheet.getHyperlink(_record.getRow(), _record.getColumn());
- }
-
- /**
- * Assign a hyperlink to this cell. If the supplied hyperlink is null, the
- * hyperlink for this cell will be removed.
- *
- * @param hyperlink hyperlink associated with this cell
- */
- @Override
- public void setHyperlink(Hyperlink hyperlink){
- if (hyperlink == null) {
- removeHyperlink();
- return;
- }
-
- HSSFHyperlink link = (HSSFHyperlink)hyperlink;
-
- link.setFirstRow(_record.getRow());
- link.setLastRow(_record.getRow());
- link.setFirstColumn(_record.getColumn());
- link.setLastColumn(_record.getColumn());
-
- switch(link.getType()){
- case EMAIL:
- case URL:
- link.setLabel("url");
- break;
- case FILE:
- link.setLabel("file");
- break;
- case DOCUMENT:
- link.setLabel("place");
- break;
- default:
- break;
- }
-
- List<RecordBase> records = _sheet.getSheet().getRecords();
- int eofLoc = records.size() - 1;
- records.add( eofLoc, link.record );
- }
-
- /**
- * Removes the hyperlink for this cell, if there is one.
- */
- public void removeHyperlink() {
- for (Iterator<RecordBase> it = _sheet.getSheet().getRecords().iterator(); it.hasNext();) {
- RecordBase rec = it.next();
- if (rec instanceof HyperlinkRecord) {
- HyperlinkRecord link = (HyperlinkRecord) rec;
- if (link.getFirstColumn() == _record.getColumn() && link.getFirstRow() == _record.getRow()) {
- it.remove();
- return;
- }
- }
- }
- }
-
- /**
- * Only valid for formula cells
- * @return one of ({@link CellType#NUMERIC}, {@link CellType#STRING},
- * {@link CellType#BOOLEAN}, {@link CellType#ERROR}) depending
- * on the cached value of the formula
- *
- * @since POI 4.0
- */
- @Override
- public CellType getCachedFormulaResultType() {
- if (_cellType != CellType.FORMULA) {
- throw new IllegalStateException("Only formula cells have cached results");
- }
-
- return ((FormulaRecordAggregate)_record).getFormulaRecord().getCachedResultTypeEnum();
- }
-
- void setCellArrayFormula(CellRangeAddress range) {
- int row = _record.getRow();
- short col = _record.getColumn();
- short styleIndex = _record.getXFIndex();
- setCellType(CellType.FORMULA, false, row, col, styleIndex);
-
- // Billet for formula in rec
- Ptg[] ptgsForCell = {new ExpPtg(range.getFirstRow(), range.getFirstColumn())};
- FormulaRecordAggregate agg = (FormulaRecordAggregate) _record;
- agg.setParsedExpression(ptgsForCell);
- }
-
- public CellRangeAddress getArrayFormulaRange() {
- if (_cellType != CellType.FORMULA) {
- String ref = new CellReference(this).formatAsString();
- throw new IllegalStateException("Cell " + ref
- + " is not part of an array formula.");
- }
- return ((FormulaRecordAggregate)_record).getArrayFormulaRange();
- }
-
- public boolean isPartOfArrayFormulaGroup() {
- return _cellType == CellType.FORMULA && ((FormulaRecordAggregate) _record).isPartOfArrayFormula();
- }
-
- /**
- * Applying a user-defined style (UDS) is special. Excel does not directly reference user-defined styles, but
- * instead create a 'proxy' ExtendedFormatRecord referencing the UDS as parent.
- *
- * The proceudre to apply a UDS is as follows:
- *
- * 1. search for a ExtendedFormatRecord with parentIndex == style.getIndex()
- * and xfType == ExtendedFormatRecord.XF_CELL.
- * 2. if not found then create a new ExtendedFormatRecord and copy all attributes from the user-defined style
- * and set the parentIndex to be style.getIndex()
- * 3. return the index of the ExtendedFormatRecord, this will be assigned to the parent cell record
- *
- * @param style the user style to apply
- *
- * @return the index of a ExtendedFormatRecord record that will be referenced by the cell
- */
- private short applyUserCellStyle(HSSFCellStyle style){
- if(style.getUserStyleName() == null) {
- throw new IllegalArgumentException("Expected user-defined style");
- }
-
- InternalWorkbook iwb = _book.getWorkbook();
- short userXf = -1;
- int numfmt = iwb.getNumExFormats();
- for(short i = 0; i < numfmt; i++){
- ExtendedFormatRecord xf = iwb.getExFormatAt(i);
- if(xf.getXFType() == ExtendedFormatRecord.XF_CELL && xf.getParentIndex() == style.getIndex() ){
- userXf = i;
- break;
- }
- }
- short styleIndex;
- if (userXf == -1){
- ExtendedFormatRecord xfr = iwb.createCellXF();
- xfr.cloneStyleFrom(iwb.getExFormatAt(style.getIndex()));
- xfr.setIndentionOptions((short)0);
- xfr.setXFType(ExtendedFormatRecord.XF_CELL);
- xfr.setParentIndex(style.getIndex());
- styleIndex = (short)numfmt;
- } else {
- styleIndex = userXf;
- }
-
- return styleIndex;
- }
- }
|