git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1837909 13f79535-47bb-0310-9956-ffa450edef68tags/REL_4_0_0_FINAL
@@ -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; |
@@ -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(); | |||
} | |||
} |
@@ -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"); | |||
} |
@@ -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); | |||
} | |||
} |
@@ -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 |
@@ -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; | |||
@@ -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(); | |||
} | |||
} | |||
} |
@@ -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); | |||
} | |||
@@ -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(); | |||
} | |||
} | |||
@@ -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); | |||
} | |||
} |
@@ -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); | |||
} | |||
} | |||
@@ -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; | |||
} | |||
} |
@@ -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(); |