From 2b08cd8946f9413d66e3b10b11cffbe2771b46b5 Mon Sep 17 00:00:00 2001 From: Dominik Stadler Date: Sun, 31 Aug 2014 20:24:42 +0000 Subject: [PATCH] Bug 55280: Implement a method XSSFSheet.removeMergedRegions() to bulk remove merged regions and thus speed up shifting rows with many merged regions greatly. git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1621633 13f79535-47bb-0310-9956-ffa450edef68 --- .../apache/poi/xssf/usermodel/XSSFSheet.java | 82 +++++++------------ .../usermodel/helpers/XSSFRowShifter.java | 13 ++- .../usermodel/TestXSSFSheetShiftRows.java | 12 +++ 3 files changed, 52 insertions(+), 55 deletions(-) diff --git a/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFSheet.java b/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFSheet.java index 543263f7af..60ecf7bb9f 100644 --- a/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFSheet.java +++ b/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFSheet.java @@ -26,6 +26,7 @@ import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; +import java.util.Set; import java.util.TreeMap; import javax.xml.namespace.QName; @@ -43,16 +44,7 @@ import org.apache.poi.openxml4j.opc.TargetMode; import org.apache.poi.ss.SpreadsheetVersion; import org.apache.poi.ss.formula.FormulaShifter; import org.apache.poi.ss.formula.SheetNameFormatter; -import org.apache.poi.ss.usermodel.Cell; -import org.apache.poi.ss.usermodel.CellRange; -import org.apache.poi.ss.usermodel.CellStyle; -import org.apache.poi.ss.usermodel.DataValidation; -import org.apache.poi.ss.usermodel.DataValidationHelper; -import org.apache.poi.ss.usermodel.Footer; -import org.apache.poi.ss.usermodel.Header; -import org.apache.poi.ss.usermodel.IndexedColors; -import org.apache.poi.ss.usermodel.Row; -import org.apache.poi.ss.usermodel.Sheet; +import org.apache.poi.ss.usermodel.*; import org.apache.poi.ss.util.AreaReference; import org.apache.poi.ss.util.CellRangeAddress; import org.apache.poi.ss.util.CellRangeAddressList; @@ -70,48 +62,7 @@ import org.apache.poi.xssf.usermodel.helpers.XSSFRowShifter; import org.apache.xmlbeans.XmlException; import org.apache.xmlbeans.XmlOptions; import org.openxmlformats.schemas.officeDocument.x2006.relationships.STRelationshipId; -import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTAutoFilter; -import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTBreak; -import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTCalcPr; -import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTCell; -import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTCellFormula; -import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTCol; -import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTColor; -import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTCols; -import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTComment; -import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTCommentList; -import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTDataValidation; -import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTDataValidations; -import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTDrawing; -import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTHeaderFooter; -import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTHyperlink; -import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTLegacyDrawing; -import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTMergeCell; -import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTMergeCells; -import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTOutlinePr; -import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTPageBreak; -import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTPageMargins; -import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTPageSetUpPr; -import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTPane; -import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTPrintOptions; -import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTRow; -import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTSelection; -import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTSheet; -import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTSheetCalcPr; -import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTSheetFormatPr; -import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTSheetPr; -import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTSheetProtection; -import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTSheetView; -import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTSheetViews; -import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTTablePart; -import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTTableParts; -import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTWorksheet; -import org.openxmlformats.schemas.spreadsheetml.x2006.main.STCalcMode; -import org.openxmlformats.schemas.spreadsheetml.x2006.main.STCellFormulaType; -import org.openxmlformats.schemas.spreadsheetml.x2006.main.STPane; -import org.openxmlformats.schemas.spreadsheetml.x2006.main.STPaneState; -import org.openxmlformats.schemas.spreadsheetml.x2006.main.STUnsignedShortHex; -import org.openxmlformats.schemas.spreadsheetml.x2006.main.WorksheetDocument; +import org.openxmlformats.schemas.spreadsheetml.x2006.main.*; /** * High level representation of a SpreadsheetML worksheet. @@ -1595,6 +1546,33 @@ public class XSSFSheet extends POIXMLDocumentPart implements Sheet { worksheet.unsetMergeCells(); } } + + /** + * Removes a number of merged regions of cells (hence letting them free) + * + * This method can be used to bulk-remove merged regions in a way + * much faster than calling removeMergedRegion() for every single + * merged region. + * + * @param indices A set of the regions to unmerge + */ + public void removeMergedRegions(Set indices) { + CTMergeCells ctMergeCells = worksheet.getMergeCells(); + + int size = ctMergeCells.sizeOfMergeCellArray(); + CTMergeCell[] mergeCellsArray = new CTMergeCell[size - indices.size()]; + for (int i = 0, d = 0 ; i < size ; i++) { + if(!indices.contains(i)) { + mergeCellsArray[d] = ctMergeCells.getMergeCellArray(i); + d++; + } + } + if(mergeCellsArray.length > 0){ + ctMergeCells.setMergeCellArray(mergeCellsArray); + } else{ + worksheet.unsetMergeCells(); + } + } /** * Remove a row from this sheet. All cells contained in the row are removed as well diff --git a/src/ooxml/java/org/apache/poi/xssf/usermodel/helpers/XSSFRowShifter.java b/src/ooxml/java/org/apache/poi/xssf/usermodel/helpers/XSSFRowShifter.java index b5614082e2..9ec69d1795 100644 --- a/src/ooxml/java/org/apache/poi/xssf/usermodel/helpers/XSSFRowShifter.java +++ b/src/ooxml/java/org/apache/poi/xssf/usermodel/helpers/XSSFRowShifter.java @@ -18,7 +18,9 @@ package org.apache.poi.xssf.usermodel.helpers; import java.util.ArrayList; +import java.util.HashSet; import java.util.List; +import java.util.Set; import org.apache.poi.ss.formula.FormulaParseException; import org.apache.poi.ss.formula.FormulaParser; @@ -67,8 +69,10 @@ public final class XSSFRowShifter { */ public List shiftMerged(int startRow, int endRow, int n) { List shiftedRegions = new ArrayList(); + Set removedIndices = new HashSet(); //move merged regions completely if they fall within the new region boundaries when they are shifted - for (int i = 0; i < sheet.getNumMergedRegions(); i++) { + int size = sheet.getNumMergedRegions(); + for (int i = 0; i < size; i++) { CellRangeAddress merged = sheet.getMergedRegion(i); boolean inStart = (merged.getFirstRow() >= startRow || merged.getLastRow() >= startRow); @@ -85,10 +89,13 @@ public final class XSSFRowShifter { merged.setLastRow(merged.getLastRow() + n); //have to remove/add it back shiftedRegions.add(merged); - sheet.removeMergedRegion(i); - i = i - 1; // we have to back up now since we removed one + removedIndices.add(i); } } + + if(!removedIndices.isEmpty()) { + sheet.removeMergedRegions(removedIndices); + } //read so it doesn't get shifted again for (CellRangeAddress region : shiftedRegions) { diff --git a/src/ooxml/testcases/org/apache/poi/xssf/usermodel/TestXSSFSheetShiftRows.java b/src/ooxml/testcases/org/apache/poi/xssf/usermodel/TestXSSFSheetShiftRows.java index d7bfc2f769..d3729e0c92 100644 --- a/src/ooxml/testcases/org/apache/poi/xssf/usermodel/TestXSSFSheetShiftRows.java +++ b/src/ooxml/testcases/org/apache/poi/xssf/usermodel/TestXSSFSheetShiftRows.java @@ -25,9 +25,11 @@ import org.apache.poi.ss.usermodel.Comment; import org.apache.poi.ss.usermodel.Row; import org.apache.poi.ss.usermodel.Sheet; import org.apache.poi.ss.usermodel.Workbook; +import org.apache.poi.ss.util.CellRangeAddress; import org.apache.poi.ss.util.CellUtil; import org.apache.poi.xssf.XSSFITestDataProvider; import org.apache.poi.xssf.XSSFTestDataSamples; +import org.junit.Test; /** * @author Yegor Kozlov @@ -187,4 +189,14 @@ public final class TestXSSFSheetShiftRows extends BaseTestSheetShiftRows { assertEquals("Amdocs", comment.getAuthor()); assertEquals("Amdocs:\ntest\n", comment.getString().getString()); } + + @Test + public void testBug55280() { + Workbook w = new XSSFWorkbook(); + Sheet s = w.createSheet(); + for (int row = 0; row < 5000; ++row) + s.addMergedRegion(new CellRangeAddress(row, row, 0, 3)); + + s.shiftRows(0, 4999, 1); // takes a long time... + } }