return 0.0;
case NUMERIC:
if(_cell.isSetV()) {
- String v = _cell.getV();
- if (v.isEmpty()) {
- return 0.0;
- }
- try {
- return Double.parseDouble(v);
- } catch(NumberFormatException e) {
- throw typeMismatch(CellType.NUMERIC, CellType.STRING, false);
- }
+ String v = _cell.getV();
+ if (v.isEmpty()) {
+ return 0.0;
+ }
+ try {
+ return Double.parseDouble(v);
+ } catch(NumberFormatException e) {
+ throw typeMismatch(CellType.NUMERIC, CellType.STRING, false);
+ }
} else {
- return 0.0;
+ return 0.0;
}
case FORMULA:
throw new AssertionError();
*/
private boolean isFormulaCell() {
return (_cell.isSetF() && _cell.getF().getT() != STCellFormulaType.DATA_TABLE)
- || getSheet().isCellInArrayFormulaContext(this);
+ || getSheet().isCellInArrayFormulaContext(this);
}
/**
case STCellType.INT_S: // String is in shared strings
case STCellType.INT_INLINE_STR: // String is inline in cell
case STCellType.INT_STR:
- return CellType.STRING;
+ return CellType.STRING;
default:
throw new IllegalStateException("Illegal cell type: " + this._cell.getT());
}
/**
* Removes the comment for this cell, if there is one.
- */
+ */
@Override
public void removeCellComment() {
XSSFComment comment = getCellComment();
return FALSE;
}
throw new IllegalStateException("Unexpected boolean cached formula value '"
- + textValue + "'.");
+ + textValue + "'.");
case STRING:
// fall-through
}
}
-
XSSFRow other = (XSSFRow) obj;
return (this.getRowNum() == other.getRowNum()) &&
- (this.getSheet() == other.getSheet());
+ (this.getSheet() == other.getSheet());
}
@Override
*/
@Override
public XSSFCellStyle getRowStyle() {
- if(!isFormatted()) {
- return null;
- }
+ if(!isFormatted()) {
+ return null;
+ }
- StylesTable stylesSource = getSheet().getWorkbook().getStylesSource();
- if(stylesSource.getNumCellStyles() > 0) {
- return stylesSource.getStyleAt(Math.toIntExact(_row.getS()));
- } else {
- return null;
- }
+ StylesTable stylesSource = getSheet().getWorkbook().getStylesSource();
+ if(stylesSource.getNumCellStyles() > 0) {
+ return stylesSource.getStyleAt(Math.toIntExact(_row.getS()));
+ } else {
+ return null;
+ }
}
/**
@Override
public void setRowStyle(CellStyle style) {
if(style == null) {
- if(_row.isSetS()) {
- _row.unsetS();
- _row.unsetCustomFormat();
- }
+ if(_row.isSetS()) {
+ _row.unsetS();
+ _row.unsetCustomFormat();
+ }
} else {
StylesTable styleSource = getSheet().getWorkbook().getStylesSource();
xcell.setCellFormula(null); // to remove the array formula
}
if(cell.getCellType() == CellType.FORMULA) {
- _sheet.getWorkbook().onDeleteFormula(xcell);
+ _sheet.getWorkbook().onDeleteFormula(xcell);
}
// Performance optimization for bug 57840: explicit boxing is slightly faster than auto-unboxing, though may use more memory
final Integer colI = Integer.valueOf(cell.getColumnIndex()); // NOSONAR
package org.apache.poi.hssf.usermodel;
+import java.util.HashSet;
import java.util.Iterator;
import java.util.NoSuchElementException;
+import java.util.Set;
import org.apache.poi.hssf.record.CellValueRecordInterface;
import org.apache.poi.hssf.record.ExtendedFormatRecord;
import org.apache.poi.hssf.record.RowRecord;
+import org.apache.poi.hssf.usermodel.helpers.HSSFRowShifter;
import org.apache.poi.ss.SpreadsheetVersion;
+import org.apache.poi.ss.formula.FormulaShifter;
import org.apache.poi.ss.usermodel.Cell;
+import org.apache.poi.ss.usermodel.CellCopyContext;
+import org.apache.poi.ss.usermodel.CellCopyPolicy;
import org.apache.poi.ss.usermodel.CellStyle;
import org.apache.poi.ss.usermodel.CellType;
+import org.apache.poi.ss.usermodel.FormulaError;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.helpers.RowShifter;
+import org.apache.poi.ss.util.CellRangeAddress;
+import org.apache.poi.ss.util.CellUtil;
+import org.apache.poi.util.Beta;
import org.apache.poi.util.Configurator;
/**
cells[columnIndex] = null;
}
}
+
+ /**
+ * Copy the cells from srcRow to this row
+ * If this row is not a blank row, this will merge the two rows, overwriting
+ * the cells in this row with the cells in srcRow
+ * If srcRow is null, overwrite cells in destination row with blank values, styles, etc per cell copy policy
+ * srcRow may be from a different sheet in the same workbook
+ * @param srcRow the rows to copy from
+ * @param policy the policy to determine what gets copied
+ */
+ @Beta
+ public void copyRowFrom(Row srcRow, CellCopyPolicy policy) {
+ copyRowFrom(srcRow, policy, null);
+ }
+
+ /**
+ * Copy the cells from srcRow to this row
+ * If this row is not a blank row, this will merge the two rows, overwriting
+ * the cells in this row with the cells in srcRow
+ * If srcRow is null, overwrite cells in destination row with blank values, styles, etc per cell copy policy
+ * srcRow may be from a different sheet in the same workbook
+ * @param srcRow the rows to copy from
+ * @param policy the policy to determine what gets copied
+ * @param context the context - see {@link CellCopyContext}
+ * @since v5.1.0
+ */
+ @Beta
+ public void copyRowFrom(Row srcRow, CellCopyPolicy policy, CellCopyContext context) {
+ if (srcRow == null) {
+ // srcRow is blank. Overwrite cells with blank values, blank styles, etc per cell copy policy
+ for (Cell destCell : this) {
+ CellUtil.copyCell(null, destCell, policy, context);
+ }
+
+ if (policy.isCopyMergedRegions()) {
+ // Remove MergedRegions in dest row
+ final int destRowNum = getRowNum();
+ int index = 0;
+ final Set<Integer> indices = new HashSet<>();
+ for (CellRangeAddress destRegion : getSheet().getMergedRegions()) {
+ if (destRowNum == destRegion.getFirstRow() && destRowNum == destRegion.getLastRow()) {
+ indices.add(index);
+ }
+ index++;
+ }
+ getSheet().removeMergedRegions(indices);
+ }
+
+ if (policy.isCopyRowHeight()) {
+ // clear row height
+ setHeight((short)-1);
+ }
+
+ } else {
+ for (final Cell c : srcRow) {
+ final HSSFCell destCell = createCell(c.getColumnIndex());
+ CellUtil.copyCell(c, destCell, policy, context);
+ }
+
+ final int sheetIndex = sheet.getWorkbook().getSheetIndex(sheet);
+ final String sheetName = sheet.getWorkbook().getSheetName(sheetIndex);
+ final int srcRowNum = srcRow.getRowNum();
+ final int destRowNum = getRowNum();
+ final int rowDifference = destRowNum - srcRowNum;
+
+ final FormulaShifter formulaShifter = FormulaShifter.createForRowCopy(sheetIndex, sheetName, srcRowNum, srcRowNum, rowDifference, SpreadsheetVersion.EXCEL2007);
+ final HSSFRowShifter rowShifter = new HSSFRowShifter(sheet);
+ rowShifter.updateRowFormulas(this, formulaShifter);
+
+ // Copy merged regions that are fully contained on the row
+ // FIXME: is this something that rowShifter could be doing?
+ if (policy.isCopyMergedRegions()) {
+ for (CellRangeAddress srcRegion : srcRow.getSheet().getMergedRegions()) {
+ if (srcRowNum == srcRegion.getFirstRow() && srcRowNum == srcRegion.getLastRow()) {
+ CellRangeAddress destRegion = srcRegion.copy();
+ destRegion.setFirstRow(destRowNum);
+ destRegion.setLastRow(destRowNum);
+ getSheet().addMergedRegion(destRegion);
+ }
+ }
+ }
+
+ if (policy.isCopyRowHeight()) {
+ setHeight(srcRow.getHeight());
+ }
+ }
+ }
}
--- /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.hssf.usermodel.helpers;
+
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+import org.apache.poi.hssf.usermodel.*;
+import org.apache.poi.ss.formula.*;
+import org.apache.poi.ss.formula.ptg.Ptg;
+import org.apache.poi.ss.usermodel.*;
+import org.apache.poi.util.Internal;
+
+import static org.apache.logging.log4j.util.Unbox.box;
+
+/**
+ * Class for code common to {@link HSSFRowShifter} and {@link HSSFColumnShifter}
+ *
+ * @since POI 5.1.0
+ */
+@Internal
+/*private*/ final class HSSFRowColShifter {
+ private static final Logger LOG = LogManager.getLogger(HSSFRowColShifter.class);
+
+ private HSSFRowColShifter() { /*no instances for static classes*/}
+
+ /**
+ * Update formulas.
+ */
+ /*package*/ static void updateFormulas(Sheet sheet, FormulaShifter formulaShifter) {
+ //update formulas on the parent sheet
+ updateSheetFormulas(sheet,formulaShifter);
+
+ //update formulas on other sheets
+ Workbook wb = sheet.getWorkbook();
+ for(Sheet sh : wb)
+ {
+ if (sheet == sh) continue;
+ updateSheetFormulas(sh, formulaShifter);
+ }
+ }
+
+ /*package*/ static void updateSheetFormulas(Sheet sh, FormulaShifter formulashifter) {
+ for (Row r : sh) {
+ HSSFRow row = (HSSFRow) r;
+ updateRowFormulas(row, formulashifter);
+ }
+ }
+
+ /**
+ * Update the formulas in specified row using the formula shifting policy specified by shifter
+ *
+ * @param row the row to update the formulas on
+ * @param formulaShifter the formula shifting policy
+ */
+ /*package*/ static void updateRowFormulas(HSSFRow row, FormulaShifter formulaShifter) {
+ HSSFSheet sheet = row.getSheet();
+ for (Cell c : row) {
+ HSSFCell cell = (HSSFCell) c;
+ String formula = cell.getCellFormula();
+ if (formula.length() > 0) {
+ String shiftedFormula = shiftFormula(row, formula, formulaShifter);
+ cell.setCellFormula(shiftedFormula);
+ }
+ }
+ }
+
+ /**
+ * Shift a formula using the supplied FormulaShifter
+ *
+ * @param row the row of the cell this formula belongs to. Used to get a reference to the parent workbook.
+ * @param formula the formula to shift
+ * @param formulaShifter the FormulaShifter object that operates on the parsed formula tokens
+ * @return the shifted formula if the formula was changed,
+ * <code>null</code> if the formula wasn't modified
+ */
+ /*package*/
+ static String shiftFormula(Row row, String formula, FormulaShifter formulaShifter) {
+ Sheet sheet = row.getSheet();
+ Workbook wb = sheet.getWorkbook();
+ int sheetIndex = wb.getSheetIndex(sheet);
+ final int rowIndex = row.getRowNum();
+ HSSFEvaluationWorkbook fpb = HSSFEvaluationWorkbook.create((HSSFWorkbook) wb);
+
+ try {
+ Ptg[] ptgs = FormulaParser.parse(formula, fpb, FormulaType.CELL, sheetIndex, rowIndex);
+ String shiftedFmla;
+ if (formulaShifter.adjustFormula(ptgs, sheetIndex)) {
+ shiftedFmla = FormulaRenderer.toFormulaString(fpb, ptgs);
+ } else {
+ shiftedFmla = formula;
+ }
+ return shiftedFmla;
+ } catch (FormulaParseException fpe) {
+ // Log, but don't change, rather than breaking
+ LOG.atWarn().withThrowable(fpe).log("Error shifting formula on row {}", box(row.getRowNum()));
+ return formula;
+ }
+ }
+
+}
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
+import org.apache.poi.hssf.usermodel.HSSFRow;
import org.apache.poi.hssf.usermodel.HSSFSheet;
import org.apache.poi.ss.formula.FormulaShifter;
import org.apache.poi.ss.formula.eval.NotImplementedException;
import org.apache.poi.ss.usermodel.helpers.RowShifter;
+import org.apache.poi.util.Internal;
import org.apache.poi.util.NotImplemented;
/**
throw new NotImplementedException("updateHyperlinks");
}
+ /**
+ * Update the formulas in specified row using the formula shifting policy specified by shifter
+ *
+ * @param row the row to update the formulas on
+ * @param formulaShifter the formula shifting policy
+ */
+ @Internal(since="5.1.0")
+ public void updateRowFormulas(HSSFRow row, FormulaShifter formulaShifter) {
+ HSSFRowColShifter.updateRowFormulas(row, formulaShifter);
+ }
+
}
import org.apache.poi.hssf.HSSFITestDataProvider;
import org.apache.poi.hssf.record.BlankRecord;
import org.apache.poi.hssf.record.RowRecord;
-import org.apache.poi.ss.usermodel.BaseTestRow;
+import org.apache.poi.ss.usermodel.*;
import org.junit.jupiter.api.Test;
/**
workbook.close();
}
+
+ @Test
+ void testCopyRowFromExternalSheet() throws IOException {
+ final HSSFWorkbook workbook = new HSSFWorkbook();
+ final HSSFSheet srcSheet = workbook.createSheet("src");
+ final HSSFSheet destSheet = workbook.createSheet("dest");
+ workbook.createSheet("other");
+
+ final Row srcRow = srcSheet.createRow(0);
+ int col = 0;
+ //Test 2D and 3D Ref Ptgs (Pxg for OOXML Workbooks)
+ srcRow.createCell(col++).setCellFormula("B5");
+ srcRow.createCell(col++).setCellFormula("src!B5");
+ srcRow.createCell(col++).setCellFormula("dest!B5");
+ srcRow.createCell(col++).setCellFormula("other!B5");
+
+ //Test 2D and 3D Ref Ptgs with absolute row
+ srcRow.createCell(col++).setCellFormula("B$5");
+ srcRow.createCell(col++).setCellFormula("src!B$5");
+ srcRow.createCell(col++).setCellFormula("dest!B$5");
+ srcRow.createCell(col++).setCellFormula("other!B$5");
+
+ //Test 2D and 3D Area Ptgs (Pxg for OOXML Workbooks)
+ srcRow.createCell(col++).setCellFormula("SUM(B5:D$5)");
+ srcRow.createCell(col++).setCellFormula("SUM(src!B5:D$5)");
+ srcRow.createCell(col++).setCellFormula("SUM(dest!B5:D$5)");
+ srcRow.createCell(col++).setCellFormula("SUM(other!B5:D$5)");
+
+ //////////////////
+
+ final int styleCount = workbook.getNumCellStyles();
+
+ final HSSFRow destRow = destSheet.createRow(1);
+ destRow.copyRowFrom(srcRow, new CellCopyPolicy());
+
+ //////////////////
+
+ //Test 2D and 3D Ref Ptgs (Pxg for OOXML Workbooks)
+ col = 0;
+ Cell cell = destRow.getCell(col++);
+ assertNotNull(cell);
+ assertEquals("B6", cell.getCellFormula(), "RefPtg");
+
+ cell = destRow.getCell(col++);
+ assertNotNull(cell);
+ assertEquals("src!B6", cell.getCellFormula(), "Ref3DPtg");
+
+ cell = destRow.getCell(col++);
+ assertNotNull(cell);
+ assertEquals("dest!B6", cell.getCellFormula(), "Ref3DPtg");
+
+ cell = destRow.getCell(col++);
+ assertNotNull(cell);
+ assertEquals("other!B6", cell.getCellFormula(), "Ref3DPtg");
+
+ /////////////////////////////////////////////
+
+ //Test 2D and 3D Ref Ptgs with absolute row (Ptg row number shouldn't change)
+ cell = destRow.getCell(col++);
+ assertNotNull(cell);
+ assertEquals("B$5", cell.getCellFormula(), "RefPtg");
+
+ cell = destRow.getCell(col++);
+ assertNotNull(cell);
+ assertEquals("src!B$5", cell.getCellFormula(), "Ref3DPtg");
+
+ cell = destRow.getCell(col++);
+ assertNotNull(cell);
+ assertEquals("dest!B$5", cell.getCellFormula(), "Ref3DPtg");
+
+ cell = destRow.getCell(col++);
+ assertNotNull(cell);
+ assertEquals("other!B$5", cell.getCellFormula(), "Ref3DPtg");
+
+ //////////////////////////////////////////
+
+ //Test 2D and 3D Area Ptgs (Pxg for OOXML Workbooks)
+ // Note: absolute row changes from last cell to first cell in order
+ // to maintain topLeft:bottomRight order
+ cell = destRow.getCell(col++);
+ assertNotNull(cell);
+ assertEquals("SUM(B$5:D6)", cell.getCellFormula(), "Area2DPtg");
+
+ cell = destRow.getCell(col++);
+ assertNotNull(cell);
+ assertEquals("SUM(src!B$5:D6)", cell.getCellFormula(), "Area3DPtg");
+
+ cell = destRow.getCell(col++);
+ assertNotNull(cell);
+ assertEquals("SUM(dest!B$5:D6)", cell.getCellFormula(), "Area3DPtg");
+
+ cell = destRow.getCell(col++);
+ assertNotNull(cell);
+ assertEquals("SUM(other!B$5:D6)", cell.getCellFormula(), "Area3DPtg");
+
+ assertEquals(styleCount, workbook.getNumCellStyles(), "no new styles should be added by copyRow");
+ workbook.close();
+ }
}