From: PJ Fanning Date: Fri, 15 May 2020 19:46:17 +0000 (+0000) Subject: [github-179] add an option for RangeCopier.copyRange() to clone styles. Thanks to... X-Git-Tag: before_ooxml_3rd_edition~271 X-Git-Url: https://source.dussan.org/?a=commitdiff_plain;h=9bddb8729eb517f18b47d4e9eb6ed5495631462d;p=poi.git [github-179] add an option for RangeCopier.copyRange() to clone styles. Thanks to xjlin0. This closes #179 git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1877792 13f79535-47bb-0310-9956-ffa450edef68 --- diff --git a/src/java/org/apache/poi/ss/usermodel/RangeCopier.java b/src/java/org/apache/poi/ss/usermodel/RangeCopier.java index 8409accc72..b9d42f61b9 100644 --- a/src/java/org/apache/poi/ss/usermodel/RangeCopier.java +++ b/src/java/org/apache/poi/ss/usermodel/RangeCopier.java @@ -19,6 +19,7 @@ package org.apache.poi.ss.usermodel; +import java.util.HashMap; import java.util.Map; import org.apache.poi.ss.formula.FormulaShifter; import org.apache.poi.ss.formula.ptg.Ptg; @@ -46,10 +47,25 @@ public abstract class RangeCopier { * 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 + * @param tileDestRange destination range, which should be overridden */ public void copyRange(CellRangeAddress tilePatternRange, CellRangeAddress tileDestRange) { + copyRange(tilePatternRange, tileDestRange, false, false); + } + + /** 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 + * @param copyStyles whether to copy the cell styles + * @param copyMergedRanges whether to copy merged ranges + * @since 4.1.3 + */ + public void copyRange(CellRangeAddress tilePatternRange, CellRangeAddress tileDestRange, boolean copyStyles, boolean copyMergedRanges) { Sheet sourceCopy = sourceSheet.getWorkbook().cloneSheet(sourceSheet.getWorkbook().getSheetIndex(sourceSheet)); + Map styleMap = copyStyles ? new HashMap() {} : null; int sourceWidthMinus1 = tilePatternRange.getLastColumn() - tilePatternRange.getFirstColumn(); int sourceHeightMinus1 = tilePatternRange.getLastRow() - tilePatternRange.getFirstRow(); int rightLimitToCopy; @@ -67,17 +83,21 @@ public abstract class RangeCopier { tilePatternRange.getFirstRow(), bottomLimitToCopy, tilePatternRange.getFirstColumn(), rightLimitToCopy ); - copyRange(rangeToCopy, nextCellIndexInRowToCopy - rangeToCopy.getFirstColumn(), nextRowIndexToCopy - rangeToCopy.getFirstRow(), sourceCopy); + copyRange(rangeToCopy, nextCellIndexInRowToCopy - rangeToCopy.getFirstColumn(), nextRowIndexToCopy - rangeToCopy.getFirstRow(), sourceCopy, styleMap); nextCellIndexInRowToCopy += widthToCopyMinus1 + 1; } while (nextCellIndexInRowToCopy <= tileDestRange.getLastColumn()); nextRowIndexToCopy += heightToCopyMinus1 + 1; } while (nextRowIndexToCopy <= tileDestRange.getLastRow()); + if (copyMergedRanges) { + sourceSheet.getMergedRegions().forEach((mergedRangeAddress) -> destSheet.addMergedRegion(mergedRangeAddress)); + } + 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 + private void copyRange(CellRangeAddress sourceRange, int deltaX, int deltaY, Sheet sourceClone, Map styleMap) { //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()); @@ -105,7 +125,7 @@ public abstract class RangeCopier { newCell = destRow.createCell(columnIndex + deltaX); } - cloneCellContent(sourceCell, newCell, null); + cloneCellContent(sourceCell, newCell, styleMap); if(newCell.getCellType() == CellType.FORMULA) adjustCellReferencesInsideFormula(newCell, destSheet, deltaX, deltaY); } diff --git a/src/testcases/org/apache/poi/ss/usermodel/TestRangeCopier.java b/src/testcases/org/apache/poi/ss/usermodel/TestRangeCopier.java index d00a820e3c..929abc35d4 100644 --- a/src/testcases/org/apache/poi/ss/usermodel/TestRangeCopier.java +++ b/src/testcases/org/apache/poi/ss/usermodel/TestRangeCopier.java @@ -19,14 +19,14 @@ 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; +import static org.junit.Assert.*; + @Ignore public abstract class TestRangeCopier { protected Sheet sheet1; @@ -116,13 +116,57 @@ public abstract class TestRangeCopier { assertEquals("1.2", getCellContent(sheet1, "G24")); } - protected static String getCellContent(Sheet sheet, String coordinates) { + @Test + public void testCopyStyles() { + String cellContent = "D6 aligned to the right"; + HorizontalAlignment toTheRight = HorizontalAlignment.RIGHT; + // create cell with content aligned to the right + CellStyle style = workbook.createCellStyle(); + style.setAlignment(toTheRight); + Cell cell = sheet1.createRow(5).createCell(3); + cell.setCellValue(cellContent); + cell.setCellStyle(style); + + Sheet destSheet = sheet2; + CellRangeAddress tileRange = CellRangeAddress.valueOf("D6:D6"); // on sheet1 + CellRangeAddress destRange = CellRangeAddress.valueOf("J6:J6"); // on sheet2 + transSheetRangeCopier.copyRange(tileRange, destRange, true, false); + assertEquals(cellContent, getCellContent(destSheet, "J6")); + assertEquals(toTheRight, getCell(destSheet, "J6").getCellStyle().getAlignment()); + } + + @Test + public void testMergedRanges() { + String cellContent = "D6 merged to E7"; + + // create cell merged from D6 to E7 + CellRangeAddress mergedRangeAddress = new CellRangeAddress(5,6,3,4); + Cell cell = sheet1.createRow(5).createCell(3); + cell.setCellValue(cellContent); + sheet1.addMergedRegion(mergedRangeAddress); + + Sheet destSheet = sheet2; + CellRangeAddress tileRange = CellRangeAddress.valueOf("D6:E7"); // on sheet1 + transSheetRangeCopier.copyRange(tileRange, tileRange, false, true); + assertEquals(cellContent, getCellContent(destSheet, "D6")); + assertFalse(destSheet.getMergedRegions().isEmpty()); + destSheet.getMergedRegions().forEach((mergedRegion) -> { + assertTrue(mergedRegion.equals(mergedRangeAddress)); + }); + } + + protected static String getCellContent(Sheet sheet, String coordinates) { + Cell cell = getCell(sheet, coordinates); + return cell == null ? "" : cell.toString(); + } + + protected static Cell getCell(Sheet sheet, String coordinates) { try { CellReference p = new CellReference(coordinates); - return sheet.getRow(p.getRow()).getCell(p.getCol()).toString(); + return sheet.getRow(p.getRow()).getCell(p.getCol()); } catch (NullPointerException e) { // row or cell does not exist - return ""; + return null; } } }