mirror of https://github.com/apache/poi.git
support copying to hssf row
git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1893945 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
fd548a7a33
commit
38d4834ba7
|
@ -240,17 +240,17 @@ public final class XSSFCell extends CellBase {
|
|||
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();
|
||||
|
@ -586,7 +586,7 @@ public final class XSSFCell extends CellBase {
|
|||
*/
|
||||
private boolean isFormulaCell() {
|
||||
return (_cell.isSetF() && _cell.getF().getT() != STCellFormulaType.DATA_TABLE)
|
||||
|| getSheet().isCellInArrayFormulaContext(this);
|
||||
|| getSheet().isCellInArrayFormulaContext(this);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -645,7 +645,7 @@ public final class XSSFCell extends CellBase {
|
|||
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());
|
||||
}
|
||||
|
@ -972,7 +972,7 @@ public final class XSSFCell extends CellBase {
|
|||
|
||||
/**
|
||||
* Removes the comment for this cell, if there is one.
|
||||
*/
|
||||
*/
|
||||
@Override
|
||||
public void removeCellComment() {
|
||||
XSSFComment comment = getCellComment();
|
||||
|
@ -1125,7 +1125,7 @@ public final class XSSFCell extends CellBase {
|
|||
return FALSE;
|
||||
}
|
||||
throw new IllegalStateException("Unexpected boolean cached formula value '"
|
||||
+ textValue + "'.");
|
||||
+ textValue + "'.");
|
||||
|
||||
case STRING:
|
||||
// fall-through
|
||||
|
@ -1174,4 +1174,3 @@ public final class XSSFCell extends CellBase {
|
|||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -176,7 +176,7 @@ public class XSSFRow implements Row, Comparable<XSSFRow> {
|
|||
XSSFRow other = (XSSFRow) obj;
|
||||
|
||||
return (this.getRowNum() == other.getRowNum()) &&
|
||||
(this.getSheet() == other.getSheet());
|
||||
(this.getSheet() == other.getSheet());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -463,16 +463,16 @@ public class XSSFRow implements Row, Comparable<XSSFRow> {
|
|||
*/
|
||||
@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;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -483,10 +483,10 @@ public class XSSFRow implements Row, Comparable<XSSFRow> {
|
|||
@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();
|
||||
|
||||
|
@ -519,7 +519,7 @@ public class XSSFRow implements Row, Comparable<XSSFRow> {
|
|||
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
|
||||
|
|
|
@ -17,18 +17,28 @@
|
|||
|
||||
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;
|
||||
|
||||
/**
|
||||
|
@ -775,4 +785,91 @@ public final class HSSFRow implements Row, Comparable<HSSFRow> {
|
|||
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());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,115 @@
|
|||
/* ====================================================================
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -19,10 +19,12 @@ 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.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;
|
||||
|
||||
/**
|
||||
|
@ -61,4 +63,15 @@ public final class HSSFRowShifter extends RowShifter {
|
|||
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);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -29,7 +29,7 @@ import java.io.IOException;
|
|||
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;
|
||||
|
||||
/**
|
||||
|
@ -141,4 +141,102 @@ final class TestHSSFRow extends BaseTestRow {
|
|||
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue