From c8d5a37017aad6d03d19bc41598d14c726fccf04 Mon Sep 17 00:00:00 2001 From: Javen O'Neal Date: Mon, 2 Nov 2015 09:59:32 +0000 Subject: [PATCH] bug 58348: add hyperlink copying and merging to CellCopyPolicy git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1711926 13f79535-47bb-0310-9956-ffa450edef68 --- .../poi/ss/usermodel/CellCopyPolicy.java | 110 +++++++++++++++--- .../apache/poi/xssf/usermodel/XSSFCell.java | 19 +++ .../poi/xssf/usermodel/TestXSSFCell.java | 96 ++++++++++++++- 3 files changed, 208 insertions(+), 17 deletions(-) diff --git a/src/java/org/apache/poi/ss/usermodel/CellCopyPolicy.java b/src/java/org/apache/poi/ss/usermodel/CellCopyPolicy.java index 4b901b06b4..80043210a6 100644 --- a/src/java/org/apache/poi/ss/usermodel/CellCopyPolicy.java +++ b/src/java/org/apache/poi/ss/usermodel/CellCopyPolicy.java @@ -21,23 +21,37 @@ import org.apache.poi.util.Beta; @Beta public class CellCopyPolicy implements Cloneable { + // cell-level policies public static final boolean DEFAULT_COPY_CELL_VALUE_POLICY = true; public static final boolean DEFAULT_COPY_CELL_STYLE_POLICY = true; public static final boolean DEFAULT_COPY_CELL_FORMULA_POLICY = true; - public static final boolean DEFAULT_COPY_MERGED_REGIONS_POLICY = true; + public static final boolean DEFAULT_COPY_HYPERLINK_POLICY = true; + public static final boolean DEFAULT_MERGE_HYPERLINK_POLICY = false; + + // row-level policies public static final boolean DEFAULT_COPY_ROW_HEIGHT_POLICY = true; public static final boolean DEFAULT_CONDENSE_ROWS_POLICY = false; + // sheet-level policies + public static final boolean DEFAULT_COPY_MERGED_REGIONS_POLICY = true; + + // cell-level policies private boolean copyCellValue = DEFAULT_COPY_CELL_VALUE_POLICY; private boolean copyCellStyle = DEFAULT_COPY_CELL_STYLE_POLICY; private boolean copyCellFormula = DEFAULT_COPY_CELL_FORMULA_POLICY; - private boolean copyMergedRegions = DEFAULT_COPY_MERGED_REGIONS_POLICY; + private boolean copyHyperlink = DEFAULT_COPY_HYPERLINK_POLICY; + private boolean mergeHyperlink = DEFAULT_MERGE_HYPERLINK_POLICY; + + // row-level policies private boolean copyRowHeight = DEFAULT_COPY_ROW_HEIGHT_POLICY; private boolean condenseRows = DEFAULT_CONDENSE_ROWS_POLICY; + // sheet-level policies + private boolean copyMergedRegions = DEFAULT_COPY_MERGED_REGIONS_POLICY; + /** * Default CellCopyPolicy, uses default policy - * For custom CellCopyPolicy, use {@link #Builder} class + * For custom CellCopyPolicy, use {@link Builder} class */ public CellCopyPolicy() { } @@ -48,25 +62,37 @@ public class CellCopyPolicy implements Cloneable { copyCellValue = builder.copyCellValue; copyCellStyle = builder.copyCellStyle; copyCellFormula = builder.copyCellFormula; - copyMergedRegions = builder.copyMergedRegions; + copyHyperlink = builder.copyHyperlink; + mergeHyperlink = builder.mergeHyperlink; + copyRowHeight = builder.copyRowHeight; condenseRows = builder.condenseRows; + + copyMergedRegions = builder.copyMergedRegions; } public static class Builder { + // cell-level policies private boolean copyCellValue = DEFAULT_COPY_CELL_VALUE_POLICY; private boolean copyCellStyle = DEFAULT_COPY_CELL_STYLE_POLICY; private boolean copyCellFormula = DEFAULT_COPY_CELL_FORMULA_POLICY; - private boolean copyMergedRegions = DEFAULT_COPY_MERGED_REGIONS_POLICY; + private boolean copyHyperlink = DEFAULT_COPY_HYPERLINK_POLICY; + private boolean mergeHyperlink = DEFAULT_MERGE_HYPERLINK_POLICY; + + // row-level policies private boolean copyRowHeight = DEFAULT_COPY_ROW_HEIGHT_POLICY; private boolean condenseRows = DEFAULT_CONDENSE_ROWS_POLICY; + // sheet-level policies + private boolean copyMergedRegions = DEFAULT_COPY_MERGED_REGIONS_POLICY; + /** * Builder class for CellCopyPolicy */ public Builder() { } + // cell-level policies public Builder cellValue(boolean copyCellValue) { this.copyCellValue = copyCellValue; return this; @@ -79,10 +105,16 @@ public class CellCopyPolicy implements Cloneable { this.copyCellFormula = copyCellFormula; return this; } - public Builder mergedRegions(boolean copyMergedRegions) { - this.copyMergedRegions = copyMergedRegions; + public Builder copyHyperlink(boolean copyHyperlink) { + this.copyHyperlink = copyHyperlink; return this; } + public Builder mergeHyperlink(boolean mergeHyperlink) { + this.mergeHyperlink = mergeHyperlink; + return this; + } + + // row-level policies public Builder rowHeight(boolean copyRowHeight) { this.copyRowHeight = copyRowHeight; return this; @@ -91,6 +123,12 @@ public class CellCopyPolicy implements Cloneable { this.condenseRows = condenseRows; return this; } + + // sheet-level policies + public Builder mergedRegions(boolean copyMergedRegions) { + this.copyMergedRegions = copyMergedRegions; + return this; + } public CellCopyPolicy build() { return new CellCopyPolicy(this); } @@ -101,9 +139,11 @@ public class CellCopyPolicy implements Cloneable { .cellValue(copyCellValue) .cellStyle(copyCellStyle) .cellFormula(copyCellFormula) - .mergedRegions(copyMergedRegions) + .copyHyperlink(copyHyperlink) + .mergeHyperlink(mergeHyperlink) .rowHeight(copyRowHeight) - .condenseRows(condenseRows); + .condenseRows(condenseRows) + .mergedRegions(copyMergedRegions); return builder; } @@ -111,7 +151,10 @@ public class CellCopyPolicy implements Cloneable { public CellCopyPolicy clone() { return createBuilder().build(); } - + +/* + * Cell-level policies + */ /** * @return the copyCellValue */ @@ -153,21 +196,38 @@ public class CellCopyPolicy implements Cloneable { public void setCopyCellFormula(boolean copyCellFormula) { this.copyCellFormula = copyCellFormula; } + + /** + * @return the copyHyperlink + */ + public boolean isCopyHyperlink() { + return copyHyperlink; + } /** - * @return the copyMergedRegions + * @param copyHyperlink the copyHyperlink to set */ - public boolean isCopyMergedRegions() { - return copyMergedRegions; + public void setCopyHyperlink(boolean copyHyperlink) { + this.copyHyperlink = copyHyperlink; + } + + /** + * @return the mergeHyperlink + */ + public boolean isMergeHyperlink() { + return mergeHyperlink; } /** - * @param copyMergedRegions the copyMergedRegions to set + * @param mergeHyperlink the mergeHyperlink to set */ - public void setCopyMergedRegions(boolean copyMergedRegions) { - this.copyMergedRegions = copyMergedRegions; + public void setMergeHyperlink(boolean mergeHyperlink) { + this.mergeHyperlink = mergeHyperlink; } +/* + * Row-level policies + */ /** * @return the copyRowHeight */ @@ -199,5 +259,23 @@ public class CellCopyPolicy implements Cloneable { public void setCondenseRows(boolean condenseRows) { this.condenseRows = condenseRows; } + + +/* + * Sheet-level policies + */ + /** + * @return the copyMergedRegions + */ + public boolean isCopyMergedRegions() { + return copyMergedRegions; + } + + /** + * @param copyMergedRegions the copyMergedRegions to set + */ + public void setCopyMergedRegions(boolean copyMergedRegions) { + this.copyMergedRegions = copyMergedRegions; + } } 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 9ee050b581..1de2982dcd 100644 --- a/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFCell.java +++ b/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFCell.java @@ -180,6 +180,25 @@ public final class XSSFCell implements Cell { setCellStyle(null); } } + + if (policy.isMergeHyperlink()) { + // if srcCell doesn't have a hyperlink and destCell has a hyperlink, don't clear destCell's hyperlink + final Hyperlink srcHyperlink = srcCell.getHyperlink(); + if (srcHyperlink != null) { + setHyperlink(srcHyperlink.clone()); + } + } + else if (policy.isCopyHyperlink()) { + // overwrite the hyperlink at dest cell with srcCell's hyperlink + // if srcCell doesn't have a hyperlink, clear the hyperlink (if one exists) at destCell + final Hyperlink srcHyperlink = srcCell.getHyperlink(); + if (srcHyperlink == null) { + setHyperlink(null); + } + else { + setHyperlink(srcHyperlink.clone()); + } + } } /** diff --git a/src/ooxml/testcases/org/apache/poi/xssf/usermodel/TestXSSFCell.java b/src/ooxml/testcases/org/apache/poi/xssf/usermodel/TestXSSFCell.java index 14510c83a7..09dab72691 100644 --- a/src/ooxml/testcases/org/apache/poi/xssf/usermodel/TestXSSFCell.java +++ b/src/ooxml/testcases/org/apache/poi/xssf/usermodel/TestXSSFCell.java @@ -21,9 +21,11 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertSame; import static org.junit.Assert.assertTrue; import java.io.IOException; +import java.util.List; import org.apache.poi.hssf.HSSFITestDataProvider; import org.apache.poi.ss.SpreadsheetVersion; @@ -31,7 +33,11 @@ import org.apache.poi.ss.usermodel.BaseTestXCell; import org.apache.poi.ss.usermodel.Cell; import org.apache.poi.ss.usermodel.CellCopyPolicy; import org.apache.poi.ss.usermodel.CellStyle; +import org.apache.poi.ss.usermodel.CreationHelper; import org.apache.poi.ss.usermodel.DataFormatter; +import org.apache.poi.ss.usermodel.Font; +import org.apache.poi.ss.usermodel.Hyperlink; +import org.apache.poi.ss.usermodel.IndexedColors; import org.apache.poi.ss.usermodel.RichTextString; import org.apache.poi.ss.usermodel.Row; import org.apache.poi.ss.usermodel.Sheet; @@ -521,7 +527,6 @@ public final class TestXSSFCell extends BaseTestXCell { final CellCopyPolicy policy = new CellCopyPolicy.Builder().cellFormula(false).build(); destCell.copyCellFrom(srcCell, policy); assertEquals(Cell.CELL_TYPE_NUMERIC, destCell.getCellType()); - System.out.println("ERROR: fix formula evaluation"); } @Test @@ -540,6 +545,95 @@ public final class TestXSSFCell extends BaseTestXCell { assertEquals(true, destCell.getBooleanCellValue()); } + @Test + public final void testCopyCellFrom_CellCopyPolicy_copyHyperlink() throws IOException { + setUp_testCopyCellFrom_CellCopyPolicy(); + final Workbook wb = srcCell.getSheet().getWorkbook(); + final CreationHelper createHelper = wb.getCreationHelper(); + + srcCell.setCellValue("URL LINK"); + Hyperlink link = createHelper.createHyperlink(Hyperlink.LINK_URL); + link.setAddress("http://poi.apache.org/"); + srcCell.setHyperlink(link); + + // Set link cell style (optional) + CellStyle hlinkStyle = wb.createCellStyle(); + Font hlinkFont = wb.createFont(); + hlinkFont.setUnderline(Font.U_SINGLE); + hlinkFont.setColor(IndexedColors.BLUE.getIndex()); + hlinkStyle.setFont(hlinkFont); + srcCell.setCellStyle(hlinkStyle); + + // Copy hyperlink + final CellCopyPolicy policy = new CellCopyPolicy.Builder().copyHyperlink(true).mergeHyperlink(false).build(); + destCell.copyCellFrom(srcCell, policy); + assertNotNull(destCell.getHyperlink()); + + assertSame("unit test assumes srcCell and destCell are on the same sheet", + srcCell.getSheet(), destCell.getSheet()); + + final List links = srcCell.getSheet().getHyperlinkList(); + assertEquals("number of hyperlinks on sheet", 2, links.size()); + assertEquals("source hyperlink", + new CellReference(srcCell).formatAsString(), links.get(0).getCellRef()); + assertEquals("destination hyperlink", + new CellReference(destCell).formatAsString(), links.get(1).getCellRef()); + + wb.close(); + } + + @Test + public final void testCopyCellFrom_CellCopyPolicy_mergeHyperlink() throws IOException { + setUp_testCopyCellFrom_CellCopyPolicy(); + final Workbook wb = srcCell.getSheet().getWorkbook(); + final CreationHelper createHelper = wb.getCreationHelper(); + + srcCell.setCellValue("URL LINK"); + Hyperlink link = createHelper.createHyperlink(Hyperlink.LINK_URL); + link.setAddress("http://poi.apache.org/"); + destCell.setHyperlink(link); + + // Set link cell style (optional) + CellStyle hlinkStyle = wb.createCellStyle(); + Font hlinkFont = wb.createFont(); + hlinkFont.setUnderline(Font.U_SINGLE); + hlinkFont.setColor(IndexedColors.BLUE.getIndex()); + hlinkStyle.setFont(hlinkFont); + destCell.setCellStyle(hlinkStyle); + + // Pre-condition assumptions. This test is broken if either of these fail. + assertSame("unit test assumes srcCell and destCell are on the same sheet", + srcCell.getSheet(), destCell.getSheet()); + assertNull(srcCell.getHyperlink()); + + // Merge hyperlink - since srcCell doesn't have a hyperlink, destCell's hyperlink is not overwritten (cleared). + final CellCopyPolicy policy = new CellCopyPolicy.Builder().mergeHyperlink(true).copyHyperlink(false).build(); + destCell.copyCellFrom(srcCell, policy); + assertNull(srcCell.getHyperlink()); + assertNotNull(destCell.getHyperlink()); + assertSame(link, destCell.getHyperlink()); + + List links; + links = srcCell.getSheet().getHyperlinkList(); + assertEquals("number of hyperlinks on sheet", 1, links.size()); + assertEquals("source hyperlink", + new CellReference(destCell).formatAsString(), links.get(0).getCellRef()); + + // Merge destCell's hyperlink to srcCell. Since destCell does have a hyperlink, this should copy destCell's hyperlink to srcCell. + srcCell.copyCellFrom(destCell, policy); + assertNotNull(srcCell.getHyperlink()); + assertNotNull(destCell.getHyperlink()); + + links = srcCell.getSheet().getHyperlinkList(); + assertEquals("number of hyperlinks on sheet", 2, links.size()); + assertEquals("dest hyperlink", + new CellReference(destCell).formatAsString(), links.get(0).getCellRef()); + assertEquals("source hyperlink", + new CellReference(srcCell).formatAsString(), links.get(1).getCellRef()); + + wb.close(); + } + private final void setUp_testCopyCellFrom_CellCopyPolicy() { @SuppressWarnings("resource") final XSSFWorkbook wb = new XSSFWorkbook(); -- 2.39.5