#61589 - Importing content does not copy hyperlink address

git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1837909 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Andreas Beeker 2018-08-12 22:35:02 +00:00
parent 1691c2372a
commit 1407ace4f7
13 changed files with 269 additions and 92 deletions

View 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;

View File

@ -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();
}
}

View 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");
}

View 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;
@ -156,12 +157,44 @@ public class XSLFHyperlink implements Hyperlink<XSLFShape,XSLFTextParagraph> {
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);
}
}

View 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

View 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,
@ -380,6 +384,7 @@ public abstract class XSLFShape implements Shape<XSLFShape,XSLFTextParagraph> {
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() {
@ -414,16 +419,16 @@ 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) {
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;

View 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();
}
}
}

View 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);
}

View 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();
}
}

View 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);
}
}

View 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);
}
}

View 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;
}
}

View 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();