]> source.dussan.org Git - poi.git/commitdiff
#61589 - Importing content does not copy hyperlink address
authorAndreas Beeker <kiwiwings@apache.org>
Sun, 12 Aug 2018 22:35:02 +0000 (22:35 +0000)
committerAndreas Beeker <kiwiwings@apache.org>
Sun, 12 Aug 2018 22:35:02 +0000 (22:35 +0000)
git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1837909 13f79535-47bb-0310-9956-ffa450edef68

13 files changed:
src/java/org/apache/poi/sl/draw/DrawPaint.java
src/java/org/apache/poi/sl/usermodel/AbstractColorStyle.java [new file with mode: 0644]
src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFColor.java
src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFHyperlink.java
src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFRelation.java
src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFShape.java
src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFTable.java
src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFTableCell.java
src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFTableRow.java
src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFTextParagraph.java
src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFTextRun.java
src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFTheme.java
src/ooxml/testcases/org/apache/poi/xslf/TestXSLFBugs.java

index a242149afe3a63a7935567e50a93e503fc147d60..d6986f3023e78ebd2f718282ec3ae6ffc4f585c3 100644 (file)
@@ -29,7 +29,9 @@ import java.awt.geom.Rectangle2D;
 import java.awt.image.BufferedImage;
 import java.io.IOException;
 import java.io.InputStream;
+import java.util.Objects;
 
+import org.apache.poi.sl.usermodel.AbstractColorStyle;
 import org.apache.poi.sl.usermodel.ColorStyle;
 import org.apache.poi.sl.usermodel.PaintStyle;
 import org.apache.poi.sl.usermodel.PaintStyle.GradientPaint;
@@ -66,7 +68,7 @@ public class DrawPaint {
             if (color == null) {
                 throw new NullPointerException("Color needs to be specified");
             }
-            this.solidColor = new ColorStyle(){
+            this.solidColor = new AbstractColorStyle(){
                     @Override
                     public Color getColor() {
                         return new Color(color.getRed(), color.getGreen(), color.getBlue());
@@ -89,6 +91,8 @@ public class DrawPaint {
                     public int getShade() { return -1; }
                     @Override
                     public int getTint() { return -1; }
+
+
                 };
         }
 
@@ -103,6 +107,22 @@ public class DrawPaint {
         public ColorStyle getSolidColor() {
             return solidColor;
         }
+
+        @Override
+        public boolean equals(Object o) {
+            if (this == o) {
+                return true;
+            }
+            if (!(o instanceof SolidPaint)) {
+                return false;
+            }
+            return Objects.equals(getSolidColor(), ((SolidPaint) o).getSolidColor());
+        }
+
+        @Override
+        public int hashCode() {
+            return Objects.hash(solidColor);
+        }
     }
 
     public static SolidPaint createSolidPaint(final Color color) {
@@ -131,9 +151,10 @@ public class DrawPaint {
         return null;
     }
 
+    @SuppressWarnings({"WeakerAccess", "unused"})
     protected Paint getSolidPaint(SolidPaint fill, Graphics2D graphics, final PaintModifier modifier) {
         final ColorStyle orig = fill.getSolidColor();
-        ColorStyle cs = new ColorStyle() {
+        ColorStyle cs = new AbstractColorStyle() {
             @Override
             public Color getColor() {
                 return orig.getColor();
@@ -204,6 +225,7 @@ public class DrawPaint {
         return applyColorTransform(cs);
     }
 
+    @SuppressWarnings("WeakerAccess")
     protected Paint getGradientPaint(GradientPaint fill, Graphics2D graphics) {
         switch (fill.getGradientType()) {
         case linear:
@@ -217,6 +239,7 @@ public class DrawPaint {
         }
     }
 
+    @SuppressWarnings("WeakerAccess")
     protected Paint getTexturePaint(TexturePaint fill, Graphics2D graphics) {
         InputStream is = fill.getImageData();
         if (is == null) {
@@ -320,8 +343,6 @@ public class DrawPaint {
      * @param hslPart the hsl part to modify [0..2]
      * @param mod the modulation adjustment
      * @param off the offset adjustment
-     * @return the modified hsl value
-     *
      */
     private static void applyHslModOff(double hsl[], int hslPart, int mod, int off) {
         if (mod == -1) {
@@ -370,6 +391,7 @@ public class DrawPaint {
         hsl[2] = hsl[2]*(1.-tintPct) + (100.-100.*(1.-tintPct));
     }
 
+    @SuppressWarnings("WeakerAccess")
     protected Paint createLinearGradientPaint(GradientPaint fill, Graphics2D graphics) {
         // TODO: we need to find the two points for gradient - the problem is, which point at the outline
         // do you take? My solution would be to apply the gradient rotation to the shape in reverse
@@ -412,6 +434,7 @@ public class DrawPaint {
         return new LinearGradientPaint(p1, p2, fractions, colors);
     }
 
+    @SuppressWarnings("WeakerAccess")
     protected Paint createRadialGradientPaint(GradientPaint fill, Graphics2D graphics) {
         Rectangle2D anchor = DrawShape.getAnchor(graphics, shape);
 
@@ -431,6 +454,7 @@ public class DrawPaint {
         return new RadialGradientPaint(pCenter, radius, fractions, colors);
     }
 
+    @SuppressWarnings({"WeakerAccess", "unused"})
     protected Paint createPathGradientPaint(GradientPaint fill, Graphics2D graphics) {
         // currently we ignore an eventually center setting
 
@@ -445,20 +469,6 @@ public class DrawPaint {
         return new PathGradientPaint(colors, fractions);
     }
 
-    protected void snapToAnchor(Point2D p, Rectangle2D anchor) {
-        if (p.getX() < anchor.getX()) {
-            p.setLocation(anchor.getX(), p.getY());
-        } else if (p.getX() > (anchor.getX() + anchor.getWidth())) {
-            p.setLocation(anchor.getX() + anchor.getWidth(), p.getY());
-        }
-
-        if (p.getY() < anchor.getY()) {
-            p.setLocation(p.getX(), anchor.getY());
-        } else if (p.getY() > (anchor.getY() + anchor.getHeight())) {
-            p.setLocation(p.getX(), anchor.getY() + anchor.getHeight());
-        }
-    }
-
     /**
      *  Convert HSL values to a RGB Color.
      *
@@ -568,7 +578,7 @@ public class DrawPaint {
 
         //  Calculate the Saturation
 
-        double s = 0;
+        final double s;
 
         if (max == min) {
             s = 0;
diff --git a/src/java/org/apache/poi/sl/usermodel/AbstractColorStyle.java b/src/java/org/apache/poi/sl/usermodel/AbstractColorStyle.java
new file mode 100644 (file)
index 0000000..32e146e
--- /dev/null
@@ -0,0 +1,47 @@
+/* ====================================================================
+   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.sl.usermodel;
+
+import java.util.Objects;
+
+import org.apache.poi.sl.draw.DrawPaint;
+import org.apache.poi.util.Internal;
+
+
+/**
+ * Helper class for ColorStyle - not part of the API / implementation may change any time
+ */
+@Internal
+public abstract class AbstractColorStyle implements ColorStyle {
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) {
+            return true;
+        }
+        if (!(o instanceof ColorStyle)) {
+            return false;
+        }
+        return Objects.equals(DrawPaint.applyColorTransform(this), DrawPaint.applyColorTransform((ColorStyle)o));
+    }
+
+    @Override
+    public int hashCode() {
+        return DrawPaint.applyColorTransform(this).hashCode();
+    }
+
+}
index d5c40a7ccfbd585b1fe996411f620e7c82e5c7ca..4b9d3106636b576828f7b4d04c33676856293131 100644 (file)
@@ -21,6 +21,7 @@ package org.apache.poi.xslf.usermodel;
 import java.awt.Color;
 
 import org.apache.poi.sl.draw.DrawPaint;
+import org.apache.poi.sl.usermodel.AbstractColorStyle;
 import org.apache.poi.sl.usermodel.ColorStyle;
 import org.apache.poi.sl.usermodel.PresetColor;
 import org.apache.poi.util.Beta;
@@ -52,6 +53,7 @@ public class XSLFColor {
     private Color _color;
     private CTSchemeColor _phClr;
 
+    @SuppressWarnings("WeakerAccess")
     public XSLFColor(XmlObject obj, XSLFTheme theme, CTSchemeColor phClr) {
         _xmlObject = obj;
         _phClr = phClr;
@@ -72,8 +74,9 @@ public class XSLFColor {
         return DrawPaint.applyColorTransform(getColorStyle());
     }
 
+    @SuppressWarnings("WeakerAccess")
     public ColorStyle getColorStyle() {
-        return new ColorStyle() {
+        return new AbstractColorStyle() {
             @Override
             public Color getColor() {
                 return _color;
@@ -126,7 +129,7 @@ public class XSLFColor {
         };
     }
     
-    Color toColor(XmlObject obj, XSLFTheme theme) {
+    private Color toColor(XmlObject obj, XSLFTheme theme) {
         Color color = null;
         for (XmlObject ch : obj.selectPath("*")) {
             if (ch instanceof CTHslColor) {
@@ -178,10 +181,7 @@ public class XSLFColor {
                         color = Color.black;
                     }
                 }
-            } else if (ch instanceof CTFontReference) {
-                // try next ...
-                continue;
-            } else {
+            } else if (!(ch instanceof CTFontReference)) {
                 throw new IllegalArgumentException("Unexpected color choice: " + ch.getClass());
             }
         }
@@ -298,11 +298,6 @@ public class XSLFColor {
         return (val == -1) ? val : (val / 1000);
     }
 
-    private int getAngleValue(String elem){
-        int val = getRawValue(elem);
-        return (val == -1) ? val : (val / 60000);
-    }
-
     /**
      * the opacity as expressed by a percentage value
      *
@@ -336,14 +331,18 @@ public class XSLFColor {
     }
 
 
+    @SuppressWarnings("unused")
     int getHue(){
-        return getAngleValue("hue");
+        int val = getRawValue("hue");
+        return (val == -1) ? val : (val / 60000);
     }
 
+    @SuppressWarnings("unused")
     int getHueMod(){
         return getPercentageValue("hueMod");
     }
 
+    @SuppressWarnings("unused")
     int getHueOff(){
         return getPercentageValue("hueOff");
     }
@@ -355,6 +354,7 @@ public class XSLFColor {
      * @return  luminance in percents in the range [0..100]
      * or -1 if the value is not set
      */
+    @SuppressWarnings("unused")
     int getLum(){
         return getPercentageValue("lum");
     }
@@ -422,10 +422,12 @@ public class XSLFColor {
         return getPercentageValue("red");
     }
 
+    @SuppressWarnings("unused")
     int getRedMod(){
         return getPercentageValue("redMod");
     }
 
+    @SuppressWarnings("unused")
     int getRedOff(){
         return getPercentageValue("redOff");
     }
@@ -442,10 +444,12 @@ public class XSLFColor {
         return getPercentageValue("green");
     }
 
+    @SuppressWarnings("unused")
     int getGreenMod(){
         return getPercentageValue("greenMod");
     }
 
+    @SuppressWarnings("unused")
     int getGreenOff(){
         return getPercentageValue("greenOff");
     }
@@ -462,10 +466,12 @@ public class XSLFColor {
         return getPercentageValue("blue");
     }
 
+    @SuppressWarnings("unused")
     int getBlueMod(){
         return getPercentageValue("blueMod");
     }
 
+    @SuppressWarnings("unused")
     int getBlueOff(){
         return getPercentageValue("blueOff");
     }
@@ -478,6 +484,7 @@ public class XSLFColor {
      * percentage with 0% indicating minimal shade and 100% indicating maximum
      * or -1 if the value is not set
      */
+    @SuppressWarnings("WeakerAccess")
     public int getShade(){
         return getPercentageValue("shade");
     }
index 9df566929a1be0855dcb2324776e17cb15b241e2..b86d553490dc02aaf97848dd13d5dd653ea404fb 100644 (file)
@@ -19,6 +19,7 @@ package org.apache.poi.xslf.usermodel;
 import java.net.URI;
 
 import org.apache.poi.common.usermodel.HyperlinkType;
+import org.apache.poi.ooxml.POIXMLDocumentPart;
 import org.apache.poi.ooxml.POIXMLDocumentPart.RelationPart;
 import org.apache.poi.openxml4j.opc.PackagePart;
 import org.apache.poi.openxml4j.opc.PackageRelationship;
@@ -155,13 +156,45 @@ public class XSLFHyperlink implements Hyperlink<XSLFShape,XSLFTextParagraph> {
     public void linkToLastSlide() {
         linkToRelativeSlide("lastslide");
     }
-    
+
+    void copy(XSLFHyperlink src) {
+        switch (src.getType()) {
+            case EMAIL:
+            case URL:
+                linkToExternal(src.getAddress());
+                break;
+            case DOCUMENT:
+                final String idSrc = src._link.getId();
+                if (idSrc == null || idSrc.isEmpty()) {
+                    // link to slide - relative reference
+                    linkToRelativeSlide(src.getAddress());
+                } else {
+                    // link to slide . absolute reference
+                    // this is kind of a hack, as we might link to pages not yet imported,
+                    // but the underlying implementation is based only on package part names,
+                    // so this actually works ...
+                    POIXMLDocumentPart pp = src._sheet.getRelationById(idSrc);
+                    if (pp != null) {
+                        RelationPart rp = _sheet.addRelation(null, XSLFRelation.SLIDE, pp);
+                        _link.setId(rp.getRelationship().getId());
+                        _link.setAction(src._link.getAction());
+                    }
+                }
+                break;
+            default:
+            case FILE:
+            case NONE:
+                return;
+        }
+        setLabel(src.getLabel());
+    }
+
     private void linkToRelativeSlide(String jump) {
         PackagePart thisPP = _sheet.getPackagePart();
         if (_link.isSetId() && !_link.getId().isEmpty()) {
             thisPP.removeRelationship(_link.getId());
         }
         _link.setId("");
-        _link.setAction("ppaction://hlinkshowjump?jump="+jump);
+        _link.setAction((jump.startsWith("ppaction") ? "" : "ppaction://hlinkshowjump?jump=") + jump);
     }
 }
index 62f009a15ab784036e58e1c6e3f5dac8bcf7c93f..0ea5e349165a85d03f216182d1ec4d77abbcdeae 100644 (file)
@@ -26,8 +26,10 @@ import org.apache.poi.sl.usermodel.PictureData.PictureType;
 import org.apache.poi.util.Beta;
 import org.apache.poi.xssf.usermodel.XSSFWorkbook;
 
+@SuppressWarnings({"unused", "WeakerAccess"})
 @Beta
-public class XSLFRelation extends POIXMLRelation {
+public final class XSLFRelation extends POIXMLRelation {
+    /* package */ static final String NS_DRAWINGML = "http://schemas.openxmlformats.org/drawingml/2006/main";
 
     /**
      * A map to lookup POIXMLRelation by its relation type
index 66d9a67bfd76c509053937726e5ccfa31720032c..4d162027e8654cc2943ce3b7ca1c9960d98a9c36 100644 (file)
@@ -24,7 +24,6 @@ import java.awt.geom.Rectangle2D;
 import java.io.IOException;
 import java.io.InputStream;
 import java.util.Arrays;
-import java.util.Comparator;
 
 import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
 import org.apache.poi.openxml4j.opc.PackagePart;
@@ -178,10 +177,12 @@ public abstract class XSLFShape implements Shape<XSLFShape,XSLFTextParagraph> {
         return fetcher.getValue();
     }
 
+    @SuppressWarnings("unused")
     protected CTBackgroundProperties getBgPr() {
         return getChild(CTBackgroundProperties.class, PML_NS, "bgPr");
     }
     
+    @SuppressWarnings("unused")
     protected CTStyleMatrixReference getBgRef() {
         return getChild(CTStyleMatrixReference.class, PML_NS, "bgRef");
     }
@@ -198,6 +199,7 @@ public abstract class XSLFShape implements Shape<XSLFShape,XSLFTextParagraph> {
         return _nvPr;
     }
 
+    @SuppressWarnings("WeakerAccess")
     protected CTShapeStyle getSpStyle() {
         if (_spStyle == null) {
             _spStyle = getChild(CTShapeStyle.class, PML_NS, "style");
@@ -213,14 +215,14 @@ public abstract class XSLFShape implements Shape<XSLFShape,XSLFTextParagraph> {
      * @param nodename the node name, without prefix
      * @return the properties object or null if it can't be found
      */
-    @SuppressWarnings("unchecked")
+    @SuppressWarnings({"unchecked", "WeakerAccess", "unused", "SameParameterValue"})
     protected <T extends XmlObject> T getChild(Class<T> childClass, String namespace, String nodename) {
         XmlCursor cur = getXmlObject().newCursor();
         T child = null;
         if (cur.toChild(namespace, nodename)) {
             child = (T)cur.getObject();
         }
-        if (cur.toChild("http://schemas.openxmlformats.org/drawingml/2006/main", nodename)) {
+        if (cur.toChild(XSLFRelation.NS_DRAWINGML, nodename)) {
             child = (T)cur.getObject();
         }
         cur.dispose();
@@ -248,6 +250,7 @@ public abstract class XSLFShape implements Shape<XSLFShape,XSLFTextParagraph> {
     /**
      * @see SimpleShape#getPlaceholderDetails()
      */
+    @SuppressWarnings("WeakerAccess")
     public XSLFPlaceholderDetails getPlaceholderDetails() {
         return new XSLFPlaceholderDetails(this);
     }
@@ -262,7 +265,7 @@ public abstract class XSLFShape implements Shape<XSLFShape,XSLFTextParagraph> {
      * @param xquery the simple (xmlbean) xpath expression to the property
      * @return the xml object at the xpath location, or null if not found
      */
-    @SuppressWarnings("unchecked")
+    @SuppressWarnings({"unchecked", "WeakerAccess"})
     protected <T extends XmlObject> T selectProperty(Class<T> resultClass, String xquery) {
         XmlObject[] rs = getXmlObject().selectPath(xquery);
         if (rs.length == 0) return null;
@@ -284,6 +287,7 @@ public abstract class XSLFShape implements Shape<XSLFShape,XSLFTextParagraph> {
      * @param visitor the object that collects the desired property
      * @return true if the property was fetched
      */
+    @SuppressWarnings("WeakerAccess")
     protected boolean fetchShapeProperty(PropertyFetcher<?> visitor) {
         // try shape properties in slide
         if (visitor.fetch(this)) {
@@ -311,9 +315,7 @@ public abstract class XSLFShape implements Shape<XSLFShape,XSLFTextParagraph> {
             XSLFSlideMaster master = (XSLFSlideMaster)sm;
             int textType = getPlaceholderType(ph);
             XSLFSimpleShape masterShape = master.getPlaceholderByType(textType);
-            if (masterShape != null && visitor.fetch(masterShape)) {
-                return true;
-            }
+            return masterShape != null && visitor.fetch(masterShape);
         }
         
         return false;
@@ -348,6 +350,7 @@ public abstract class XSLFShape implements Shape<XSLFShape,XSLFTextParagraph> {
      *
      * @return  the applied Paint or null if none was applied
      */
+    @SuppressWarnings("WeakerAccess")
     protected static PaintStyle selectPaint(XSLFFillProperties fp, final CTSchemeColor phClr, final PackagePart parentPart, final XSLFTheme theme, boolean hasPlaceholder) {
         if (fp == null || fp.isSetNoFill()) {
             return null;
@@ -364,6 +367,7 @@ public abstract class XSLFShape implements Shape<XSLFShape,XSLFTextParagraph> {
         }
     }
 
+    @SuppressWarnings("WeakerAccess")
     protected static PaintStyle selectPaint(CTSolidColorFillProperties solidFill, CTSchemeColor phClr, final XSLFTheme theme) {
         if (solidFill.isSetSchemeClr()) {
                // if there's a reference to the placeholder color,
@@ -379,7 +383,8 @@ public abstract class XSLFShape implements Shape<XSLFShape,XSLFTextParagraph> {
         final XSLFColor c = new XSLFColor(solidFill, theme, phClr);
         return DrawPaint.createSolidPaint(c.getColorStyle());
     }
-    
+
+    @SuppressWarnings("WeakerAccess")
     protected static PaintStyle selectPaint(final CTBlipFillProperties blipFill, final PackagePart parentPart) {
         final CTBlip blip = blipFill.getBlip();
         return new TexturePaint() {
@@ -413,17 +418,17 @@ public abstract class XSLFShape implements Shape<XSLFShape,XSLFTextParagraph> {
             }
         };        
     }
-    
+
+    @SuppressWarnings("WeakerAccess")
     protected static PaintStyle selectPaint(final CTGradientFillProperties gradFill, CTSchemeColor phClr, final XSLFTheme theme) {
 
+        @SuppressWarnings("deprecation")
         final CTGradientStop[] gs = gradFill.getGsLst().getGsArray();
 
-        Arrays.sort(gs, new Comparator<CTGradientStop>() {
-            public int compare(CTGradientStop o1, CTGradientStop o2) {
-                Integer pos1 = o1.getPos();
-                Integer pos2 = o2.getPos();
-                return pos1.compareTo(pos2);
-            }
+        Arrays.sort(gs, (o1, o2) -> {
+            Integer pos1 = o1.getPos();
+            Integer pos2 = o2.getPos();
+            return pos1.compareTo(pos2);
         });
 
         final ColorStyle cs[] = new ColorStyle[gs.length];
@@ -480,6 +485,7 @@ public abstract class XSLFShape implements Shape<XSLFShape,XSLFTextParagraph> {
         };        
     }
     
+    @SuppressWarnings("WeakerAccess")
     protected static PaintStyle selectPaint(CTStyleMatrixReference fillRef, final XSLFTheme theme, boolean isLineStyle, boolean hasPlaceholder) {
         if (fillRef == null) return null;
         
index 07dc096c5b5a3e200c6d53e7851475542b33d217..c8624f071a127d93c877d578cbf37b1c7fe0faf8 100644 (file)
@@ -49,7 +49,6 @@ import org.openxmlformats.schemas.presentationml.x2006.main.CTGraphicalObjectFra
 public class XSLFTable extends XSLFGraphicFrame implements Iterable<XSLFTableRow>,
     TableShape<XSLFShape,XSLFTextParagraph> {
     /* package */ static final String TABLE_URI = "http://schemas.openxmlformats.org/drawingml/2006/table";
-    /* package */ static final String DRAWINGML_URI = "http://schemas.openxmlformats.org/drawingml/2006/main";
 
     private CTTable _table;
     private List<XSLFTableRow> _rows;
@@ -60,7 +59,7 @@ public class XSLFTable extends XSLFGraphicFrame implements Iterable<XSLFTableRow
         CTGraphicalObjectData god = shape.getGraphic().getGraphicData();
         XmlCursor xc = god.newCursor();
         try {
-            if (!xc.toChild(DRAWINGML_URI, "tbl")) {
+            if (!xc.toChild(XSLFRelation.NS_DRAWINGML, "tbl")) {
                 throw new IllegalStateException("a:tbl element was not found in\n " + god);
             }
     
@@ -174,7 +173,7 @@ public class XSLFTable extends XSLFGraphicFrame implements Iterable<XSLFTableRow
         CTGraphicalObjectData gr = frame.addNewGraphic().addNewGraphicData();
         XmlCursor grCur = gr.newCursor();
         grCur.toNextToken();
-        grCur.beginElement(new QName(DRAWINGML_URI, "tbl"));
+        grCur.beginElement(new QName(XSLFRelation.NS_DRAWINGML, "tbl"));
         
         CTTable tbl = CTTable.Factory.newInstance();
         tbl.addNewTblPr();
@@ -191,6 +190,7 @@ public class XSLFTable extends XSLFGraphicFrame implements Iterable<XSLFTableRow
     /**
      * Merge cells of a table
      */
+    @SuppressWarnings("unused")
     public void mergeCells(int firstRow, int lastRow, int firstCol, int lastCol) {
 
        if(firstRow > lastRow) {
@@ -225,14 +225,14 @@ public class XSLFTable extends XSLFGraphicFrame implements Iterable<XSLFTableRow
                                if(i == firstRow) {
                                        cell.setRowSpan(rowSpan);
                                } else {
-                                       cell.setVMerge(true);
+                                       cell.setVMerge();
                                }
                        }
                        if(mergeColumnRequired) {
                                if(colPos == firstCol) {
                                        cell.setGridSpan(colSpan);
                                } else {
-                                       cell.setHMerge(true);
+                                       cell.setHMerge();
                                }
                        }
                }
index 200faeaf8fa83446c0af6001564f48ad1de6b525..63f1965932458e7206ed44222e544ca6e2714773 100644 (file)
@@ -41,7 +41,6 @@ import org.openxmlformats.schemas.drawingml.x2006.main.CTLineEndProperties;
 import org.openxmlformats.schemas.drawingml.x2006.main.CTLineProperties;
 import org.openxmlformats.schemas.drawingml.x2006.main.CTPoint2D;
 import org.openxmlformats.schemas.drawingml.x2006.main.CTPositiveSize2D;
-import org.openxmlformats.schemas.drawingml.x2006.main.CTRegularTextRun;
 import org.openxmlformats.schemas.drawingml.x2006.main.CTSchemeColor;
 import org.openxmlformats.schemas.drawingml.x2006.main.CTSolidColorFillProperties;
 import org.openxmlformats.schemas.drawingml.x2006.main.CTTable;
@@ -104,6 +103,7 @@ public class XSLFTableCell extends XSLFTextShape implements TableCell<XSLFShape,
         return cell;
     }
 
+    @SuppressWarnings("WeakerAccess")
     protected CTTableCellProperties getCellProperties(boolean create) {
         if (_tcPr == null) {
             CTTableCell cell = getCell();
@@ -251,6 +251,7 @@ public class XSLFTableCell extends XSLFTextShape implements TableCell<XSLFShape,
         setBorderWidth(edge, width);
     }
 
+    @SuppressWarnings("WeakerAccess")
     public Double getBorderWidth(BorderEdge edge) {
         CTLineProperties ln = getCTLine(edge, false);
         return (ln == null || !ln.isSetW()) ? null : Units.toPoints(ln.getW());
@@ -320,6 +321,7 @@ public class XSLFTableCell extends XSLFTextShape implements TableCell<XSLFShape,
         c.setColor(color);
     }
 
+    @SuppressWarnings("WeakerAccess")
     public Color getBorderColor(BorderEdge edge) {
         CTLineProperties ln = getCTLine(edge, false);
         if (ln == null || ln.isSetNoFill() || !ln.isSetSolidFill()) {
@@ -331,6 +333,7 @@ public class XSLFTableCell extends XSLFTextShape implements TableCell<XSLFShape,
         return c.getColor();
     }
 
+    @SuppressWarnings("WeakerAccess")
     public LineCompound getBorderCompound(BorderEdge edge) {
         CTLineProperties ln = getCTLine(edge, false);
         if (ln == null || ln.isSetNoFill() || !ln.isSetSolidFill() || !ln.isSetCmpd()) {
@@ -350,6 +353,7 @@ public class XSLFTableCell extends XSLFTextShape implements TableCell<XSLFShape,
         ln.setCmpd(STCompoundLine.Enum.forInt(compound.ooxmlId));
     }
 
+    @SuppressWarnings("WeakerAccess")
     public LineDash getBorderDash(BorderEdge edge) {
         CTLineProperties ln = getCTLine(edge, false);
         if (ln == null || ln.isSetNoFill() || !ln.isSetSolidFill() || !ln.isSetPrstDash()) {
@@ -372,6 +376,7 @@ public class XSLFTableCell extends XSLFTextShape implements TableCell<XSLFShape,
         ln.getPrstDash().setVal(STPresetLineDashVal.Enum.forInt(dash.ooxmlId));
     }
 
+    @SuppressWarnings("WeakerAccess")
     public LineCap getBorderCap(BorderEdge edge) {
         CTLineProperties ln = getCTLine(edge, false);
         if (ln == null || ln.isSetNoFill() || !ln.isSetSolidFill() || !ln.isSetCap()) {
@@ -381,6 +386,7 @@ public class XSLFTableCell extends XSLFTextShape implements TableCell<XSLFShape,
         return LineCap.fromOoxmlId(ln.getCap().intValue());
     }
 
+    @SuppressWarnings("WeakerAccess")
     public void setBorderCap(BorderEdge edge, LineCap cap) {
         if (cap == null) {
             throw new IllegalArgumentException("LineCap need to be specified.");
@@ -544,12 +550,12 @@ public class XSLFTableCell extends XSLFTextShape implements TableCell<XSLFShape,
         return (c.isSetRowSpan()) ? c.getRowSpan() : 1;
     }
 
-    void setHMerge(boolean merge_) {
-        getCell().setHMerge(merge_);
+    void setHMerge() {
+        getCell().setHMerge(true);
     }
 
-    void setVMerge(boolean merge_) {
-        getCell().setVMerge(merge_);
+    void setVMerge() {
+        getCell().setVMerge(true);
     }
 
     @Override
@@ -715,13 +721,13 @@ public class XSLFTableCell extends XSLFTextShape implements TableCell<XSLFShape,
     /**
      * @since POI 3.15-beta2
      */
-    private class XSLFCellTextParagraph extends XSLFTextParagraph {
-        protected XSLFCellTextParagraph(CTTextParagraph p, XSLFTextShape shape) {
+    private final class XSLFCellTextParagraph extends XSLFTextParagraph {
+        private XSLFCellTextParagraph(CTTextParagraph p, XSLFTextShape shape) {
             super(p, shape);
         }
 
         @Override
-        protected XSLFCellTextRun newTextRun(CTRegularTextRun r) {
+        protected XSLFCellTextRun newTextRun(XmlObject r) {
             return new XSLFCellTextRun(r, this);
         }
     }
@@ -729,8 +735,8 @@ public class XSLFTableCell extends XSLFTextShape implements TableCell<XSLFShape,
     /**
      * @since POI 3.15-beta2
      */
-    private class XSLFCellTextRun extends XSLFTextRun {
-        protected XSLFCellTextRun(CTRegularTextRun r, XSLFTextParagraph p) {
+    private final class XSLFCellTextRun extends XSLFTextRun {
+        private XSLFCellTextRun(XmlObject r, XSLFTextParagraph p) {
             super(r, p);
         }
 
index 835b4438a7e6be36cc732cbfc59b06062fb3308b..08112499c4d28f023b44805dbbc514e39fc6fa3d 100644 (file)
@@ -39,6 +39,7 @@ public class XSLFTableRow implements Iterable<XSLFTableCell> {
     /*package*/ XSLFTableRow(CTTableRow row, XSLFTable table){
         _row = row;
         _table = table;
+        @SuppressWarnings("deprecation")
         CTTableCell[] tcArray = _row.getTcArray();
         _cells = new ArrayList<>(tcArray.length);
         for(CTTableCell cell : tcArray) {
@@ -86,6 +87,7 @@ public class XSLFTableRow implements Iterable<XSLFTableCell> {
      * @param firstCol 0-based index of first column to merge, inclusive
      * @param lastCol 0-based index of last column to merge, inclusive
      */
+    @SuppressWarnings("WeakerAccess")
     public void mergeCells(int firstCol, int lastCol)
     {
         if (firstCol >= lastCol) {
@@ -99,7 +101,7 @@ public class XSLFTableRow implements Iterable<XSLFTableCell> {
 
         _cells.get(firstCol).setGridSpan(colSpan);
         for (final XSLFTableCell cell : _cells.subList(firstCol+1, lastCol+1)) {
-            cell.setHMerge(true);
+            cell.setHMerge();
         }
     }
 
index 68b4b22a2f811d107eb1a8731ecb3425e21aad9a..91c85ebe47726f3868cb8bb4488a48e1af6de7dd 100644 (file)
@@ -134,6 +134,13 @@ public class XSLFTextParagraph implements TextParagraph<XSLFShape,XSLFTextParagr
             // by default line break has the font size of the last text run
             CTTextCharacterProperties prevRun = _runs.get(_runs.size() - 1).getRPr(true);
             brProps.set(prevRun);
+            // don't copy hlink properties
+            if (brProps.isSetHlinkClick()) {
+                brProps.unsetHlinkClick();
+            }
+            if (brProps.isSetHlinkMouseOver()) {
+                brProps.unsetHlinkMouseOver();
+            }
         }
         _runs.add(run);
         return run;
@@ -188,6 +195,7 @@ public class XSLFTextParagraph implements TextParagraph<XSLFShape,XSLFTextParagr
      *
      * @param align font align
      */
+    @SuppressWarnings("unused")
     public void setFontAlign(FontAlign align){
         CTTextParagraphProperties pr = _p.isSetPPr() ? _p.getPPr() : _p.addNewPPr();
         if(align == null) {
@@ -718,7 +726,7 @@ public class XSLFTextParagraph implements TextParagraph<XSLFShape,XSLFTextParagr
      * @return master style text paragraph properties, or <code>null</code> if 
      * there are no master slides or the master slides do not contain a text paragraph
      */
-    /* package */ CTTextParagraphProperties getDefaultMasterStyle(){
+    private CTTextParagraphProperties getDefaultMasterStyle(){
         CTPlaceholder ph = _shape.getPlaceholderDetails().getCTPlaceholder(false);
         String defaultStyleSelector;  
         switch(ph == null ? -1 : ph.getType().intValue()) {
@@ -740,7 +748,6 @@ public class XSLFTextParagraph implements TextParagraph<XSLFShape,XSLFTextParagr
 
         // wind up and find the root master sheet which must be slide master
         final String nsPML = "http://schemas.openxmlformats.org/presentationml/2006/main";
-        final String nsDML = "http://schemas.openxmlformats.org/drawingml/2006/main";
         XSLFSheet masterSheet = _shape.getSheet();
         for (XSLFSheet m = masterSheet; m != null; m = (XSLFSheet)m.getMasterSheet()) {
             masterSheet = m;
@@ -752,7 +759,7 @@ public class XSLFTextParagraph implements TextParagraph<XSLFShape,XSLFTextParagr
                        (cur.pop() && cur.toChild(nsPML, "notesStyle"))) {
                     while (level >= 0) {
                         cur.push();
-                       if (cur.toChild(nsDML, "lvl" +(level+1)+ "pPr")) {
+                       if (cur.toChild(XSLFRelation.NS_DRAWINGML, "lvl" +(level+1)+ "pPr")) {
                                return (CTTextParagraphProperties)cur.getObject();
                        }
                        cur.pop();
@@ -788,11 +795,13 @@ public class XSLFTextParagraph implements TextParagraph<XSLFShape,XSLFTextParagr
         fetchMasterProperty(visitor);
     }
 
-    boolean fetchMasterProperty(final ParagraphPropertyFetcher<?> visitor) {
+    void fetchMasterProperty(final ParagraphPropertyFetcher<?> visitor) {
         // defaults for placeholders are defined in the slide master
         final CTTextParagraphProperties defaultProps = getDefaultMasterStyle();
         // TODO: determine master shape
-        return defaultProps != null && visitor.fetch(defaultProps);
+        if (defaultProps != null) {
+            visitor.fetch(defaultProps);
+        }
     }
 
     boolean fetchThemeProperty(final ParagraphPropertyFetcher<?> visitor) {
@@ -836,15 +845,15 @@ public class XSLFTextParagraph implements TextParagraph<XSLFShape,XSLFTextParagr
         otherC.dispose();
         thisC.dispose();
         
-        List<XSLFTextRun> otherRs = other.getTextRuns();
-        int i=0;
-        for(CTRegularTextRun rtr : thisP.getRList()) {
-            XSLFTextRun run = newTextRun(rtr);
-            run.copy(otherRs.get(i++));
+        for (XSLFTextRun tr : other.getTextRuns()) {
+            XmlObject xo = tr.getXmlObject();
+            XSLFTextRun run = (xo instanceof CTTextLineBreak)
+                ? newTextRun((CTTextLineBreak)xo)
+                : newTextRun(xo);
+            run.copy(tr);
             _runs.add(run);
         }
-        
-        
+
         // set properties again, in case we are based on a different
         // template
         TextAlign srcAlign = other.getTextAlign();
@@ -998,6 +1007,7 @@ public class XSLFTextParagraph implements TextParagraph<XSLFShape,XSLFTextParagr
             public boolean fetch(CTTextParagraphProperties props) {
                 if (props.isSetTabLst()) {
                     final List<XSLFTabStop> list = new ArrayList<>();
+                    //noinspection deprecation
                     for (final CTTextTabStop ta : props.getTabLst().getTabArray()) {
                         list.add(new XSLFTabStop(ta));
                     }
@@ -1021,6 +1031,10 @@ public class XSLFTextParagraph implements TextParagraph<XSLFShape,XSLFTextParagr
             final CTTextParagraph xo = getXmlObject();
             tpp = (xo.isSetPPr()) ? xo.getPPr() : xo.addNewPPr();
         }
+
+        if (tpp == null) {
+            return;
+        }
         final CTTextTabStopList stl = (tpp.isSetTabLst()) ? tpp.getTabLst() : tpp.addNewTabLst();
         XSLFTabStop tab = new XSLFTabStop(stl.addNewTab());
         tab.setPositionInPoints(positionInPoints);
@@ -1090,7 +1104,12 @@ public class XSLFTextParagraph implements TextParagraph<XSLFShape,XSLFTextParagr
      * 
      * @since POI 3.15-beta2
      */
-    protected XSLFTextRun newTextRun(CTRegularTextRun r) {
+    protected XSLFTextRun newTextRun(XmlObject r) {
         return new XSLFTextRun(r, this);
     }
+
+    @SuppressWarnings("WeakerAccess")
+    protected XSLFTextRun newTextRun(CTTextLineBreak r) {
+        return new XSLFLineBreak(r, this);
+    }
 }
index 40afebf051fc8b241991b80da77248ea8fd1c4f4..be714cbd858967fbcd002fbb40625c406b5a7c79 100644 (file)
@@ -581,6 +581,12 @@ public class XSLFTextRun implements TextRun {
         if(strike != isStrikethrough()) {
             setStrikethrough(strike);
         }
+
+        XSLFHyperlink hyperSrc = r.getHyperlink();
+        if (hyperSrc != null) {
+            XSLFHyperlink hyperDst = getHyperlink();
+            hyperDst.copy(hyperSrc);
+        }
     }
 
 
index a13ad5bfa29653fe07527cd485076ac80d3e9abd..929839b96dac70f1d427fc836045c3055109734f 100644 (file)
@@ -37,7 +37,6 @@ import org.openxmlformats.schemas.drawingml.x2006.main.CTColor;
 import org.openxmlformats.schemas.drawingml.x2006.main.CTColorMapping;
 import org.openxmlformats.schemas.drawingml.x2006.main.CTColorScheme;
 import org.openxmlformats.schemas.drawingml.x2006.main.CTOfficeStyleSheet;
-import org.openxmlformats.schemas.drawingml.x2006.main.CTTextParagraphProperties;
 import org.openxmlformats.schemas.drawingml.x2006.main.ThemeDocument;
 
 /**
@@ -66,6 +65,7 @@ public class XSLFTheme extends POIXMLDocumentPart {
         initialize();
     }
 
+    @SuppressWarnings("WeakerAccess")
     public void importTheme(XSLFTheme theme) {
         _theme = theme.getXmlObject();
         _schemeColors = theme._schemeColors;
@@ -134,7 +134,7 @@ public class XSLFTheme extends POIXMLDocumentPart {
     protected final void commit() throws IOException {
         XmlOptions xmlOptions = new XmlOptions(DEFAULT_XML_OPTIONS);
         xmlOptions.setSaveSyntheticDocumentElement(
-            new QName("http://schemas.openxmlformats.org/drawingml/2006/main", "theme"));
+            new QName(XSLFRelation.NS_DRAWINGML, "theme"));
 
         PackagePart part = getPackagePart();
         OutputStream out = part.getOutputStream();
@@ -147,6 +147,7 @@ public class XSLFTheme extends POIXMLDocumentPart {
      * Typically the major font is used for heading areas of a document.
      *
      */
+    @SuppressWarnings("WeakerAccess")
     public String getMajorFont(){
         return _theme.getThemeElements().getFontScheme().getMajorFont().getLatin().getTypeface();
     }
@@ -156,19 +157,8 @@ public class XSLFTheme extends POIXMLDocumentPart {
      * Typically the monor font is used for normal text or paragraph areas.
      *
      */
+    @SuppressWarnings("WeakerAccess")
     public String getMinorFont(){
         return _theme.getThemeElements().getFontScheme().getMinorFont().getLatin().getTypeface();
     }
-
-
-    CTTextParagraphProperties getDefaultParagraphStyle(){
-        XmlObject[] o = _theme.selectPath(
-                "declare namespace p='http://schemas.openxmlformats.org/presentationml/2006/main' " +
-                "declare namespace a='http://schemas.openxmlformats.org/drawingml/2006/main' " +
-                ".//a:objectDefaults/a:spDef/a:lstStyle/a:defPPr");
-        if(o.length == 1){
-            return (CTTextParagraphProperties)o[0];
-        }
-        return null;
-    }
 }
index 91c0fb4a27cc56661f514ed3677d49422b35835e..c594280654a20ee652a48837f67f9d9839db0242 100644 (file)
@@ -81,6 +81,7 @@ import org.apache.poi.xslf.usermodel.XSLFSlideMaster;
 import org.apache.poi.xslf.usermodel.XSLFTable;
 import org.apache.poi.xslf.usermodel.XSLFTableCell;
 import org.apache.poi.xslf.usermodel.XSLFTableRow;
+import org.apache.poi.xslf.usermodel.XSLFTextBox;
 import org.apache.poi.xslf.usermodel.XSLFTextParagraph;
 import org.apache.poi.xslf.usermodel.XSLFTextRun;
 import org.junit.Ignore;
@@ -92,6 +93,54 @@ import org.openxmlformats.schemas.presentationml.x2006.main.CTShape;
 public class TestXSLFBugs {
     private static final POIDataSamples slTests = POIDataSamples.getSlideShowInstance();
 
+
+    @Test
+    public void bug61589() throws IOException {
+        ByteArrayOutputStream bos = new ByteArrayOutputStream();
+        try (XMLSlideShow src = new XMLSlideShow();
+             XMLSlideShow dest = new XMLSlideShow()) {
+            XSLFSlide slide = src.createSlide();
+            XSLFSlide slide2 = src.createSlide();
+
+            XSLFTextBox shape = slide.createTextBox();
+            shape.setAnchor(new Rectangle2D.Double(100,100,400,100));
+            XSLFTextParagraph p = shape.addNewTextParagraph();
+
+            XSLFTextRun r = p.addNewTextRun();
+            p.addLineBreak();
+            r.setText("Apache POI");
+            r.createHyperlink().setAddress("http://poi.apache.org");
+            // create hyperlink pointing to a page, which isn't available at the time of importing the content
+            r = p.addNewTextRun();
+            r.setText("Slide 2");
+            r.createHyperlink().linkToSlide(slide2);
+
+            shape = slide2.createTextBox();
+            shape.setAnchor(new Rectangle2D.Double(100,100,400,100));
+            shape.setText("slide 2");
+
+            dest.createSlide().importContent(slide);
+            dest.createSlide().importContent(slide2);
+
+            dest.write(bos);
+        }
+
+        try (XMLSlideShow ppt = new XMLSlideShow(new ByteArrayInputStream(bos.toByteArray()))) {
+            XSLFSlide slide = ppt.getSlides().get(0);
+            XSLFTextBox shape = (XSLFTextBox)slide.getShapes().get(0);
+            XSLFTextParagraph p = shape.getTextParagraphs().get(1);
+            XSLFHyperlink h1 = p.getTextRuns().get(0).getHyperlink();
+            assertNotNull(h1);
+            assertEquals("http://poi.apache.org", h1.getAddress());
+            XSLFHyperlink h2 = p.getTextRuns().get(2).getHyperlink();
+            assertNotNull(h2);
+            // relative url will be resolved to an absolute url, therefore this doesn't equals to "slide2.xml"
+            assertEquals("/ppt/slides/slide2.xml", h2.getAddress());
+            RelationPart sldRef = slide.getRelationPartById(h2.getXmlObject().getId());
+            assertTrue(sldRef.getDocumentPart() instanceof XSLFSlide);
+        }
+    }
+
     @Test
     public void bug62587() throws IOException {
         ByteArrayOutputStream bos = new ByteArrayOutputStream();