]> source.dussan.org Git - poi.git/commitdiff
[github-94] Add Range Copier. Thanks to Dragan Jovanović. This closes #94
authorPJ Fanning <fanningpj@apache.org>
Wed, 14 Feb 2018 20:30:01 +0000 (20:30 +0000)
committerPJ Fanning <fanningpj@apache.org>
Wed, 14 Feb 2018 20:30:01 +0000 (20:30 +0000)
git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1824266 13f79535-47bb-0310-9956-ffa450edef68

12 files changed:
src/java/org/apache/poi/hssf/usermodel/HSSFRangeCopier.java [new file with mode: 0644]
src/java/org/apache/poi/ss/usermodel/RangeCopier.java [new file with mode: 0644]
src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFRangeCopier.java [new file with mode: 0644]
src/ooxml/testcases/org/apache/poi/ss/usermodel/TestXSSFRangeCopier.java [new file with mode: 0644]
src/ooxml/testcases/org/apache/poi/xssf/usermodel/TestXSSFSheetShiftColumns.java
src/ooxml/testcases/org/apache/poi/xssf/usermodel/helpers/TestXSSFColumnShifting.java
src/testcases/org/apache/poi/hssf/usermodel/TestHSSFRangeCopier.java [new file with mode: 0644]
src/testcases/org/apache/poi/hssf/usermodel/TestHSSFSheetShiftColumns.java
src/testcases/org/apache/poi/ss/usermodel/BaseTestSheetShiftColumns.java
src/testcases/org/apache/poi/ss/usermodel/TestRangeCopier.java [new file with mode: 0644]
test-data/spreadsheet/tile-range-test.xls [new file with mode: 0644]
test-data/spreadsheet/tile-range-test.xlsx [new file with mode: 0644]

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 (file)
index 0000000..f6d3fb3
--- /dev/null
@@ -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 (file)
index 0000000..ea3bc4e
--- /dev/null
@@ -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<Integer, CellStyle> 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 (file)
index 0000000..9269843
--- /dev/null
@@ -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 (file)
index 0000000..405390f
--- /dev/null
@@ -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());
+    }
+    
+}
index f912b439091ec454682d6350b3159336995cfa7a..45bb31e3a31014a9dd3d651d6eab745972bfb54d 100644 (file)
@@ -40,4 +40,4 @@ public class TestXSSFSheetShiftColumns extends BaseTestSheetShiftColumns {
         return XSSFTestDataSamples.writeOutAndReadBack(wb);
     }
 
-}
+}
\ No newline at end of file
index e976294f1f28147df448130322d573fa00687ff1..67767aea50aab732473db1d789f229e9efaeee78 100644 (file)
@@ -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 (file)
index 0000000..8f6b678
--- /dev/null
@@ -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);
+    }
+}
index b9afa51a1658b0ea2184be61fda1e48eda4965c3..f5be8470d2f055887995854bc722e850a31b2434 100644 (file)
@@ -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 <https://bz.apache.org/bugzilla/show_bug.cgi?id=62030>")
     @Test
index 884e3a8119ca3e6886edad92de0843cd160ab2b9..3f146a8fb0a60f6ebd1b16b3ea36dc3515e5d30a 100644 (file)
@@ -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 (file)
index 0000000..def64a3
--- /dev/null
@@ -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 (file)
index 0000000..231fe65
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 (file)
index 0000000..fd6057b
Binary files /dev/null and b/test-data/spreadsheet/tile-range-test.xlsx differ