package org.apache.poi.xssf.usermodel;
import java.util.HashSet;
+import java.util.IdentityHashMap;
import java.util.Iterator;
+import java.util.List;
+import java.util.Objects;
import java.util.Set;
import java.util.TreeMap;
ctCell = _row.addNewC();
}
XSSFCell xcell = new XSSFCell(this, ctCell);
- xcell.setCellNum(columnIndex);
+ try {
+ xcell.setCellNum(columnIndex);
+ } catch (IllegalArgumentException e) {
+ // we need to undo adding the CTCell in _row if something fails here, e.g.
+ // cell-limits are exceeded
+ _row.removeC(_row.getCList().size()-1);
+
+ throw e;
+ }
if (type != CellType.BLANK && type != CellType.FORMULA) {
setDefaultValue(xcell, type);
}
if (cell.getRow() != this) {
throw new IllegalArgumentException("Specified cell does not belong to this row");
}
+ //noinspection SuspiciousMethodCalls
+ if(!_cells.containsValue(cell)) {
+ throw new IllegalArgumentException("the row does not contain this cell");
+ }
XSSFCell xcell = (XSSFCell)cell;
if(xcell.isPartOfArrayFormulaGroup()) {
}
// Performance optimization for bug 57840: explicit boxing is slightly faster than auto-unboxing, though may use more memory
final Integer colI = Integer.valueOf(cell.getColumnIndex()); // NOSONAR
- _cells.remove(colI);
+ XSSFCell removed = _cells.remove(colI);
+
+ // also remove the corresponding CTCell from the _row.cArray,
+ // it may not be at the same position right now
+ // thus search for it
+ int i = 0;
+ for (CTCell ctCell : _row.getCArray()) {
+ if(ctCell == removed.getCTCell()) {
+ _row.removeC(i);
+ }
+ i++;
+ }
}
/**
*
* @see org.apache.poi.xssf.usermodel.XSSFSheet#write(java.io.OutputStream) ()
*/
- protected void onDocumentWrite(){
- CTCell[] cArray = new CTCell[_cells.size()];
+ protected void onDocumentWrite() {
+ // _row.cArray and _cells.getCTCell might be out of sync after adding/removing cells,
+ // thus we need to re-order it here to make the resulting file correct
+
+ // copy all values to 2nd array and a map for lookup of index
+ List<CTCell> cArrayOrig = _row.getCList();
+ CTCell[] cArrayCopy = new CTCell[cArrayOrig.size()];
+ IdentityHashMap<CTCell, Integer> map = new IdentityHashMap<>(_cells.size());
int i = 0;
- for (XSSFCell xssfCell : _cells.values()) {
- cArray[i] = (CTCell) xssfCell.getCTCell().copy();
-
- // we have to copy and re-create the XSSFCell here because the
- // elements as otherwise setCArray below invalidates all the columns!
- // see Bug 56170, XMLBeans seems to always release previous objects
- // in the CArray, so we need to provide completely new ones here!
- //_cells.put(entry.getKey(), new XSSFCell(this, cArray[i]));
- xssfCell.setCTCell(cArray[i]);
+ for (CTCell ctCell : cArrayOrig) {
+ cArrayCopy[i] = (CTCell) ctCell.copy();
+ map.put(ctCell, i);
+ i++;
+ }
+
+ // populate _row.cArray correctly
+ i = 0;
+ for (XSSFCell cell : _cells.values()) {
+ // no need to change anything if position is correct
+ Integer correctPosition = map.get(cell.getCTCell());
+ Objects.requireNonNull(correctPosition, "Should find CTCell in _row");
+ if(correctPosition != i) {
+ // we need to re-populate this CTCell
+ _row.setCArray(i, cArrayCopy[correctPosition]);
+ cell.setCTCell(_row.getCArray(i));
+ }
i++;
}
- _row.setCArray(cArray);
+ // remove any remaining illegal references in _rows.cArray
+ while(cArrayOrig.size() > _cells.size()) {
+ _row.removeC(_cells.size());
+ }
}
/**
private void shiftCell(int columnIndex, int step/*pass negative value for left shift*/){
if(columnIndex + step < 0) {
- throw new IllegalStateException("Column index less than zero : " + (Integer.valueOf(columnIndex + step)).toString());
+ throw new IllegalStateException("Column index less than zero : " + (Integer.valueOf(columnIndex + step)));
}
XSSFCell currentCell = getCell(columnIndex);
package org.apache.poi.xssf.usermodel;
import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertSame;
workbook.close();
}
-
+
@Test
public void testMultipleEditWriteCycles() {
final XSSFWorkbook wb1 = new XSSFWorkbook();
final XSSFSheet sheet1 = wb1.createSheet("Sheet1");
- final XSSFRow srcRow = sheet1.createRow(0);
+ XSSFRow srcRow = sheet1.createRow(0);
srcRow.createCell(0).setCellValue("hello");
srcRow.createCell(3).setCellValue("world");
-
+
// discard result
XSSFTestDataSamples.writeOutAndReadBack(wb1);
+
+ assertEquals("hello", srcRow.getCell(0).getStringCellValue());
+ assertEquals("hello",
+ wb1.getSheet("Sheet1").getRow(0).getCell(0).getStringCellValue());
+ assertEquals("world", srcRow.getCell(3).getStringCellValue());
+ assertEquals("world",
+ wb1.getSheet("Sheet1").getRow(0).getCell(3).getStringCellValue());
+
srcRow.createCell(1).setCellValue("cruel");
+
// discard result
XSSFTestDataSamples.writeOutAndReadBack(wb1);
+ assertEquals("hello", srcRow.getCell(0).getStringCellValue());
+ assertEquals("hello",
+ wb1.getSheet("Sheet1").getRow(0).getCell(0).getStringCellValue());
+ assertEquals("cruel", srcRow.getCell(1).getStringCellValue());
+ assertEquals("cruel",
+ wb1.getSheet("Sheet1").getRow(0).getCell(1).getStringCellValue());
+ assertEquals("world", srcRow.getCell(3).getStringCellValue());
+ assertEquals("world",
+ wb1.getSheet("Sheet1").getRow(0).getCell(3).getStringCellValue());
+
srcRow.getCell(1).setCellValue((RichTextString) null);
-
+
XSSFWorkbook wb3 = XSSFTestDataSamples.writeOutAndReadBack(wb1);
- assertEquals("Cell not blank", CellType.BLANK, wb3.getSheet("Sheet1").getRow(0).getCell(1).getCellType());
+ assertEquals("Cell should be blank", CellType.BLANK,
+ wb3.getSheet("Sheet1").getRow(0).getCell(1).getCellType());
}
}