From: PJ Fanning Date: Wed, 14 Feb 2018 20:30:01 +0000 (+0000) Subject: [github-94] Add Range Copier. Thanks to Dragan Jovanović. This closes #94 X-Git-Url: https://source.dussan.org/?a=commitdiff_plain;h=51f99aa616de1806e5c92906888347a2b8ce10f7;p=poi.git [github-94] Add Range Copier. Thanks to Dragan Jovanović. This closes #94 git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1824266 13f79535-47bb-0310-9956-ffa450edef68 --- diff --git a/src/java/org/apache/poi/hssf/usermodel/HSSFRangeCopier.java b/src/java/org/apache/poi/hssf/usermodel/HSSFRangeCopier.java new file mode 100644 index 0000000000..f6d3fb3819 --- /dev/null +++ b/src/java/org/apache/poi/hssf/usermodel/HSSFRangeCopier.java @@ -0,0 +1,42 @@ +/* + * ==================================================================== + * 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 org.apache.poi.hssf.record.aggregates.FormulaRecordAggregate; +import org.apache.poi.ss.formula.ptg.Ptg; +import org.apache.poi.ss.usermodel.Cell; +import org.apache.poi.ss.usermodel.RangeCopier; +import org.apache.poi.ss.usermodel.Sheet; +import org.apache.poi.util.Beta; + +@Beta +public class HSSFRangeCopier extends RangeCopier { + public HSSFRangeCopier(Sheet sourceSheet, Sheet destSheet) { + super(sourceSheet, destSheet); + } + + protected void adjustCellReferencesInsideFormula(Cell cell, Sheet destSheet, int deltaX, int deltaY) { + FormulaRecordAggregate fra = (FormulaRecordAggregate)((HSSFCell)cell).getCellValueRecord(); + int destSheetIndex = destSheet.getWorkbook().getSheetIndex(destSheet); + Ptg[] ptgs = fra.getFormulaTokens(); + if(adjustInBothDirections(ptgs, destSheetIndex, deltaX, deltaY)) + fra.setParsedExpression(ptgs); + } +} diff --git a/src/java/org/apache/poi/ss/usermodel/RangeCopier.java b/src/java/org/apache/poi/ss/usermodel/RangeCopier.java new file mode 100644 index 0000000000..ea3bc4e225 --- /dev/null +++ b/src/java/org/apache/poi/ss/usermodel/RangeCopier.java @@ -0,0 +1,159 @@ +/* + * ==================================================================== + * 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.ss.usermodel; + +import java.util.Map; +import org.apache.poi.ss.formula.FormulaShifter; +import org.apache.poi.ss.formula.ptg.Ptg; +import org.apache.poi.ss.util.CellRangeAddress; +import org.apache.poi.util.Beta; + +@Beta +public abstract class RangeCopier { + private Sheet sourceSheet; + private Sheet destSheet; + private FormulaShifter horizontalFormulaShifter; + private FormulaShifter verticalFormulaShifter; + + public RangeCopier(Sheet sourceSheet, Sheet destSheet) { + this.sourceSheet = sourceSheet; + this.destSheet = destSheet; + } + public RangeCopier(Sheet sheet) { + this(sheet, sheet); + } + /** Uses input pattern to tile destination region, overwriting existing content. Works in following manner : + * 1.Start from top-left of destination. + * 2.Paste source but only inside of destination borders. + * 3.If there is space left on right or bottom side of copy, process it as in step 2. + * @param tilePatternRange source range which should be copied in tiled manner + * @param tileDestRange destination range, which should be overridden + */ + public void copyRange(CellRangeAddress tilePatternRange, CellRangeAddress tileDestRange) { + Sheet sourceCopy = sourceSheet.getWorkbook().cloneSheet(sourceSheet.getWorkbook().getSheetIndex(sourceSheet)); + int sourceWidthMinus1 = tilePatternRange.getLastColumn() - tilePatternRange.getFirstColumn(); + int sourceHeightMinus1 = tilePatternRange.getLastRow() - tilePatternRange.getFirstRow(); + int rightLimitToCopy; + int bottomLimitToCopy; + + int nextRowIndexToCopy = tileDestRange.getFirstRow(); + do { + int nextCellIndexInRowToCopy = tileDestRange.getFirstColumn(); + int heightToCopyMinus1 = Math.min(sourceHeightMinus1, tileDestRange.getLastRow() - nextRowIndexToCopy); + bottomLimitToCopy = tilePatternRange.getFirstRow() + heightToCopyMinus1; + do { + int widthToCopyMinus1 = Math.min(sourceWidthMinus1, tileDestRange.getLastColumn() - nextCellIndexInRowToCopy); + rightLimitToCopy = tilePatternRange.getFirstColumn() + widthToCopyMinus1; + CellRangeAddress rangeToCopy = new CellRangeAddress( + tilePatternRange.getFirstRow(), bottomLimitToCopy, + tilePatternRange.getFirstColumn(), rightLimitToCopy + ); + copyRange(rangeToCopy, nextCellIndexInRowToCopy - rangeToCopy.getFirstColumn(), nextRowIndexToCopy - rangeToCopy.getFirstRow(), sourceCopy); + nextCellIndexInRowToCopy += widthToCopyMinus1 + 1; + } while (nextCellIndexInRowToCopy <= tileDestRange.getLastColumn()); + nextRowIndexToCopy += heightToCopyMinus1 + 1; + } while (nextRowIndexToCopy <= tileDestRange.getLastRow()); + + int tempCopyIndex = sourceSheet.getWorkbook().getSheetIndex(sourceCopy); + sourceSheet.getWorkbook().removeSheetAt(tempCopyIndex); + } + + private void copyRange(CellRangeAddress sourceRange, int deltaX, int deltaY, Sheet sourceClone) { //NOSONAR, it's a bit complex but monolith method, does not make much sense to divide it + if(deltaX != 0) + horizontalFormulaShifter = FormulaShifter.createForColumnCopy(sourceSheet.getWorkbook().getSheetIndex(sourceSheet), + sourceSheet.getSheetName(), sourceRange.getFirstColumn(), sourceRange.getLastColumn(), deltaX, sourceSheet.getWorkbook().getSpreadsheetVersion()); + if(deltaY != 0) + verticalFormulaShifter = FormulaShifter.createForRowCopy(sourceSheet.getWorkbook().getSheetIndex(sourceSheet), + sourceSheet.getSheetName(), sourceRange.getFirstRow(), sourceRange.getLastRow(), deltaY, sourceSheet.getWorkbook().getSpreadsheetVersion()); + + for(int rowNo = sourceRange.getFirstRow(); rowNo <= sourceRange.getLastRow(); rowNo++) { + Row sourceRow = sourceClone.getRow(rowNo); // copy from source copy, original source might be overridden in process! + for (int columnIndex = sourceRange.getFirstColumn(); columnIndex <= sourceRange.getLastColumn(); columnIndex++) { + Cell sourceCell = sourceRow.getCell(columnIndex); + if(sourceCell == null) + continue; + Row destRow = destSheet.getRow(rowNo + deltaY); + if(destRow == null) + destRow = destSheet.createRow(rowNo + deltaY); + + Cell newCell = destRow.getCell(columnIndex + deltaX); + if(newCell != null) + newCell.setCellType(sourceCell.getCellType()); + else newCell = destRow.createCell(columnIndex + deltaX, sourceCell.getCellType()); + + cloneCellContent(sourceCell, newCell, null); + if(newCell.getCellType() == CellType.FORMULA) + adjustCellReferencesInsideFormula(newCell, destSheet, deltaX, deltaY); + } + } + } + + protected abstract void adjustCellReferencesInsideFormula(Cell cell, Sheet destSheet, int deltaX, int deltaY); // this part is different for HSSF and XSSF + + protected boolean adjustInBothDirections(Ptg[] ptgs, int sheetIndex, int deltaX, int deltaY) { + boolean adjustSucceeded = true; + if(deltaY != 0) + adjustSucceeded = verticalFormulaShifter.adjustFormula(ptgs, sheetIndex); + if(deltaX != 0) + adjustSucceeded = adjustSucceeded && horizontalFormulaShifter.adjustFormula(ptgs, sheetIndex); + return adjustSucceeded; + } + + // TODO clone some more properties ? + public static void cloneCellContent(Cell srcCell, Cell destCell, Map styleMap) { + if(styleMap != null) { + if(srcCell.getSheet().getWorkbook() == destCell.getSheet().getWorkbook()){ + destCell.setCellStyle(srcCell.getCellStyle()); + } else { + int stHashCode = srcCell.getCellStyle().hashCode(); + CellStyle newCellStyle = styleMap.get(stHashCode); + if(newCellStyle == null){ + newCellStyle = destCell.getSheet().getWorkbook().createCellStyle(); + newCellStyle.cloneStyleFrom(srcCell.getCellStyle()); + styleMap.put(stHashCode, newCellStyle); + } + destCell.setCellStyle(newCellStyle); + } + } + switch(srcCell.getCellType()) { + case STRING: + destCell.setCellValue(srcCell.getStringCellValue()); + break; + case NUMERIC: + destCell.setCellValue(srcCell.getNumericCellValue()); + break; + case BLANK: + destCell.setCellType(CellType.BLANK); + break; + case BOOLEAN: + destCell.setCellValue(srcCell.getBooleanCellValue()); + break; + case ERROR: + destCell.setCellErrorValue(srcCell.getErrorCellValue()); + break; + case FORMULA: + String oldFormula = srcCell.getCellFormula(); + destCell.setCellFormula(oldFormula); + break; + default: + break; + } + } +} diff --git a/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFRangeCopier.java b/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFRangeCopier.java new file mode 100644 index 0000000000..9269843828 --- /dev/null +++ b/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFRangeCopier.java @@ -0,0 +1,46 @@ +/* + * ==================================================================== + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ==================================================================== + */ + +package org.apache.poi.xssf.usermodel; + +import org.apache.poi.ss.formula.FormulaParser; +import org.apache.poi.ss.formula.FormulaRenderer; +import org.apache.poi.ss.formula.FormulaType; +import org.apache.poi.ss.formula.ptg.Ptg; +import org.apache.poi.ss.usermodel.Cell; +import org.apache.poi.ss.usermodel.RangeCopier; +import org.apache.poi.ss.usermodel.Sheet; +import org.apache.poi.util.Beta; + +@Beta +public class XSSFRangeCopier extends RangeCopier { + + public XSSFRangeCopier(Sheet sourceSheet, Sheet destSheet){ + super(sourceSheet, destSheet); + } + + protected void adjustCellReferencesInsideFormula(Cell cell, Sheet destSheet, int deltaX, int deltaY){ + XSSFWorkbook hostWorkbook = (XSSFWorkbook) destSheet.getWorkbook(); + XSSFEvaluationWorkbook fpb = XSSFEvaluationWorkbook.create(hostWorkbook); + Ptg[] ptgs = FormulaParser.parse(cell.getCellFormula(), fpb, FormulaType.CELL, 0); + int destSheetIndex = hostWorkbook.getSheetIndex(destSheet); + if(adjustInBothDirections(ptgs, destSheetIndex, deltaX, deltaY)) + cell.setCellFormula(FormulaRenderer.toFormulaString(fpb, ptgs)); + } +} diff --git a/src/ooxml/testcases/org/apache/poi/ss/usermodel/TestXSSFRangeCopier.java b/src/ooxml/testcases/org/apache/poi/ss/usermodel/TestXSSFRangeCopier.java new file mode 100644 index 0000000000..405390fbda --- /dev/null +++ b/src/ooxml/testcases/org/apache/poi/ss/usermodel/TestXSSFRangeCopier.java @@ -0,0 +1,56 @@ +/* + * ==================================================================== + * 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.ss.usermodel; + +import static org.junit.Assert.assertEquals; + +import org.apache.poi.xssf.XSSFITestDataProvider; +import org.apache.poi.xssf.XSSFTestDataSamples; +import org.apache.poi.xssf.usermodel.XSSFRangeCopier; +import org.apache.poi.xssf.usermodel.XSSFRow; +import org.apache.poi.xssf.usermodel.XSSFWorkbook; +import org.junit.Before; +import org.junit.Test; + +public class TestXSSFRangeCopier extends TestRangeCopier { + public TestXSSFRangeCopier() { + super(); + workbook = new XSSFWorkbook(); + testDataProvider = XSSFITestDataProvider.instance; + } + + @Before + public void init() { + workbook = XSSFTestDataSamples.openSampleWorkbook("tile-range-test.xlsx"); + initSheets(); + rangeCopier = new XSSFRangeCopier(sheet1, sheet1); + transSheetRangeCopier = new XSSFRangeCopier(sheet1, sheet2); + } + + @Test // XSSF only. HSSF version wouldn't be so simple. And also this test is contained in following, more complex tests, so it's not really important. + public void copyRow() { + Row existingRow = sheet1.getRow(4); + XSSFRow newRow = (XSSFRow)sheet1.getRow(5); + CellCopyPolicy policy = new CellCopyPolicy(); + newRow.copyRowFrom(existingRow, policy); + assertEquals("$C2+B$2", newRow.getCell(1).getCellFormula()); + } + +} diff --git a/src/ooxml/testcases/org/apache/poi/xssf/usermodel/TestXSSFSheetShiftColumns.java b/src/ooxml/testcases/org/apache/poi/xssf/usermodel/TestXSSFSheetShiftColumns.java index f912b43909..45bb31e3a3 100644 --- a/src/ooxml/testcases/org/apache/poi/xssf/usermodel/TestXSSFSheetShiftColumns.java +++ b/src/ooxml/testcases/org/apache/poi/xssf/usermodel/TestXSSFSheetShiftColumns.java @@ -40,4 +40,4 @@ public class TestXSSFSheetShiftColumns extends BaseTestSheetShiftColumns { return XSSFTestDataSamples.writeOutAndReadBack(wb); } -} +} \ No newline at end of file diff --git a/src/ooxml/testcases/org/apache/poi/xssf/usermodel/helpers/TestXSSFColumnShifting.java b/src/ooxml/testcases/org/apache/poi/xssf/usermodel/helpers/TestXSSFColumnShifting.java index e976294f1f..67767aea50 100644 --- a/src/ooxml/testcases/org/apache/poi/xssf/usermodel/helpers/TestXSSFColumnShifting.java +++ b/src/ooxml/testcases/org/apache/poi/xssf/usermodel/helpers/TestXSSFColumnShifting.java @@ -31,5 +31,4 @@ public class TestXSSFColumnShifting extends BaseTestColumnShifting { protected void initColumnShifter(){ columnShifter = new XSSFColumnShifter((XSSFSheet)sheet1); } - } diff --git a/src/testcases/org/apache/poi/hssf/usermodel/TestHSSFRangeCopier.java b/src/testcases/org/apache/poi/hssf/usermodel/TestHSSFRangeCopier.java new file mode 100644 index 0000000000..8f6b678513 --- /dev/null +++ b/src/testcases/org/apache/poi/hssf/usermodel/TestHSSFRangeCopier.java @@ -0,0 +1,42 @@ +/* + * ==================================================================== + * 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 org.apache.poi.hssf.HSSFITestDataProvider; +import org.apache.poi.hssf.HSSFTestDataSamples; +import org.apache.poi.ss.usermodel.TestRangeCopier; +import org.junit.Before; + +public class TestHSSFRangeCopier extends TestRangeCopier { + + public TestHSSFRangeCopier() { + super(); + workbook = new HSSFWorkbook(); + testDataProvider = HSSFITestDataProvider.instance; + } + + @Before + public void init() { + workbook = HSSFTestDataSamples.openSampleWorkbook("tile-range-test.xls"); + initSheets(); + rangeCopier = new HSSFRangeCopier(sheet1, sheet1); + transSheetRangeCopier = new HSSFRangeCopier(sheet1, sheet2); + } +} diff --git a/src/testcases/org/apache/poi/hssf/usermodel/TestHSSFSheetShiftColumns.java b/src/testcases/org/apache/poi/hssf/usermodel/TestHSSFSheetShiftColumns.java index b9afa51a16..f5be8470d2 100644 --- a/src/testcases/org/apache/poi/hssf/usermodel/TestHSSFSheetShiftColumns.java +++ b/src/testcases/org/apache/poi/hssf/usermodel/TestHSSFSheetShiftColumns.java @@ -79,7 +79,6 @@ public class TestHSSFSheetShiftColumns extends BaseTestSheetShiftColumns { // so that original method from BaseTestSheetShiftColumns can be executed. // After removing, you can re-add 'final' keyword to specification of original method. } - @Override @Ignore("see ") @Test diff --git a/src/testcases/org/apache/poi/ss/usermodel/BaseTestSheetShiftColumns.java b/src/testcases/org/apache/poi/ss/usermodel/BaseTestSheetShiftColumns.java index 884e3a8119..3f146a8fb0 100644 --- a/src/testcases/org/apache/poi/ss/usermodel/BaseTestSheetShiftColumns.java +++ b/src/testcases/org/apache/poi/ss/usermodel/BaseTestSheetShiftColumns.java @@ -94,7 +94,6 @@ public abstract class BaseTestSheetShiftColumns { style.setVerticalAlignment(VerticalAlignment.BOTTOM); return style; } - @Test public void testShiftOneColumnRight() { sheet1.shiftColumns(1, 2, 1); @@ -271,7 +270,6 @@ public abstract class BaseTestSheetShiftColumns { // A1:A5 should be moved to B1:B5 // B1:B3 will be removed sheet.shiftColumns(0, 0, 1); - assertEquals(1, sheet.getNumMergedRegions()); assertEquals(CellRangeAddress.valueOf("B1:B5"), sheet.getMergedRegion(0)); @@ -398,6 +396,4 @@ public abstract class BaseTestSheetShiftColumns { assertEquals("X", cell.getStringCellValue()); wb.close(); } - - } diff --git a/src/testcases/org/apache/poi/ss/usermodel/TestRangeCopier.java b/src/testcases/org/apache/poi/ss/usermodel/TestRangeCopier.java new file mode 100644 index 0000000000..def64a32c9 --- /dev/null +++ b/src/testcases/org/apache/poi/ss/usermodel/TestRangeCopier.java @@ -0,0 +1,99 @@ +/* + * ==================================================================== + * 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.ss.usermodel; + +import static org.junit.Assert.assertEquals; + +import org.junit.Ignore; +import org.junit.Test; +import org.apache.poi.ss.ITestDataProvider; +import org.apache.poi.ss.util.CellRangeAddress; +import org.apache.poi.ss.util.CellReference; + +@Ignore +public abstract class TestRangeCopier { + protected Sheet sheet1; + protected Sheet sheet2; + protected Workbook workbook; + protected RangeCopier rangeCopier; + protected RangeCopier transSheetRangeCopier; + protected ITestDataProvider testDataProvider; + + protected void initSheets() { + sheet1 = workbook.getSheet("sheet1"); + sheet2 = workbook.getSheet("sheet2"); + } + + @Test + public void copySheetRangeWithoutFormulas() { + CellRangeAddress rangeToCopy = CellRangeAddress.valueOf("B1:C2"); //2x2 + CellRangeAddress destRange = CellRangeAddress.valueOf("C2:D3"); //2x2 + rangeCopier.copyRange(rangeToCopy, destRange); + assertEquals("1.1", sheet1.getRow(2).getCell(2).toString()); + assertEquals("2.1", sheet1.getRow(2).getCell(3).toString()); + } + + @Test + public void tileTheRangeAway() { + CellRangeAddress tileRange = CellRangeAddress.valueOf("C4:D5"); + CellRangeAddress destRange = CellRangeAddress.valueOf("F4:K5"); + rangeCopier.copyRange(tileRange, destRange); + assertEquals("1.3", getCellContent(sheet1, "H4")); + assertEquals("1.3", getCellContent(sheet1, "J4")); + assertEquals("$C1+G$2", getCellContent(sheet1, "G5")); + assertEquals("SUM(G3:I3)", getCellContent(sheet1, "H5")); + assertEquals("$C1+I$2", getCellContent(sheet1, "I5")); + assertEquals("", getCellContent(sheet1, "L5")); //out of borders + assertEquals("", getCellContent(sheet1, "G7")); //out of borders + } + + @Test + public void tileTheRangeOver() { + CellRangeAddress tileRange = CellRangeAddress.valueOf("C4:D5"); + CellRangeAddress destRange = CellRangeAddress.valueOf("A4:C5"); + rangeCopier.copyRange(tileRange, destRange); + assertEquals("1.3", getCellContent(sheet1, "A4")); + assertEquals("$C1+B$2", getCellContent(sheet1, "B5")); + assertEquals("SUM(B3:D3)", getCellContent(sheet1, "C5")); + } + + @Test + public void copyRangeToOtherSheet() { + Sheet destSheet = sheet2; + CellRangeAddress tileRange = CellRangeAddress.valueOf("C4:D5"); // on sheet1 + CellRangeAddress destRange = CellRangeAddress.valueOf("F4:J6"); // on sheet2 + transSheetRangeCopier.copyRange(tileRange, destRange); + assertEquals("1.3", getCellContent(destSheet, "H4")); + assertEquals("1.3", getCellContent(destSheet, "J4")); + assertEquals("$C1+G$2", getCellContent(destSheet, "G5")); + assertEquals("SUM(G3:I3)", getCellContent(destSheet, "H5")); + assertEquals("$C1+I$2", getCellContent(destSheet, "I5")); + } + + protected static String getCellContent(Sheet sheet, String coordinates) { + try { + CellReference p = new CellReference(coordinates); + return sheet.getRow(p.getRow()).getCell(p.getCol()).toString(); + } + catch (NullPointerException e) { // row or cell does not exist + return ""; + } + } +} diff --git a/test-data/spreadsheet/tile-range-test.xls b/test-data/spreadsheet/tile-range-test.xls new file mode 100644 index 0000000000..231fe65e34 Binary files /dev/null and b/test-data/spreadsheet/tile-range-test.xls differ diff --git a/test-data/spreadsheet/tile-range-test.xlsx b/test-data/spreadsheet/tile-range-test.xlsx new file mode 100644 index 0000000000..fd6057b5cd Binary files /dev/null and b/test-data/spreadsheet/tile-range-test.xlsx differ