Ви не можете вибрати більше 25 тем Теми мають розпочинатися з літери або цифри, можуть містити дефіси (-) і не повинні перевищувати 35 символів.

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159
  1. /*
  2. * ====================================================================
  3. * Licensed to the Apache Software Foundation (ASF) under one or more
  4. * contributor license agreements. See the NOTICE file distributed with
  5. * this work for additional information regarding copyright ownership.
  6. * The ASF licenses this file to You under the Apache License, Version 2.0
  7. * (the "License"); you may not use this file except in compliance with
  8. * the License. You may obtain a copy of the License at
  9. *
  10. * http://www.apache.org/licenses/LICENSE-2.0
  11. *
  12. * Unless required by applicable law or agreed to in writing, software
  13. * distributed under the License is distributed on an "AS IS" BASIS,
  14. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  15. * See the License for the specific language governing permissions and
  16. * limitations under the License.
  17. * ====================================================================
  18. */
  19. package org.apache.poi.ss.usermodel;
  20. import java.util.Map;
  21. import org.apache.poi.ss.formula.FormulaShifter;
  22. import org.apache.poi.ss.formula.ptg.Ptg;
  23. import org.apache.poi.ss.util.CellRangeAddress;
  24. import org.apache.poi.util.Beta;
  25. @Beta
  26. public abstract class RangeCopier {
  27. private Sheet sourceSheet;
  28. private Sheet destSheet;
  29. private FormulaShifter horizontalFormulaShifter;
  30. private FormulaShifter verticalFormulaShifter;
  31. public RangeCopier(Sheet sourceSheet, Sheet destSheet) {
  32. this.sourceSheet = sourceSheet;
  33. this.destSheet = destSheet;
  34. }
  35. public RangeCopier(Sheet sheet) {
  36. this(sheet, sheet);
  37. }
  38. /** Uses input pattern to tile destination region, overwriting existing content. Works in following manner :
  39. * 1.Start from top-left of destination.
  40. * 2.Paste source but only inside of destination borders.
  41. * 3.If there is space left on right or bottom side of copy, process it as in step 2.
  42. * @param tilePatternRange source range which should be copied in tiled manner
  43. * @param tileDestRange destination range, which should be overridden
  44. */
  45. public void copyRange(CellRangeAddress tilePatternRange, CellRangeAddress tileDestRange) {
  46. Sheet sourceCopy = sourceSheet.getWorkbook().cloneSheet(sourceSheet.getWorkbook().getSheetIndex(sourceSheet));
  47. int sourceWidthMinus1 = tilePatternRange.getLastColumn() - tilePatternRange.getFirstColumn();
  48. int sourceHeightMinus1 = tilePatternRange.getLastRow() - tilePatternRange.getFirstRow();
  49. int rightLimitToCopy;
  50. int bottomLimitToCopy;
  51. int nextRowIndexToCopy = tileDestRange.getFirstRow();
  52. do {
  53. int nextCellIndexInRowToCopy = tileDestRange.getFirstColumn();
  54. int heightToCopyMinus1 = Math.min(sourceHeightMinus1, tileDestRange.getLastRow() - nextRowIndexToCopy);
  55. bottomLimitToCopy = tilePatternRange.getFirstRow() + heightToCopyMinus1;
  56. do {
  57. int widthToCopyMinus1 = Math.min(sourceWidthMinus1, tileDestRange.getLastColumn() - nextCellIndexInRowToCopy);
  58. rightLimitToCopy = tilePatternRange.getFirstColumn() + widthToCopyMinus1;
  59. CellRangeAddress rangeToCopy = new CellRangeAddress(
  60. tilePatternRange.getFirstRow(), bottomLimitToCopy,
  61. tilePatternRange.getFirstColumn(), rightLimitToCopy
  62. );
  63. copyRange(rangeToCopy, nextCellIndexInRowToCopy - rangeToCopy.getFirstColumn(), nextRowIndexToCopy - rangeToCopy.getFirstRow(), sourceCopy);
  64. nextCellIndexInRowToCopy += widthToCopyMinus1 + 1;
  65. } while (nextCellIndexInRowToCopy <= tileDestRange.getLastColumn());
  66. nextRowIndexToCopy += heightToCopyMinus1 + 1;
  67. } while (nextRowIndexToCopy <= tileDestRange.getLastRow());
  68. int tempCopyIndex = sourceSheet.getWorkbook().getSheetIndex(sourceCopy);
  69. sourceSheet.getWorkbook().removeSheetAt(tempCopyIndex);
  70. }
  71. 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
  72. if(deltaX != 0)
  73. horizontalFormulaShifter = FormulaShifter.createForColumnCopy(sourceSheet.getWorkbook().getSheetIndex(sourceSheet),
  74. sourceSheet.getSheetName(), sourceRange.getFirstColumn(), sourceRange.getLastColumn(), deltaX, sourceSheet.getWorkbook().getSpreadsheetVersion());
  75. if(deltaY != 0)
  76. verticalFormulaShifter = FormulaShifter.createForRowCopy(sourceSheet.getWorkbook().getSheetIndex(sourceSheet),
  77. sourceSheet.getSheetName(), sourceRange.getFirstRow(), sourceRange.getLastRow(), deltaY, sourceSheet.getWorkbook().getSpreadsheetVersion());
  78. for(int rowNo = sourceRange.getFirstRow(); rowNo <= sourceRange.getLastRow(); rowNo++) {
  79. Row sourceRow = sourceClone.getRow(rowNo); // copy from source copy, original source might be overridden in process!
  80. for (int columnIndex = sourceRange.getFirstColumn(); columnIndex <= sourceRange.getLastColumn(); columnIndex++) {
  81. Cell sourceCell = sourceRow.getCell(columnIndex);
  82. if(sourceCell == null)
  83. continue;
  84. Row destRow = destSheet.getRow(rowNo + deltaY);
  85. if(destRow == null)
  86. destRow = destSheet.createRow(rowNo + deltaY);
  87. Cell newCell = destRow.getCell(columnIndex + deltaX);
  88. if(newCell != null)
  89. newCell.setCellType(sourceCell.getCellType());
  90. else newCell = destRow.createCell(columnIndex + deltaX, sourceCell.getCellType());
  91. cloneCellContent(sourceCell, newCell, null);
  92. if(newCell.getCellType() == CellType.FORMULA)
  93. adjustCellReferencesInsideFormula(newCell, destSheet, deltaX, deltaY);
  94. }
  95. }
  96. }
  97. protected abstract void adjustCellReferencesInsideFormula(Cell cell, Sheet destSheet, int deltaX, int deltaY); // this part is different for HSSF and XSSF
  98. protected boolean adjustInBothDirections(Ptg[] ptgs, int sheetIndex, int deltaX, int deltaY) {
  99. boolean adjustSucceeded = true;
  100. if(deltaY != 0)
  101. adjustSucceeded = verticalFormulaShifter.adjustFormula(ptgs, sheetIndex);
  102. if(deltaX != 0)
  103. adjustSucceeded = adjustSucceeded && horizontalFormulaShifter.adjustFormula(ptgs, sheetIndex);
  104. return adjustSucceeded;
  105. }
  106. // TODO clone some more properties ?
  107. public static void cloneCellContent(Cell srcCell, Cell destCell, Map<Integer, CellStyle> styleMap) {
  108. if(styleMap != null) {
  109. if(srcCell.getSheet().getWorkbook() == destCell.getSheet().getWorkbook()){
  110. destCell.setCellStyle(srcCell.getCellStyle());
  111. } else {
  112. int stHashCode = srcCell.getCellStyle().hashCode();
  113. CellStyle newCellStyle = styleMap.get(stHashCode);
  114. if(newCellStyle == null){
  115. newCellStyle = destCell.getSheet().getWorkbook().createCellStyle();
  116. newCellStyle.cloneStyleFrom(srcCell.getCellStyle());
  117. styleMap.put(stHashCode, newCellStyle);
  118. }
  119. destCell.setCellStyle(newCellStyle);
  120. }
  121. }
  122. switch(srcCell.getCellType()) {
  123. case STRING:
  124. destCell.setCellValue(srcCell.getStringCellValue());
  125. break;
  126. case NUMERIC:
  127. destCell.setCellValue(srcCell.getNumericCellValue());
  128. break;
  129. case BLANK:
  130. destCell.setCellType(CellType.BLANK);
  131. break;
  132. case BOOLEAN:
  133. destCell.setCellValue(srcCell.getBooleanCellValue());
  134. break;
  135. case ERROR:
  136. destCell.setCellErrorValue(srcCell.getErrorCellValue());
  137. break;
  138. case FORMULA:
  139. String oldFormula = srcCell.getCellFormula();
  140. destCell.setCellFormula(oldFormula);
  141. break;
  142. default:
  143. break;
  144. }
  145. }
  146. }