*/
public List<CellRangeAddress[]> shiftRowsRange(int startRow, int endRow, int n, int lCol, int rCol,
boolean copyRowHeight, boolean resetOriginalRowHeight, boolean moveComments, boolean clearRest, int copyOrigin) {
//prepare source format row
final int srcRownum = n <= 0 ? -1 : copyOrigin == Range.FORMAT_RIGHTBELOW ? startRow : copyOrigin == Range.FORMAT_LEFTABOVE ? startRow - 1 : -1;
final XSSFRow srcRow = srcRownum >= 0 ? getRow(srcRownum) : null;
final Map<Integer, Cell> srcCells = srcRow != null ? BookHelper.copyRowCells(srcRow, lCol, rCol) : null;
final short srcHeight = srcRow != null ? srcRow.getHeight() : -1;
// final XSSFCellStyle srcStyle = srcRow != null ? srcRow.getRowStyle() : null;
final int maxrow = SpreadsheetVersion.EXCEL2007.getLastRowIndex();
final int maxcol = SpreadsheetVersion.EXCEL2007.getLastColumnIndex();
if (endRow < 0) {
endRow = maxrow;
}
final List<CellRangeAddress[]> shiftedRanges = BookHelper.shiftMergedRegion(this, startRow, lCol, endRow, rCol, n, false);
final boolean wholeRow = lCol == 0 && rCol == maxcol;
final List<int[]> removePairs = new ArrayList<int[]>(); //row spans to be removed
final TreeMap<Integer, TreeMap<Integer, XSSFCell>> rowCells = new TreeMap<Integer, TreeMap<Integer, XSSFCell>>();
int expectRownum = startRow; //handle sparse rows which might override destination row
for (Iterator<Row> it = rowIterator() ; it.hasNext() ; ) { //TODO use submap between startRow and endRow
XSSFRow row = (XSSFRow)it.next();
int rownum = row.getRowNum();
if (rownum < startRow) continue;
if (rownum > endRow) break; //no more
final int newRownum = rownum + n;
if (rownum > expectRownum) { //sparse row between expectRownum(inclusive) and current row(exclusive), to be removed
addRemovePair(removePairs, expectRownum + n, newRownum);
}
expectRownum = rownum + 1;
final boolean inbound = 0 <= newRownum && newRownum <= maxrow;
if (!inbound) {
row.removeAllCells();
it.remove();
continue;
}
if (wholeRow) {
if (!copyRowHeight) {
row.setHeight((short)-1);
}
if (canRemoveRow(startRow, endRow, n, rownum)) {
it.remove();
}
else if (rownum >= startRow && rownum <= endRow) {
new XSSFRowHelper(row).shift(n);
}
} else {
SortedMap<Integer, XSSFCell> oldCells = row.getCells().subMap(Integer.valueOf(lCol), Integer.valueOf(rCol+1));
if (!oldCells.isEmpty()) {
TreeMap<Integer, XSSFCell> cells = new TreeMap<Integer, XSSFCell>(oldCells);
rowCells.put(newRownum, cells);
for (Cell cell : cells.values()) {
row.removeCell(cell);
}
}
}
if (moveComments) {
final CommentsTable sheetComments = getCommentsTable(false);
if(sheetComments != null){
//TODO shift Note's anchor in the associated /xl/drawing/vmlDrawings#.vml
CTCommentList lst = sheetComments.getCTComments().getCommentList();
for (CTComment comment : lst.getCommentArray()) {
CellReference ref = new CellReference(comment.getRef());
final int colnum = ref.getCol();
if(ref.getRow() == rownum && lCol <= colnum && colnum <= rCol){
ref = new CellReference(rownum + n, colnum);
comment.setRef(ref.formatAsString());
}
}
}
}
}
//rebuild rows ASAP or the getRow(rownum) will be incorrect
if (wholeRow) {
TreeMap<Integer, XSSFRow> map = new TreeMap<Integer, XSSFRow>();
TreeMap<Integer, XSSFRow> rows = getRows();
for(XSSFRow r : rows.values()) {
map.put(r.getRowNum(), r);
}
setRows(map);
}
//sparse row between expectRownum(inclusive) to endRow+1(exclusive), to be removed
addRemovePair(removePairs, expectRownum + n, endRow + 1 + n);
//really remove rows
if (wholeRow) {
for(int[] pair : removePairs) {
final int start = Math.max(0, pair[0]);
final int end = Math.min(SpreadsheetVersion.EXCEL2007.getLastRowIndex() + 1, pair[1]);
for(int j=start; j < end; ++j) {
Row row = getRow(j);
if (row != null) {
removeRow(row);
}
}
}
} else { //clear cells between lCol and rCol
for(int[] pair : removePairs) {
final int start = Math.max(0, pair[0]);
final int end = pair[1];
for(int j=start; j < end; ++j) {
Row row = getRow(j);
if (row != null) {
removeCells(row, lCol, rCol);
}
}
}
}
//really update the row's cells
for (Entry<Integer, TreeMap<Integer, XSSFCell>> entry : rowCells.entrySet()) {
final int rownum = entry.getKey().intValue();
final TreeMap<Integer, XSSFCell> cells = entry.getValue();
XSSFRow row = getRow(rownum);
if (row == null) {
row = createRow(rownum);
} else {
removeCells(row, lCol, rCol);
}
for(Entry<Integer, XSSFCell> cellentry : cells.entrySet()) {
final int colnum = cellentry.getKey().intValue();
final XSSFCell srcCell = cellentry.getValue();
BookHelper.assignCell(srcCell, row.createCell(colnum));
}
}
//handle inserted rows
if (srcRow != null) {
final int row2 = Math.min(startRow + n - 1, SpreadsheetVersion.EXCEL2007.getLastRowIndex());
for ( int rownum = startRow; rownum <= row2; ++rownum) {
XSSFRow row = getRow(rownum);
if (row == null) {
row = createRow(rownum);
}
row.setHeight(srcHeight); //height
// if (srcStyle != null) {
// row.setRowStyle((HSSFCellStyle)copyFromStyleExceptBorder(srcStyle));//style
// }
if (srcCells != null) {
for (Entry<Integer, Cell> cellEntry : srcCells.entrySet()) {
final Cell srcCell = cellEntry.getValue();
final CellStyle cellStyle = srcCell.getCellStyle();
final int c = cellEntry.getKey().intValue();
Cell cell = row.getCell(c);
if (cell == null) {
cell = row.createCell(c);
}
cell.setCellStyle(BookHelper.copyFromStyleExceptBorder(getBook(), cellStyle));
}
}
}
}
// Shift Hyperlinks which have been moved
shiftHyperlinks(startRow, endRow, n, 0, maxcol, 0);
//special case1: endRow < startRow
//special case2: (endRow - startRow + 1) < ABS(n)
if (n < 0) {
if (endRow < startRow) { //special case1
final int orgStartRow = startRow + n;
for ( int rowNum = orgStartRow; rowNum >= orgStartRow && rowNum <= endRow && rowNum >= 0 && rowNum <= maxrow; ++rowNum) {
final XSSFRow row = getRow( rowNum );
if (row != null) {
removeRow(row);
}
}
removeHyperlinks(orgStartRow, endRow, 0, maxcol);
} else if (clearRest) { //special case 2
final int orgStartRow = endRow + n + 1;
if (orgStartRow <= startRow) {
for ( int rowNum = orgStartRow; rowNum >= orgStartRow && rowNum <= startRow && rowNum >= 0 && rowNum <= maxrow; ++rowNum) {
final XSSFRow row = getRow( rowNum );
if (row != null) {
removeRow(row);
}
}
removeHyperlinks(orgStartRow, startRow, 0, maxcol);