| /* ==================================================================== |
| Licensed to the Apache Software Foundation (ASF) under one or more |
| contributor license agreements. See the NOTICE file distributed with |
| this work for additional information regarding copyright ownership. |
| The ASF licenses this file to You under the Apache License, Version 2.0 |
| (the "License"); you may not use this file except in compliance with |
| the License. You may obtain a copy of the License at |
| |
| http://www.apache.org/licenses/LICENSE-2.0 |
| |
| Unless required by applicable law or agreed to in writing, software |
| distributed under the License is distributed on an "AS IS" BASIS, |
| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| See the License for the specific language governing permissions and |
| limitations under the License. |
| ==================================================================== */ |
| |
| package org.apache.poi.ss.usermodel; |
| |
| import static org.apache.poi.POITestCase.skipTest; |
| import static org.apache.poi.POITestCase.testPassesNow; |
| import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; |
| import static org.junit.jupiter.api.Assertions.assertEquals; |
| import static org.junit.jupiter.api.Assertions.assertNotEquals; |
| import static org.junit.jupiter.api.Assertions.assertNotNull; |
| import static org.junit.jupiter.api.Assertions.assertNull; |
| import static org.junit.jupiter.api.Assertions.assertTrue; |
| import static org.junit.jupiter.api.Assumptions.assumeTrue; |
| |
| import java.io.IOException; |
| import java.util.ArrayList; |
| import java.util.List; |
| |
| import org.apache.poi.common.usermodel.HyperlinkType; |
| import org.apache.poi.hssf.usermodel.HSSFWorkbook; |
| import org.apache.poi.ss.ITestDataProvider; |
| import org.apache.poi.ss.util.CellAddress; |
| import org.apache.poi.ss.util.CellRangeAddress; |
| import org.apache.poi.ss.util.CellReference; |
| import org.junit.jupiter.api.Test; |
| |
| /** |
| * Tests row shifting capabilities. |
| * |
| * @author Shawn Laubach (slaubach at apache dot com) |
| * @author Toshiaki Kamoshida (kamoshida.toshiaki at future dot co dot jp) |
| */ |
| public abstract class BaseTestSheetShiftRows { |
| |
| private final ITestDataProvider _testDataProvider; |
| |
| protected BaseTestSheetShiftRows(ITestDataProvider testDataProvider) { |
| _testDataProvider = testDataProvider; |
| } |
| |
| /** |
| * Tests the shiftRows function. Does three different shifts. |
| * After each shift, writes the workbook to file and reads back to |
| * check. This ensures that if some changes code that breaks |
| * writing or what not, they realize it. |
| */ |
| @Test |
| public final void testShiftRows() throws IOException { |
| // Read initial file in |
| String sampleName = "SimpleMultiCell." + _testDataProvider.getStandardFileNameExtension(); |
| Workbook wb1 = _testDataProvider.openSampleWorkbook(sampleName); |
| Sheet s = wb1.getSheetAt( 0 ); |
| |
| // Shift the second row down 1 and write to temp file |
| s.shiftRows( 1, 1, 1 ); |
| |
| Workbook wb2 = _testDataProvider.writeOutAndReadBack(wb1); |
| wb1.close(); |
| |
| // Read from temp file and check the number of cells in each |
| // row (in original file each row was unique) |
| s = wb2.getSheetAt( 0 ); |
| |
| assertEquals(s.getRow(0).getPhysicalNumberOfCells(), 1); |
| confirmEmptyRow(s, 1); |
| assertEquals(s.getRow(2).getPhysicalNumberOfCells(), 2); |
| assertEquals(s.getRow(3).getPhysicalNumberOfCells(), 4); |
| assertEquals(s.getRow(4).getPhysicalNumberOfCells(), 5); |
| |
| // Shift rows 1-3 down 3 in the current one. This tests when |
| // 1 row is blank. Write to a another temp file |
| s.shiftRows( 0, 2, 3 ); |
| Workbook wb3 = _testDataProvider.writeOutAndReadBack(wb2); |
| wb2.close(); |
| |
| // Read and ensure things are where they should be |
| s = wb3.getSheetAt(0); |
| confirmEmptyRow(s, 0); |
| confirmEmptyRow(s, 1); |
| confirmEmptyRow(s, 2); |
| assertEquals(s.getRow(3).getPhysicalNumberOfCells(), 1); |
| confirmEmptyRow(s, 4); |
| assertEquals(s.getRow(5).getPhysicalNumberOfCells(), 2); |
| |
| wb3.close(); |
| |
| // Read the first file again |
| Workbook wb4 = _testDataProvider.openSampleWorkbook(sampleName); |
| s = wb4.getSheetAt( 0 ); |
| |
| // Shift rows 3 and 4 up and write to temp file |
| s.shiftRows( 2, 3, -2 ); |
| Workbook wb5 = _testDataProvider.writeOutAndReadBack(wb4); |
| wb4.close(); |
| s = wb5.getSheetAt( 0 ); |
| assertEquals(s.getRow(0).getPhysicalNumberOfCells(), 3); |
| assertEquals(s.getRow(1).getPhysicalNumberOfCells(), 4); |
| confirmEmptyRow(s, 2); |
| confirmEmptyRow(s, 3); |
| assertEquals(s.getRow(4).getPhysicalNumberOfCells(), 5); |
| wb5.close(); |
| } |
| private static void confirmEmptyRow(Sheet s, int rowIx) { |
| Row row = s.getRow(rowIx); |
| assertTrue(row == null || row.getPhysicalNumberOfCells() == 0); |
| } |
| |
| /** |
| * Tests when rows are null. |
| */ |
| @Test |
| public final void testShiftRow() throws IOException { |
| try (Workbook wb = _testDataProvider.createWorkbook()) { |
| Sheet s = wb.createSheet(); |
| s.createRow(0).createCell(0).setCellValue("TEST1"); |
| s.createRow(3).createCell(0).setCellValue("TEST2"); |
| assertDoesNotThrow(() -> s.shiftRows(0, 4, 1)); |
| } |
| } |
| |
| /** |
| * When shifting rows, the page breaks should go with it |
| */ |
| @Test |
| protected void testShiftRowBreaks() throws IOException { |
| // TODO - enable XSSF test |
| try (Workbook wb = _testDataProvider.createWorkbook()) { |
| Sheet s = wb.createSheet(); |
| Row row = s.createRow(4); |
| row.createCell(0).setCellValue("test"); |
| s.setRowBreak(4); |
| |
| s.shiftRows(4, 4, 2); |
| assertTrue(s.isRowBroken(6), "Row number 6 should have a pagebreak"); |
| } |
| } |
| |
| @Test |
| void testShiftWithComments() throws IOException { |
| Workbook wb1 = _testDataProvider.openSampleWorkbook("comments." + _testDataProvider.getStandardFileNameExtension()); |
| |
| Sheet sheet = wb1.getSheet("Sheet1"); |
| assertEquals(3, sheet.getLastRowNum()); |
| |
| // Verify comments are in the position expected |
| assertNotNull(sheet.getCellComment(new CellAddress(0,0))); |
| assertNull(sheet.getCellComment(new CellAddress(1,0))); |
| assertNotNull(sheet.getCellComment(new CellAddress(2,0))); |
| assertNotNull(sheet.getCellComment(new CellAddress(3,0))); |
| |
| String comment1 = sheet.getCellComment(new CellAddress(0,0)).getString().getString(); |
| assertEquals(comment1,"comment top row1 (index0)\n"); |
| String comment3 = sheet.getCellComment(new CellAddress(2,0)).getString().getString(); |
| assertEquals(comment3,"comment top row3 (index2)\n"); |
| String comment4 = sheet.getCellComment(new CellAddress(3,0)).getString().getString(); |
| assertEquals(comment4,"comment top row4 (index3)\n"); |
| |
| //Workbook wbBack = _testDataProvider.writeOutAndReadBack(wb); |
| |
| // Shifting all but first line down to test comments shifting |
| sheet.shiftRows(1, sheet.getLastRowNum(), 1, true, true); |
| |
| // Test that comments were shifted as expected |
| assertEquals(4, sheet.getLastRowNum()); |
| assertNotNull(sheet.getCellComment(new CellAddress(0,0))); |
| assertNull(sheet.getCellComment(new CellAddress(1,0))); |
| assertNull(sheet.getCellComment(new CellAddress(2,0))); |
| assertNotNull(sheet.getCellComment(new CellAddress(3,0))); |
| assertNotNull(sheet.getCellComment(new CellAddress(4,0))); |
| |
| String comment1_shifted = sheet.getCellComment(new CellAddress(0,0)).getString().getString(); |
| assertEquals(comment1,comment1_shifted); |
| String comment3_shifted = sheet.getCellComment(new CellAddress(3,0)).getString().getString(); |
| assertEquals(comment3,comment3_shifted); |
| String comment4_shifted = sheet.getCellComment(new CellAddress(4,0)).getString().getString(); |
| assertEquals(comment4,comment4_shifted); |
| |
| // Write out and read back in again |
| // Ensure that the changes were persisted |
| Workbook wb2 = _testDataProvider.writeOutAndReadBack(wb1); |
| wb1.close(); |
| |
| sheet = wb2.getSheet("Sheet1"); |
| assertEquals(4, sheet.getLastRowNum()); |
| |
| // Verify comments are in the position expected after the shift |
| assertNotNull(sheet.getCellComment(new CellAddress(0,0))); |
| assertNull(sheet.getCellComment(new CellAddress(1,0))); |
| assertNull(sheet.getCellComment(new CellAddress(2,0))); |
| assertNotNull(sheet.getCellComment(new CellAddress(3,0))); |
| assertNotNull(sheet.getCellComment(new CellAddress(4,0))); |
| |
| comment1_shifted = sheet.getCellComment(new CellAddress(0,0)).getString().getString(); |
| assertEquals(comment1,comment1_shifted); |
| comment3_shifted = sheet.getCellComment(new CellAddress(3,0)).getString().getString(); |
| assertEquals(comment3,comment3_shifted); |
| comment4_shifted = sheet.getCellComment(new CellAddress(4,0)).getString().getString(); |
| assertEquals(comment4,comment4_shifted); |
| |
| // Shifting back up again, now two rows |
| sheet.shiftRows(2, sheet.getLastRowNum(), -2, true, true); |
| |
| // TODO: it seems HSSFSheet does not correctly remove comments from rows that are overwritten |
| // by shifting rows... |
| if(!(wb2 instanceof HSSFWorkbook)) { |
| assertEquals(2, sheet.getLastRowNum()); |
| |
| // Verify comments are in the position expected |
| assertNull(sheet.getCellComment(new CellAddress(0,0)), |
| "Had: " + (sheet.getCellComment(new CellAddress(0,0)) == null ? "null" : sheet.getCellComment(new CellAddress(0,0)).getString())); |
| assertNotNull(sheet.getCellComment(new CellAddress(1,0))); |
| assertNotNull(sheet.getCellComment(new CellAddress(2,0))); |
| } |
| |
| comment1 = sheet.getCellComment(new CellAddress(1,0)).getString().getString(); |
| assertEquals(comment1,"comment top row3 (index2)\n"); |
| String comment2 = sheet.getCellComment(new CellAddress(2,0)).getString().getString(); |
| assertEquals(comment2,"comment top row4 (index3)\n"); |
| |
| wb2.close(); |
| } |
| |
| @Test |
| public final void testShiftWithNames() throws IOException { |
| Workbook wb = _testDataProvider.createWorkbook(); |
| Sheet sheet1 = wb.createSheet("Sheet1"); |
| wb.createSheet("Sheet2"); |
| Row row = sheet1.createRow(0); |
| row.createCell(0).setCellValue(1.1); |
| row.createCell(1).setCellValue(2.2); |
| |
| Name name1 = wb.createName(); |
| name1.setNameName("name1"); |
| name1.setRefersToFormula("Sheet1!$A$1+Sheet1!$B$1"); |
| |
| Name name2 = wb.createName(); |
| name2.setNameName("name2"); |
| name2.setRefersToFormula("Sheet1!$A$1"); |
| |
| //refers to A1 but on Sheet2. Should stay unaffected. |
| Name name3 = wb.createName(); |
| name3.setNameName("name3"); |
| name3.setRefersToFormula("Sheet2!$A$1"); |
| |
| //The scope of this one is Sheet2. Should stay unaffected. |
| Name name4 = wb.createName(); |
| name4.setNameName("name4"); |
| name4.setRefersToFormula("A1"); |
| name4.setSheetIndex(1); |
| |
| sheet1.shiftRows(0, 1, 2); //shift down the top row on Sheet1. |
| name1 = wb.getName("name1"); |
| assertEquals("Sheet1!$A$3+Sheet1!$B$3", name1.getRefersToFormula()); |
| |
| name2 = wb.getName("name2"); |
| assertEquals("Sheet1!$A$3", name2.getRefersToFormula()); |
| |
| //name3 and name4 refer to Sheet2 and should not be affected |
| name3 = wb.getName("name3"); |
| assertEquals("Sheet2!$A$1", name3.getRefersToFormula()); |
| |
| name4 = wb.getName("name4"); |
| assertEquals("A1", name4.getRefersToFormula()); |
| |
| wb.close(); |
| } |
| |
| @Test |
| public final void testShiftWithMergedRegions() throws IOException { |
| Workbook wb = _testDataProvider.createWorkbook(); |
| Sheet sheet = wb.createSheet(); |
| Row row = sheet.createRow(0); |
| row.createCell(0).setCellValue(1.1); |
| row.createCell(1).setCellValue(2.2); |
| CellRangeAddress region = new CellRangeAddress(0, 0, 0, 2); |
| assertEquals("A1:C1", region.formatAsString()); |
| |
| assertEquals(0, sheet.addMergedRegion(region)); |
| |
| sheet.shiftRows(0, 1, 2); |
| region = sheet.getMergedRegion(0); |
| assertEquals("A3:C3", region.formatAsString()); |
| wb.close(); |
| } |
| |
| //@Disabled("bug 56454: Incorrectly handles merged regions that do not contain column 0") |
| @Test |
| public final void shiftWithMergedRegions_bug56454() throws IOException { |
| Workbook wb = _testDataProvider.createWorkbook(); |
| Sheet sheet = wb.createSheet(); |
| // populate sheet cells |
| for (int i = 0; i < 10; i++) { |
| Row row = sheet.createRow(i); |
| |
| for (int j = 0; j < 10; j++) { |
| Cell cell = row.createCell(j, CellType.STRING); |
| cell.setCellValue(i + "x" + j); |
| } |
| } |
| |
| CellRangeAddress A4_B7 = CellRangeAddress.valueOf("A4:B7"); |
| CellRangeAddress C4_D7 = CellRangeAddress.valueOf("C4:D7"); |
| |
| assertEquals(0, sheet.addMergedRegion(A4_B7)); |
| assertEquals(1, sheet.addMergedRegion(C4_D7)); |
| |
| assumeTrue(sheet.getLastRowNum() > 8); |
| |
| // Insert a row in the middle of both merged regions. |
| sheet.shiftRows(4, sheet.getLastRowNum(), 1); |
| |
| // all regions should still start at row 3, and elongate by 1 row |
| List<CellRangeAddress> expectedMergedRegions = new ArrayList<>(); |
| CellRangeAddress A4_B8 = CellRangeAddress.valueOf("A4:B8"); //A4:B7 should be elongated by 1 row |
| CellRangeAddress C4_D8 = CellRangeAddress.valueOf("C4:D8"); //C4:B7 should be elongated by 1 row |
| expectedMergedRegions.add(A4_B8); |
| expectedMergedRegions.add(C4_D8); |
| |
| // This test is written as expected-to-fail and should be rewritten |
| // as expected-to-pass when the bug is fixed. |
| // FIXME: remove try, catch, and testPassesNow, skipTest when test passes |
| try { |
| assertEquals(expectedMergedRegions, sheet.getMergedRegions()); |
| testPassesNow(56454); |
| } catch (AssertionError e) { |
| skipTest(e); |
| } |
| wb.close(); |
| } |
| |
| |
| |
| /** |
| * See bug #34023 |
| */ |
| @Test |
| public final void testShiftWithFormulas() throws IOException { |
| Workbook wb = _testDataProvider.openSampleWorkbook("ForShifting." + _testDataProvider.getStandardFileNameExtension()); |
| |
| Sheet sheet = wb.getSheet("Sheet1"); |
| assertEquals(20, sheet.getLastRowNum()); |
| |
| confirmRow(sheet, 0, 1, 171, 1, "ROW(D1)", "100+B1", "COUNT(D1:E1)"); |
| confirmRow(sheet, 1, 2, 172, 1, "ROW(D2)", "100+B2", "COUNT(D2:E2)"); |
| confirmRow(sheet, 2, 3, 173, 1, "ROW(D3)", "100+B3", "COUNT(D3:E3)"); |
| |
| confirmCell(sheet, 6, 1, 271, "200+B1"); |
| confirmCell(sheet, 7, 1, 272, "200+B2"); |
| confirmCell(sheet, 8, 1, 273, "200+B3"); |
| |
| confirmCell(sheet, 14, 0, 0.0, "A12"); // the cell referred to by this formula will be replaced |
| |
| // ----------- |
| // Row index 1 -> 11 (row "2" -> row "12") |
| sheet.shiftRows(1, 1, 10); |
| |
| // Now check what sheet looks like after move |
| |
| // no changes on row "1" |
| confirmRow(sheet, 0, 1, 171, 1, "ROW(D1)", "100+B1", "COUNT(D1:E1)"); |
| |
| // row "2" is now empty |
| confirmEmptyRow(sheet, 1); |
| |
| // Row "2" moved to row "12", and the formula has been updated. |
| // note however that the cached formula result (2) has not been updated. (POI differs from Excel here) |
| confirmRow(sheet, 11, 2, 172, 1, "ROW(D12)", "100+B12", "COUNT(D12:E12)"); |
| |
| // no changes on row "3" |
| confirmRow(sheet, 2, 3, 173, 1, "ROW(D3)", "100+B3", "COUNT(D3:E3)"); |
| |
| |
| confirmCell(sheet, 14, 0, 0.0, "#REF!"); |
| |
| |
| // Formulas on rows that weren't shifted: |
| confirmCell(sheet, 6, 1, 271, "200+B1"); |
| confirmCell(sheet, 7, 1, 272, "200+B12"); // this one moved |
| confirmCell(sheet, 8, 1, 273, "200+B3"); |
| |
| // check formulas on other sheets |
| Sheet sheet2 = wb.getSheet("Sheet2"); |
| confirmCell(sheet2, 0, 0, 371, "300+Sheet1!B1"); |
| confirmCell(sheet2, 1, 0, 372, "300+Sheet1!B12"); |
| confirmCell(sheet2, 2, 0, 373, "300+Sheet1!B3"); |
| |
| confirmCell(sheet2, 11, 0, 300, "300+Sheet1!#REF!"); |
| |
| |
| // Note - named ranges formulas have not been updated |
| wb.close(); |
| } |
| |
| private static void confirmRow(Sheet sheet, int rowIx, double valA, double valB, double valC, |
| String formulaA, String formulaB, String formulaC) { |
| confirmCell(sheet, rowIx, 4, valA, formulaA); |
| confirmCell(sheet, rowIx, 5, valB, formulaB); |
| confirmCell(sheet, rowIx, 6, valC, formulaC); |
| } |
| |
| private static void confirmCell(Sheet sheet, int rowIx, int colIx, |
| double expectedValue, String expectedFormula) { |
| Cell cell = sheet.getRow(rowIx).getCell(colIx); |
| assertEquals(expectedValue, cell.getNumericCellValue(), 0.0); |
| assertEquals(expectedFormula, cell.getCellFormula()); |
| } |
| |
| @Test |
| public final void testShiftSharedFormulasBug54206() throws IOException { |
| Workbook wb = _testDataProvider.openSampleWorkbook("54206." + _testDataProvider.getStandardFileNameExtension()); |
| |
| Sheet sheet = wb.getSheetAt(0); |
| assertEquals("SUMIF($B$19:$B$82,$B4,G$19:G$82)", sheet.getRow(3).getCell(6).getCellFormula()); |
| assertEquals("SUMIF($B$19:$B$82,$B4,H$19:H$82)", sheet.getRow(3).getCell(7).getCellFormula()); |
| assertEquals("SUMIF($B$19:$B$82,$B4,I$19:I$82)", sheet.getRow(3).getCell(8).getCellFormula()); |
| |
| assertEquals("SUMIF($B$19:$B$82,$B15,G$19:G$82)", sheet.getRow(14).getCell(6).getCellFormula()); |
| assertEquals("SUMIF($B$19:$B$82,$B15,H$19:H$82)", sheet.getRow(14).getCell(7).getCellFormula()); |
| assertEquals("SUMIF($B$19:$B$82,$B15,I$19:I$82)", sheet.getRow(14).getCell(8).getCellFormula()); |
| |
| // now the whole block G4L:15 |
| for(int i = 3; i <= 14; i++){ |
| for(int j = 6; j <= 8; j++){ |
| String col = CellReference.convertNumToColString(j); |
| String expectedFormula = "SUMIF($B$19:$B$82,$B"+(i+1)+","+col+"$19:"+col+"$82)"; |
| assertEquals(expectedFormula, sheet.getRow(i).getCell(j).getCellFormula()); |
| } |
| } |
| |
| assertEquals("SUM(G24:I24)", sheet.getRow(23).getCell(9).getCellFormula()); |
| assertEquals("SUM(G25:I25)", sheet.getRow(24).getCell(9).getCellFormula()); |
| assertEquals("SUM(G26:I26)", sheet.getRow(25).getCell(9).getCellFormula()); |
| |
| sheet.shiftRows(24, sheet.getLastRowNum(), 4, true, false); |
| |
| assertEquals("SUMIF($B$19:$B$86,$B4,G$19:G$86)", sheet.getRow(3).getCell(6).getCellFormula()); |
| assertEquals("SUMIF($B$19:$B$86,$B4,H$19:H$86)", sheet.getRow(3).getCell(7).getCellFormula()); |
| assertEquals("SUMIF($B$19:$B$86,$B4,I$19:I$86)", sheet.getRow(3).getCell(8).getCellFormula()); |
| |
| assertEquals("SUMIF($B$19:$B$86,$B15,G$19:G$86)", sheet.getRow(14).getCell(6).getCellFormula()); |
| assertEquals("SUMIF($B$19:$B$86,$B15,H$19:H$86)", sheet.getRow(14).getCell(7).getCellFormula()); |
| assertEquals("SUMIF($B$19:$B$86,$B15,I$19:I$86)", sheet.getRow(14).getCell(8).getCellFormula()); |
| |
| // now the whole block G4L:15 |
| for(int i = 3; i <= 14; i++){ |
| for(int j = 6; j <= 8; j++){ |
| String col = CellReference.convertNumToColString(j); |
| String expectedFormula = "SUMIF($B$19:$B$86,$B"+(i+1)+","+col+"$19:"+col+"$86)"; |
| assertEquals(expectedFormula, sheet.getRow(i).getCell(j).getCellFormula()); |
| } |
| } |
| |
| assertEquals("SUM(G24:I24)", sheet.getRow(23).getCell(9).getCellFormula()); |
| |
| // shifted rows |
| assertTrue( sheet.getRow(24) == null || sheet.getRow(24).getCell(9) == null); |
| assertTrue( sheet.getRow(25) == null || sheet.getRow(25).getCell(9) == null); |
| assertTrue( sheet.getRow(26) == null || sheet.getRow(26).getCell(9) == null); |
| assertTrue( sheet.getRow(27) == null || sheet.getRow(27).getCell(9) == null); |
| |
| assertEquals("SUM(G29:I29)", sheet.getRow(28).getCell(9).getCellFormula()); |
| assertEquals("SUM(G30:I30)", sheet.getRow(29).getCell(9).getCellFormula()); |
| wb.close(); |
| } |
| |
| @Test |
| void testBug55280() throws IOException { |
| Workbook w = _testDataProvider.createWorkbook(); |
| Sheet s = w.createSheet(); |
| for (int row = 0; row < 5000; ++row) { |
| assertEquals(row, s.addMergedRegion(new CellRangeAddress(row, row, 0, 3))); |
| } |
| |
| s.shiftRows(0, 4999, 1); // takes a long time... |
| w.close(); |
| } |
| |
| @Test |
| void test47169() throws IOException { |
| try (Workbook wb = _testDataProvider.createWorkbook()) { |
| Sheet sheet = wb.createSheet(); |
| sheet.createRow(30); |
| sheet.shiftRows(29, 29, 1, true, true); |
| assertDoesNotThrow(() -> sheet.createRow(30)); |
| } |
| } |
| |
| /** |
| * Unified test for: |
| * bug 46742: XSSFSheet.shiftRows should shift hyperlinks |
| * bug 52903: HSSFSheet.shiftRows should shift hyperlinks |
| */ |
| @Test |
| void testBug46742_52903_shiftHyperlinks() throws IOException { |
| Workbook wb = _testDataProvider.createWorkbook(); |
| Sheet sheet = wb.createSheet("test"); |
| Row row = sheet.createRow(0); |
| |
| // How to create hyperlinks |
| // https://poi.apache.org/spreadsheet/quick-guide.html#Hyperlinks |
| CreationHelper helper = wb.getCreationHelper(); |
| CellStyle hlinkStyle = wb.createCellStyle(); |
| Font hlinkFont = wb.createFont(); |
| hlinkFont.setUnderline(Font.U_SINGLE); |
| hlinkFont.setColor(IndexedColors.BLUE.getIndex()); |
| hlinkStyle.setFont(hlinkFont); |
| |
| // 3D relative document link |
| // CellAddress=A1, shifted to A4 |
| Cell cell = row.createCell(0); |
| cell.setCellStyle(hlinkStyle); |
| createHyperlink(helper, cell, HyperlinkType.DOCUMENT, "test!E1"); |
| |
| // URL |
| cell = row.createCell(1); |
| // CellAddress=B1, shifted to B4 |
| cell.setCellStyle(hlinkStyle); |
| createHyperlink(helper, cell, HyperlinkType.URL, "https://poi.apache.org/"); |
| |
| // row0 will be shifted on top of row1, so this URL should be removed from the workbook |
| Row overwrittenRow = sheet.createRow(3); |
| cell = overwrittenRow.createCell(2); |
| // CellAddress=C4, will be overwritten (deleted) |
| cell.setCellStyle(hlinkStyle); |
| createHyperlink(helper, cell, HyperlinkType.EMAIL, "mailto:poi@apache.org"); |
| |
| // hyperlinks on this row are unaffected by the row shifting, so the hyperlinks should not move |
| Row unaffectedRow = sheet.createRow(20); |
| cell = unaffectedRow.createCell(3); |
| // CellAddress=D21, will be unaffected |
| cell.setCellStyle(hlinkStyle); |
| createHyperlink(helper, cell, HyperlinkType.FILE, "54524.xlsx"); |
| |
| cell = wb.createSheet("other").createRow(0).createCell(0); |
| // CellAddress=Other!A1, will be unaffected |
| cell.setCellStyle(hlinkStyle); |
| createHyperlink(helper, cell, HyperlinkType.URL, "http://apache.org/"); |
| |
| int startRow = 0; |
| int endRow = 0; |
| int n = 3; |
| sheet.shiftRows(startRow, endRow, n); |
| |
| Workbook read = _testDataProvider.writeOutAndReadBack(wb); |
| wb.close(); |
| |
| Sheet sh = read.getSheet("test"); |
| |
| Row shiftedRow = sh.getRow(3); |
| |
| // document link anchored on a shifted cell should be moved |
| // Note that hyperlinks do not track what they point to, so this hyperlink should still refer to test!E1 |
| verifyHyperlink(shiftedRow.getCell(0), HyperlinkType.DOCUMENT, "test!E1"); |
| |
| // URL, EMAIL, and FILE links anchored on a shifted cell should be moved |
| verifyHyperlink(shiftedRow.getCell(1), HyperlinkType.URL, "https://poi.apache.org/"); |
| |
| // Make sure hyperlinks were moved and not copied |
| assertNull(sh.getHyperlink(0, 0), "Document hyperlink should be moved, not copied"); |
| assertNull(sh.getHyperlink(0, 1), "URL hyperlink should be moved, not copied"); |
| |
| // Make sure hyperlink in overwritten row is deleted |
| assertEquals(3, sh.getHyperlinkList().size()); |
| CellAddress unexpectedLinkAddress = new CellAddress("C4"); |
| for (Hyperlink link : sh.getHyperlinkList()) { |
| final CellAddress linkAddress = new CellAddress(link.getFirstRow(), link.getFirstColumn()); |
| assertNotEquals(linkAddress, unexpectedLinkAddress, |
| "Row 4, including the hyperlink at C4, should have " + |
| "been deleted when Row 1 was shifted on top of it."); |
| } |
| |
| // Make sure unaffected rows are not shifted |
| Cell unaffectedCell = sh.getRow(20).getCell(3); |
| assertTrue(cellHasHyperlink(unaffectedCell)); |
| verifyHyperlink(unaffectedCell, HyperlinkType.FILE, "54524.xlsx"); |
| |
| // Make sure cells on other sheets are not affected |
| unaffectedCell = read.getSheet("other").getRow(0).getCell(0); |
| assertTrue(cellHasHyperlink(unaffectedCell)); |
| verifyHyperlink(unaffectedCell, HyperlinkType.URL, "http://apache.org/"); |
| |
| read.close(); |
| } |
| |
| //@Disabled("bug 56454: Incorrectly handles merged regions that do not contain column 0") |
| @Test |
| void shiftRowsWithMergedRegionsThatDoNotContainColumnZero() throws IOException { |
| Workbook wb = _testDataProvider.createWorkbook(); |
| Sheet sheet = wb.createSheet("test"); |
| |
| // populate sheet cells |
| for (int i = 0; i < 10; i++) { |
| Row row = sheet.createRow(i); |
| for (int j = 0; j < 12; j++) { |
| Cell cell = row.createCell(j); |
| cell.setCellValue(i + "x" + j); |
| } |
| } |
| |
| CellRangeAddress A4_B7 = new CellRangeAddress(3, 6, 0, 1); |
| CellRangeAddress C5_D7 = new CellRangeAddress(4, 6, 2, 3); |
| |
| assertEquals(0, sheet.addMergedRegion(A4_B7)); |
| assertEquals(1, sheet.addMergedRegion(C5_D7)); |
| |
| // A4:B7 will elongate vertically |
| // C5:D7 will be shifted down with same size |
| sheet.shiftRows(4, sheet.getLastRowNum(), 1); |
| |
| // This test is written as expected-to-fail and should be rewritten |
| // as expected-to-pass when the bug is fixed. |
| // FIXME: remove try, catch, and testPassesNow, skipTest when test passes |
| try { |
| assertEquals(2, sheet.getNumMergedRegions()); |
| assertEquals(CellRangeAddress.valueOf("A4:B8"), sheet.getMergedRegion(0)); |
| assertEquals(CellRangeAddress.valueOf("C5:D8"), sheet.getMergedRegion(1)); |
| testPassesNow(56454); |
| } catch (AssertionError e) { |
| skipTest(e); |
| } |
| |
| wb.close(); |
| } |
| |
| @Test |
| void shiftMergedRowsToMergedRowsUp() throws IOException { |
| Workbook wb = _testDataProvider.createWorkbook(); |
| Sheet sheet = wb.createSheet("test"); |
| populateSheetCells(sheet, 2); |
| |
| |
| CellRangeAddress A1_E1 = new CellRangeAddress(0, 0, 0, 4); |
| CellRangeAddress A2_C2 = new CellRangeAddress(1, 1, 0, 2); |
| |
| assertEquals(0, sheet.addMergedRegion(A1_E1)); |
| assertEquals(1, sheet.addMergedRegion(A2_C2)); |
| |
| // A1:E1 should be removed |
| // A2:C2 will be A1:C1 |
| sheet.shiftRows(1, sheet.getLastRowNum(), -1); |
| |
| assertEquals(1, sheet.getNumMergedRegions()); |
| assertEquals(CellRangeAddress.valueOf("A1:C1"), sheet.getMergedRegion(0)); |
| |
| wb.close(); |
| } |
| |
| @Test |
| void shiftMergedRowsToMergedRowsOverlappingMergedRegion() throws IOException { |
| Workbook wb = _testDataProvider.createWorkbook(); |
| Sheet sheet = wb.createSheet("test"); |
| populateSheetCells(sheet, 10); |
| |
| CellRangeAddress A1_E1 = new CellRangeAddress(0, 0, 0, 4); |
| CellRangeAddress A2_C2 = new CellRangeAddress(1, 7, 0, 2); |
| |
| assertEquals(0, sheet.addMergedRegion(A1_E1)); |
| assertEquals(1, sheet.addMergedRegion(A2_C2)); |
| |
| // A1:E1 should move to A5:E5 |
| // A2:C2 should be removed |
| sheet.shiftRows(0, 0, 4); |
| |
| assertEquals(1, sheet.getNumMergedRegions()); |
| assertEquals(CellRangeAddress.valueOf("A5:E5"), sheet.getMergedRegion(0)); |
| |
| wb.close(); |
| } |
| |
| @Test |
| void bug60384ShiftMergedRegion() throws IOException { |
| Workbook wb = _testDataProvider.createWorkbook(); |
| Sheet sheet = wb.createSheet("test"); |
| populateSheetCells(sheet, 9); |
| |
| |
| CellRangeAddress A8_E8 = new CellRangeAddress(7, 7, 0, 4); |
| CellRangeAddress A9_C9 = new CellRangeAddress(8, 8, 0, 2); |
| |
| assertEquals(0, sheet.addMergedRegion(A8_E8)); |
| assertEquals(1, sheet.addMergedRegion(A9_C9)); |
| |
| // A1:E1 should be removed |
| // A2:C2 will be A1:C1 |
| sheet.shiftRows(3, sheet.getLastRowNum(), 1); |
| |
| assertEquals(2, sheet.getNumMergedRegions()); |
| assertEquals(CellRangeAddress.valueOf("A9:E9"), sheet.getMergedRegion(0)); |
| assertEquals(CellRangeAddress.valueOf("A10:C10"), sheet.getMergedRegion(1)); |
| |
| wb.close(); |
| } |
| |
| private void populateSheetCells(Sheet sheet, int rowCount) { |
| // populate sheet cells |
| for (int i = 0; i < rowCount; i++) { |
| Row row = sheet.createRow(i); |
| for (int j = 0; j < 5; j++) { |
| Cell cell = row.createCell(j); |
| cell.setCellValue(i + "x" + j); |
| } |
| } |
| } |
| |
| @Test |
| void shiftMergedRowsToMergedRowsDown() throws IOException { |
| Workbook wb = _testDataProvider.createWorkbook(); |
| Sheet sheet = wb.createSheet("test"); |
| |
| // populate sheet cells |
| populateSheetCells(sheet, 2); |
| |
| CellRangeAddress A1_E1 = new CellRangeAddress(0, 0, 0, 4); |
| CellRangeAddress A2_C2 = new CellRangeAddress(1, 1, 0, 2); |
| |
| assertEquals(0, sheet.addMergedRegion(A1_E1)); |
| assertEquals(1, sheet.addMergedRegion(A2_C2)); |
| |
| // A1:E1 should be moved to A2:E2 |
| // A2:C2 will be removed |
| sheet.shiftRows(0, 0, 1); |
| |
| assertEquals(1, sheet.getNumMergedRegions()); |
| assertEquals(CellRangeAddress.valueOf("A2:E2"), sheet.getMergedRegion(0)); |
| |
| wb.close(); |
| } |
| |
| @Test |
| void test61840_shifting_rows_up_does_not_produce_REF_errors() throws IOException { |
| Workbook wb = _testDataProvider.createWorkbook(); |
| Sheet sheet = wb.createSheet(); |
| Cell cell = sheet.createRow(4).createCell(0); |
| |
| cell.setCellFormula("(B5-C5)/B5"); |
| sheet.shiftRows(4, 4, -1); |
| |
| // Cell objects created before a row shift are still valid. |
| // The row number of those cell references will be shifted if |
| // the cell is within the shift range. |
| assertEquals("(B4-C4)/B4", cell.getCellFormula()); |
| |
| // New cell references are also valid. |
| Cell shiftedCell = sheet.getRow(3).getCell(0); |
| assertNotNull(shiftedCell); |
| assertEquals("(B4-C4)/B4", shiftedCell.getCellFormula()); |
| |
| wb.close(); |
| } |
| |
| |
| @Test |
| void checkMergedRegions56454() { |
| Workbook wb = _testDataProvider.createWorkbook(); |
| Sheet sheet = wb.createSheet(); |
| |
| // populate sheet cells |
| for (int i = 0; i < 10; i++) { |
| Row row = sheet.createRow(i); |
| |
| for (int j = 0; j < 10; j++) { |
| Cell cell = row.createCell(j, CellType.STRING); |
| |
| cell.setCellValue(i + "x" + j); |
| } |
| } |
| |
| CellRangeAddress region1 = new CellRangeAddress(3, 6, 0, 1); |
| CellRangeAddress region2 = new CellRangeAddress(3, 6, 2, 3); |
| |
| sheet.addMergedRegion(region1); |
| sheet.addMergedRegion(region2); |
| |
| sheet.shiftRows(4, sheet.getLastRowNum(), 1); |
| |
| // check, if all regions still start at row 3 |
| for (int i = 0; i < sheet.getNumMergedRegions(); i++) { |
| CellRangeAddress cr = sheet.getMergedRegion(i); |
| |
| assertEquals(cr.getFirstRow(), 3); |
| } |
| } |
| |
| |
| |
| |
| private void createHyperlink(CreationHelper helper, Cell cell, HyperlinkType linkType, String ref) { |
| cell.setCellValue(ref); |
| Hyperlink link = helper.createHyperlink(linkType); |
| link.setAddress(ref); |
| cell.setHyperlink(link); |
| } |
| |
| private void verifyHyperlink(Cell cell, HyperlinkType linkType, String ref) { |
| assertTrue(cellHasHyperlink(cell)); |
| Hyperlink link = cell.getHyperlink(); |
| assertEquals(linkType, link.getType()); |
| assertEquals(ref, link.getAddress()); |
| } |
| |
| private boolean cellHasHyperlink(Cell cell) { |
| return (cell != null) && (cell.getHyperlink() != null); |
| } |
| } |