<!-- Don't forget to update status.xml too! -->
<release version="3.5-beta5" date="2008-??-??">
+ <action dev="POI-DEVELOPERS" type="fix">46536 - When shifting rows, update formulas on that sheet to point to the new location of those rows</action>
+ <action dev="POI-DEVELOPERS" type="fix">46663 - Fixed XSSFSheet.shiftRows to properly update references of the shifted cells</action>
<action dev="POI-DEVELOPERS" type="fix">46535 - Remove reference from calculation chain when a formula is deleted</action>
<action dev="POI-DEVELOPERS" type="fix">46654 - HSSFRow/RowRecord to properly update cell boundary indexes</action>
<action dev="POI-DEVELOPERS" type="fix">46643 - Fixed formula parser to encode range operator with tMemFunc</action>
<!-- Don't forget to update changes.xml too! -->
<changes>
<release version="3.5-beta5" date="2008-??-??">
+ <action dev="POI-DEVELOPERS" type="fix">46536 - When shifting rows, update formulas on that sheet to point to the new location of those rows</action>
+ <action dev="POI-DEVELOPERS" type="fix">46663 - Fixed XSSFSheet.shiftRows to properly update references of the shifted cells</action>
<action dev="POI-DEVELOPERS" type="fix">46535 - Remove reference from calculation chain when a formula is deleted</action>
<action dev="POI-DEVELOPERS" type="fix">46654 - HSSFRow/RowRecord to properly update cell boundary indexes</action>
<action dev="POI-DEVELOPERS" type="fix">46643 - Fixed formula parser to encode range operator with tMemFunc</action>
return cell;
}
- /**
- * update cell reference when shifting rows
- *
- * @param row
- */
- protected void modifyCellReference(XSSFRow row) {
- this.cell.setR(new CellReference(row.getRowNum(), cellNum).formatAsString());
-
- CTCell[] ctCells = row.getCTRow().getCArray();
- for (CTCell ctCell : ctCells) {
- ctCell.setR(new CellReference(row.getRowNum(), cellNum).formatAsString());
- }
- }
}
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.Row;
+import org.apache.poi.ss.util.CellReference;
+import org.apache.poi.ss.formula.FormulaParser;
+import org.apache.poi.ss.formula.FormulaType;
+import org.apache.poi.ss.formula.FormulaRenderer;
+import org.apache.poi.xssf.model.CalculationChain;
+import org.apache.poi.hssf.record.formula.Ptg;
+import org.apache.poi.hssf.record.SharedFormulaRecord;
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTCell;
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTRow;
+import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTCellFormula;
/**
* High level representation of a row of a spreadsheet.
public String toString(){
return row.toString();
}
+
+ /**
+ * update cell references when shifting rows
+ *
+ * @param n the number of rows to move
+ */
+ protected void shift(int n) {
+ XSSFSheet sheet = getSheet();
+ CalculationChain calcChain = sheet.getWorkbook().getCalculationChain();
+ int rownum = getRowNum() + n;
+ for(Cell c : this){
+ XSSFCell cell = (XSSFCell)c;
+
+ //remove the reference in the calculation chain
+ if(calcChain != null) calcChain.removeItem((int)sheet.sheet.getSheetId(), cell.getReference());
+
+ CTCell ctCell = cell.getCTCell();
+ String r = new CellReference(rownum, cell.getColumnIndex()).formatAsString();
+ ctCell.setR(r);
+
+ if(ctCell.isSetF()){
+ CTCellFormula f = ctCell.getF();
+ String fmla = f.getStringValue();
+ if(fmla.length() > 0) {
+ String shiftedFmla = shiftFormula(fmla, n);
+ f.setStringValue(shiftedFmla);
+ }
+ if(f.isSetRef()){ //Range of cells which the formula applies to.
+ String ref = f.getRef();
+ String shiftedRef = shiftFormula(ref, n);
+ f.setRef(shiftedRef);
+ }
+ }
+ }
+ setRowNum(rownum);
+ }
+
+ /**
+ * Shift a formula by the specified number of rows
+ * <p>
+ * Example: shiftFormula("A1+B1+C1", 3) will return "A4+B4+C4"
+ * </p>
+ *
+ * @param formula the formula to shift
+ * @param n the number of rows to shift
+ * @return the shifted formula
+ */
+ private String shiftFormula(String formula, int n){
+ XSSFSheet sheet = getSheet();
+ XSSFWorkbook wb = sheet.getWorkbook();
+ int sheetIndex = wb.getSheetIndex(sheet);
+ XSSFEvaluationWorkbook fpb = XSSFEvaluationWorkbook.create(wb);
+ Ptg[] ptgs = FormulaParser.parse(formula, fpb, FormulaType.CELL, sheetIndex);
+ Ptg[] fmla = SharedFormulaRecord.convertSharedFormulas(ptgs, n, 0);
+ return FormulaRenderer.toFormulaString(fpb, fmla);
+ }
+
}
import javax.xml.namespace.QName;
import org.apache.poi.hssf.util.PaneInformation;
-import org.apache.poi.ss.usermodel.CellStyle;
-import org.apache.poi.ss.usermodel.Footer;
-import org.apache.poi.ss.usermodel.Header;
-import org.apache.poi.ss.usermodel.Row;
-import org.apache.poi.ss.usermodel.Sheet;
+import org.apache.poi.hssf.record.formula.Ptg;
+import org.apache.poi.hssf.record.SharedFormulaRecord;
+import org.apache.poi.ss.usermodel.*;
import org.apache.poi.ss.util.CellRangeAddress;
import org.apache.poi.ss.util.CellReference;
+import org.apache.poi.ss.util.AreaReference;
+import org.apache.poi.ss.formula.FormulaParser;
+import org.apache.poi.ss.formula.FormulaType;
+import org.apache.poi.ss.formula.FormulaRenderer;
import org.apache.poi.xssf.model.CommentsTable;
+import org.apache.poi.xssf.model.CalculationChain;
import org.apache.poi.xssf.usermodel.helpers.ColumnHelper;
import org.apache.poi.POIXMLDocumentPart;
import org.apache.poi.POIXMLException;
*/
public void shiftRows(int startRow, int endRow, int n, boolean copyRowHeight, boolean resetOriginalRowHeight) {
for (Iterator<Row> it = rowIterator() ; it.hasNext() ; ) {
- Row row = it.next();
+ XSSFRow row = (XSSFRow)it.next();
if (!copyRowHeight) {
row.setHeight((short)-1);
it.remove();
}
else if (row.getRowNum() >= startRow && row.getRowNum() <= endRow) {
- row.setRowNum(row.getRowNum() + n);
- if (row.getFirstCellNum() > -1) {
- modifyCellReference((XSSFRow) row);
- }
+ row.shift(n);
}
}
//rebuild the rows map
rows = map;
}
-
- private void modifyCellReference(XSSFRow row) {
- for (int i = row.getFirstCellNum(); i <= row.getLastCellNum(); i++) {
- XSSFCell c = row.getCell(i);
- if (c != null) {
- c.modifyCellReference(row);
- }
- }
- }
-
/**
* Location of the top left visible cell Location of the top left visible cell in the bottom right
* pane (when in Left-to-Right mode).
import org.apache.poi.ss.util.CellRangeAddress;
import org.apache.poi.xssf.model.CommentsTable;
import org.apache.poi.xssf.model.StylesTable;
+import org.apache.poi.xssf.model.CalculationChain;
import org.apache.poi.xssf.usermodel.helpers.ColumnHelper;
import org.apache.poi.xssf.XSSFTestDataSamples;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
-import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTCol;
-import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTCols;
-import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTComments;
-import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTRow;
-import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTWorksheet;
-import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTXf;
-import org.openxmlformats.schemas.spreadsheetml.x2006.main.STPane;
+import org.openxmlformats.schemas.spreadsheetml.x2006.main.*;
public class TestXSSFSheet extends TestCase {
assertNull(sheet6.getRow(7));
assertEquals(8, sheet6.getPhysicalNumberOfRows());
}
-
+
+ /**
+ * When shifting rows, update formulas on that sheet to point to the new location of those rows
+ * (see bugzilla 46536)
+ */
+ public void testShiftRows_46536() {
+ XSSFWorkbook wb = XSSFTestDataSamples.openSampleWorkbook("46536.xlsx");
+ CalculationChain calcChain = wb.getCalculationChain();
+ int numItems = calcChain.getCTCalcChain().getCArray().length;
+ assertEquals(3, numItems);
+
+ XSSFSheet sheet = wb.getSheet("Test");
+ XSSFRow row2 = sheet.getRow(1);
+ XSSFCell cell_A2 = row2.getCell(0);
+ assertEquals("A2", cell_A2.getReference());
+
+ XSSFRow row3 = sheet.getRow(2);
+ XSSFCell cell_B3 = row3.getCell(1);
+ assertEquals("B3", cell_B3.getReference());
+
+ XSSFCell cell_E2 = row2.getCell(4);
+ CTCellFormula f = cell_E2.getCTCell().getF();
+ assertEquals("B2+C2+D2", f.getStringValue());
+ assertEquals("E2:E3", f.getRef());
+
+ sheet.shiftRows(1, sheet.getLastRowNum(), 3, false, true);
+
+ assertEquals(4, row2.getRowNum());
+ assertEquals(5, row3.getRowNum());
+ assertEquals("A5", cell_A2.getReference());
+ assertEquals("B6", cell_B3.getReference());
+
+ assertEquals("B5+C5+D5", f.getStringValue());
+ assertEquals("E5:E6", f.getRef());
+
+ numItems = calcChain.getCTCalcChain().getCArray().length;
+ assertEquals(1, numItems);
+
+ }
+
public void testGetCellComment() {
XSSFWorkbook workbook = new XSSFWorkbook();
XSSFSheet sheet = workbook.createSheet();