From: Yegor Kozlov Date: Sun, 8 Feb 2009 16:35:27 +0000 (+0000) Subject: improved XSSFSheet.shiftRows: 1. properly update cell references of the shifted cells... X-Git-Tag: REL_3_5_BETA5~1 X-Git-Url: https://source.dussan.org/?a=commitdiff_plain;h=73b8bf48af59614f4683e6303a80939b3f8630fd;p=poi.git improved XSSFSheet.shiftRows: 1. properly update cell references of the shifted cells (bugzilla 4663) 2. When shifting rows, update formulas on that sheet to point to the new location of those rows (bugzilla 46536) git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@742126 13f79535-47bb-0310-9956-ffa450edef68 --- diff --git a/src/documentation/content/xdocs/changes.xml b/src/documentation/content/xdocs/changes.xml index 9a22b181d3..5908abf00c 100644 --- a/src/documentation/content/xdocs/changes.xml +++ b/src/documentation/content/xdocs/changes.xml @@ -37,6 +37,8 @@ + 46536 - When shifting rows, update formulas on that sheet to point to the new location of those rows + 46663 - Fixed XSSFSheet.shiftRows to properly update references of the shifted cells 46535 - Remove reference from calculation chain when a formula is deleted 46654 - HSSFRow/RowRecord to properly update cell boundary indexes 46643 - Fixed formula parser to encode range operator with tMemFunc diff --git a/src/documentation/content/xdocs/status.xml b/src/documentation/content/xdocs/status.xml index e44a128436..4bb55ec397 100644 --- a/src/documentation/content/xdocs/status.xml +++ b/src/documentation/content/xdocs/status.xml @@ -34,6 +34,8 @@ + 46536 - When shifting rows, update formulas on that sheet to point to the new location of those rows + 46663 - Fixed XSSFSheet.shiftRows to properly update references of the shifted cells 46535 - Remove reference from calculation chain when a formula is deleted 46654 - HSSFRow/RowRecord to properly update cell boundary indexes 46643 - Fixed formula parser to encode range operator with tMemFunc diff --git a/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFCell.java b/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFCell.java index b7d2713f58..26fb2dc8a5 100644 --- a/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFCell.java +++ b/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFCell.java @@ -826,17 +826,4 @@ public final class XSSFCell implements Cell { 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()); - } - } } diff --git a/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFRow.java b/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFRow.java index 1011ecaf32..88563ec268 100644 --- a/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFRow.java +++ b/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFRow.java @@ -21,8 +21,16 @@ import java.util.*; 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. @@ -391,4 +399,61 @@ public class XSSFRow implements Row, Comparable { 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 + *

+ * Example: shiftFormula("A1+B1+C1", 3) will return "A4+B4+C4" + *

+ * + * @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); + } + } diff --git a/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFSheet.java b/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFSheet.java index b1ed009358..90f920c3e7 100644 --- a/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFSheet.java +++ b/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFSheet.java @@ -24,14 +24,17 @@ import java.util.*; 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; @@ -1438,7 +1441,7 @@ public class XSSFSheet extends POIXMLDocumentPart implements Sheet { */ public void shiftRows(int startRow, int endRow, int n, boolean copyRowHeight, boolean resetOriginalRowHeight) { for (Iterator it = rowIterator() ; it.hasNext() ; ) { - Row row = it.next(); + XSSFRow row = (XSSFRow)it.next(); if (!copyRowHeight) { row.setHeight((short)-1); @@ -1451,10 +1454,7 @@ public class XSSFSheet extends POIXMLDocumentPart implements Sheet { 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 @@ -1463,16 +1463,6 @@ public class XSSFSheet extends POIXMLDocumentPart implements Sheet { 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). diff --git a/src/ooxml/testcases/org/apache/poi/xssf/usermodel/TestXSSFSheet.java b/src/ooxml/testcases/org/apache/poi/xssf/usermodel/TestXSSFSheet.java index 61a0b5e94d..38ad08f64e 100644 --- a/src/ooxml/testcases/org/apache/poi/xssf/usermodel/TestXSSFSheet.java +++ b/src/ooxml/testcases/org/apache/poi/xssf/usermodel/TestXSSFSheet.java @@ -27,16 +27,11 @@ import org.apache.poi.ss.usermodel.Workbook; 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 { @@ -608,7 +603,46 @@ 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(); diff --git a/src/testcases/org/apache/poi/hssf/data/46536.xlsx b/src/testcases/org/apache/poi/hssf/data/46536.xlsx new file mode 100755 index 0000000000..9b625bf369 Binary files /dev/null and b/src/testcases/org/apache/poi/hssf/data/46536.xlsx differ