git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1903037 13f79535-47bb-0310-9956-ffa450edef68tags/REL_5_2_3
@@ -141,6 +141,7 @@ public class SXSSFRow implements Row, Comparable<SXSSFRow> | |||
checkBounds(column); | |||
SXSSFCell cell = new SXSSFCell(this, type); | |||
_cells.put(column, cell); | |||
_sheet.trackNewCell(cell); | |||
return cell; | |||
} | |||
@@ -27,6 +27,8 @@ import java.util.Set; | |||
import java.util.Spliterator; | |||
import java.util.TreeMap; | |||
import org.apache.logging.log4j.LogManager; | |||
import org.apache.logging.log4j.Logger; | |||
import org.apache.poi.ss.SpreadsheetVersion; | |||
import org.apache.poi.ss.usermodel.*; | |||
import org.apache.poi.ss.util.CellAddress; | |||
@@ -47,6 +49,8 @@ import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTWorksheet; | |||
* Streaming version of XSSFSheet implementing the "BigGridDemo" strategy. | |||
*/ | |||
public class SXSSFSheet implements Sheet, OoxmlSheetExtensions { | |||
private static final Logger LOG = LogManager.getLogger(SXSSFSheet.class); | |||
/*package*/ final XSSFSheet _sh; | |||
protected final SXSSFWorkbook _workbook; | |||
private final TreeMap<Integer,SXSSFRow> _rows = new TreeMap<>(); | |||
@@ -56,14 +60,38 @@ public class SXSSFSheet implements Sheet, OoxmlSheetExtensions { | |||
private int outlineLevelRow; | |||
private int lastFlushedRowNumber = -1; | |||
private boolean allFlushed; | |||
private int leftMostColumn = SpreadsheetVersion.EXCEL2007.getLastColumnIndex(); | |||
private int rightMostColumn; | |||
protected SXSSFSheet(SXSSFWorkbook workbook, XSSFSheet xSheet, int randomAccessWindowSize) { | |||
_workbook = workbook; | |||
_sh = xSheet; | |||
calculateLeftAndRightMostColumns(xSheet); | |||
setRandomAccessWindowSize(randomAccessWindowSize); | |||
_autoSizeColumnTracker = new AutoSizeColumnTracker(this); | |||
} | |||
private void calculateLeftAndRightMostColumns(XSSFSheet xssfSheet) { | |||
if (_workbook.shouldCalculateSheetDimensions()) { | |||
int rowCount = 0; | |||
int leftMostColumn = Integer.MAX_VALUE; | |||
int rightMostColumn = 0; | |||
for (Row row : xssfSheet) { | |||
rowCount++; | |||
if (row.getFirstCellNum() < leftMostColumn) { | |||
final int first = row.getFirstCellNum(); | |||
final int last = row.getLastCellNum() - 1; | |||
leftMostColumn = Math.min(first, leftMostColumn); | |||
rightMostColumn = Math.max(last, rightMostColumn); | |||
} | |||
} | |||
if (rowCount > 0) { | |||
this.leftMostColumn = leftMostColumn; | |||
this.rightMostColumn = rightMostColumn; | |||
} | |||
} | |||
} | |||
public SXSSFSheet(SXSSFWorkbook workbook, XSSFSheet xSheet) throws IOException { | |||
_workbook = workbook; | |||
_sh = xSheet; | |||
@@ -2106,4 +2134,21 @@ public class SXSSFSheet implements Sheet, OoxmlSheetExtensions { | |||
public void shiftColumns(int startColumn, int endColumn, int n){ | |||
throw new UnsupportedOperationException("Not Implemented"); | |||
} | |||
void trackNewCell(SXSSFCell cell) { | |||
leftMostColumn = Math.min(cell.getColumnIndex(), leftMostColumn); | |||
rightMostColumn = Math.max(cell.getColumnIndex(), rightMostColumn); | |||
} | |||
void deriveDimension() { | |||
if (_workbook.shouldCalculateSheetDimensions()) { | |||
try { | |||
CellRangeAddress cellRangeAddress = new CellRangeAddress( | |||
getFirstRowNum(), getLastRowNum(), leftMostColumn, rightMostColumn); | |||
_sh.setDimensionOverride(cellRangeAddress); | |||
} catch (Exception e) { | |||
LOG.atDebug().log("Failed to set dimension details on sheet", e); | |||
} | |||
} | |||
} | |||
} |
@@ -136,6 +136,8 @@ public class SXSSFWorkbook implements Workbook { | |||
*/ | |||
protected Zip64Mode zip64Mode = Zip64Mode.Always; | |||
private boolean shouldCalculateSheetDimensions = true; | |||
/** | |||
* Construct a new workbook with default row window size | |||
*/ | |||
@@ -351,6 +353,24 @@ public class SXSSFWorkbook implements Workbook { | |||
_compressTmpFiles = compress; | |||
} | |||
/** | |||
* @param shouldCalculateSheetDimensions defaults to <code>true</code>, set to <code>false</code> if | |||
* the calculated dimensions are causing trouble | |||
* @since POI 5.2.3 | |||
*/ | |||
public void setShouldCalculateSheetDimensions(boolean shouldCalculateSheetDimensions) { | |||
this.shouldCalculateSheetDimensions = shouldCalculateSheetDimensions; | |||
} | |||
/** | |||
* @return shouldCalculateSheetDimensions defaults to <code>true</code>, set to <code>false</code> if | |||
* the calculated dimensions are causing trouble | |||
* @since POI 5.2.3 | |||
*/ | |||
public boolean shouldCalculateSheetDimensions() { | |||
return shouldCalculateSheetDimensions; | |||
} | |||
@Internal | |||
protected SharedStringsTable getSharedStringSource() { | |||
return _sharedStringSource; | |||
@@ -971,8 +991,10 @@ public class SXSSFWorkbook implements Workbook { | |||
} | |||
//Substitute the template entries with the generated sheet data files | |||
try (ZipSecureFile zf = new ZipSecureFile(tmplFile); | |||
ZipFileZipEntrySource source = new ZipFileZipEntrySource(zf)) { | |||
try ( | |||
ZipSecureFile zf = new ZipSecureFile(tmplFile); | |||
ZipFileZipEntrySource source = new ZipFileZipEntrySource(zf) | |||
) { | |||
injectData(source, stream); | |||
} | |||
} finally { | |||
@@ -1012,8 +1034,8 @@ public class SXSSFWorkbook implements Workbook { | |||
} | |||
protected void flushSheets() throws IOException { | |||
for (SXSSFSheet sheet : _xFromSxHash.values()) | |||
{ | |||
for (SXSSFSheet sheet : _xFromSxHash.values()) { | |||
sheet.deriveDimension(); | |||
sheet.flushRows(); | |||
} | |||
} |
@@ -106,6 +106,7 @@ public class XSSFSheet extends POIXMLDocumentPart implements Sheet, OoxmlSheetEx | |||
private List<CellRangeAddress> arrayFormulas; | |||
private final XSSFDataValidationHelper dataValidationHelper; | |||
private XSSFVMLDrawing xssfvmlDrawing; | |||
private CellRangeAddress dimensionOverride; | |||
/** | |||
* Creates new XSSFSheet - called by XSSFWorkbook to create a sheet from scratch. | |||
@@ -3747,29 +3748,34 @@ public class XSSFSheet extends POIXMLDocumentPart implements Sheet, OoxmlSheetEx | |||
}*/ | |||
} | |||
int minCell = Integer.MAX_VALUE, maxCell = Integer.MIN_VALUE; | |||
for(Map.Entry<Integer, XSSFRow> entry : _rows.entrySet()) { | |||
XSSFRow row = entry.getValue(); | |||
CellRangeAddress cellRangeAddress = dimensionOverride; | |||
if (cellRangeAddress == null) { | |||
int minCell = Integer.MAX_VALUE, maxCell = Integer.MIN_VALUE; | |||
for(Map.Entry<Integer, XSSFRow> entry : _rows.entrySet()) { | |||
XSSFRow row = entry.getValue(); | |||
// first perform the normal write actions for the row | |||
row.onDocumentWrite(); | |||
// first perform the normal write actions for the row | |||
row.onDocumentWrite(); | |||
// then calculate min/max cell-numbers for the worksheet-dimension | |||
if(row.getFirstCellNum() != -1) { | |||
minCell = Math.min(minCell, row.getFirstCellNum()); | |||
// then calculate min/max cell-numbers for the worksheet-dimension | |||
if(row.getFirstCellNum() != -1) { | |||
minCell = Math.min(minCell, row.getFirstCellNum()); | |||
} | |||
if(row.getLastCellNum() != -1) { | |||
maxCell = Math.max(maxCell, row.getLastCellNum()-1); | |||
} | |||
} | |||
if(row.getLastCellNum() != -1) { | |||
maxCell = Math.max(maxCell, row.getLastCellNum()-1); | |||
// finally, if we had at least one cell we can populate the optional dimension-field | |||
if(minCell != Integer.MAX_VALUE) { | |||
cellRangeAddress = new CellRangeAddress(getFirstRowNum(), getLastRowNum(), minCell, maxCell); | |||
} | |||
} | |||
// finally, if we had at least one cell we can populate the optional dimension-field | |||
if(minCell != Integer.MAX_VALUE) { | |||
String ref = new CellRangeAddress(getFirstRowNum(), getLastRowNum(), minCell, maxCell).formatAsString(); | |||
if(worksheet.isSetDimension()) { | |||
worksheet.getDimension().setRef(ref); | |||
if (cellRangeAddress != null) { | |||
if (worksheet.isSetDimension()) { | |||
worksheet.getDimension().setRef(cellRangeAddress.formatAsString()); | |||
} else { | |||
worksheet.addNewDimension().setRef(ref); | |||
worksheet.addNewDimension().setRef(cellRangeAddress.formatAsString()); | |||
} | |||
} | |||
@@ -4051,6 +4057,9 @@ public class XSSFSheet extends POIXMLDocumentPart implements Sheet, OoxmlSheetEx | |||
* @since POI 5.2.3 | |||
*/ | |||
public CellRangeAddress getDimension() { | |||
if (dimensionOverride != null) { | |||
return dimensionOverride; | |||
} | |||
CTSheetDimension ctSheetDimension = worksheet.getDimension(); | |||
String ref = ctSheetDimension == null ? null : ctSheetDimension.getRef(); | |||
if (ref != null) { | |||
@@ -4845,4 +4854,14 @@ public class XSSFSheet extends POIXMLDocumentPart implements Sheet, OoxmlSheetEx | |||
public XSSFHeaderFooterProperties getHeaderFooterProperties() { | |||
return new XSSFHeaderFooterProperties(getSheetTypeHeaderFooter()); | |||
} | |||
/** | |||
* Currently, this is for internal use. Overrides the default dimensions of the sheet. | |||
* @param dimension {@link CellRangeAddress}, <code>null</code> removes the existing override | |||
* @since POI 5.2.3 | |||
*/ | |||
@Beta | |||
public void setDimensionOverride(CellRangeAddress dimension) { | |||
this.dimensionOverride = dimension; | |||
} | |||
} |
@@ -48,6 +48,7 @@ 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.usermodel.WorkbookFactory; | |||
import org.apache.poi.ss.util.CellRangeAddress; | |||
import org.apache.poi.ss.util.CellReference; | |||
import org.apache.poi.xssf.SXSSFITestDataProvider; | |||
import org.apache.poi.xssf.XSSFTestDataSamples; | |||
@@ -560,6 +561,45 @@ public final class TestSXSSFWorkbook extends BaseTestXWorkbook { | |||
} | |||
} | |||
@Test | |||
void addDimension() throws IOException { | |||
try ( | |||
SXSSFWorkbook wb = new SXSSFWorkbook(); | |||
UnsynchronizedByteArrayOutputStream bos = new UnsynchronizedByteArrayOutputStream() | |||
) { | |||
SXSSFSheet sheet = wb.createSheet(); | |||
sheet.createRow(2).createCell(3).setCellValue("top left"); | |||
sheet.createRow(6).createCell(5).setCellValue("bottom right"); | |||
assertEquals(2, sheet.getFirstRowNum()); | |||
assertEquals(6, sheet.getLastRowNum()); | |||
wb.write(bos); | |||
try (XSSFWorkbook xssfWorkbook = new XSSFWorkbook(bos.toInputStream())) { | |||
XSSFSheet xssfSheet = xssfWorkbook.getSheetAt(0); | |||
assertEquals(CellRangeAddress.valueOf("D3:F7"), xssfSheet.getDimension()); | |||
} | |||
} | |||
} | |||
@Test | |||
void addDimensionDisabled() throws IOException { | |||
try ( | |||
SXSSFWorkbook wb = new SXSSFWorkbook(); | |||
UnsynchronizedByteArrayOutputStream bos = new UnsynchronizedByteArrayOutputStream() | |||
) { | |||
wb.setShouldCalculateSheetDimensions(false); | |||
SXSSFSheet sheet = wb.createSheet(); | |||
sheet.createRow(2).createCell(3).setCellValue("top left"); | |||
sheet.createRow(6).createCell(5).setCellValue("bottom right"); | |||
assertEquals(2, sheet.getFirstRowNum()); | |||
assertEquals(6, sheet.getLastRowNum()); | |||
wb.write(bos); | |||
try (XSSFWorkbook xssfWorkbook = new XSSFWorkbook(bos.toInputStream())) { | |||
XSSFSheet xssfSheet = xssfWorkbook.getSheetAt(0); | |||
assertEquals(CellRangeAddress.valueOf("A1:A1"), xssfSheet.getDimension()); | |||
} | |||
} | |||
} | |||
@Override | |||
@Disabled("not implemented") | |||
protected void changeSheetNameWithSharedFormulas() { |