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
This commit is contained in:
Dominik Stadler 2014-08-31 20:24:42 +00:00
parent 3eec314719
commit a8f284d5f5
3 changed files with 52 additions and 55 deletions

View File

@ -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<Integer> 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

View File

@ -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<CellRangeAddress> shiftMerged(int startRow, int endRow, int n) {
List<CellRangeAddress> shiftedRegions = new ArrayList<CellRangeAddress>();
Set<Integer> removedIndices = new HashSet<Integer>();
//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) {

View File

@ -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...
}
}