#60625 - Rendering issue with background and shape overlayed by image

git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1782096 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Andreas Beeker 2017-02-08 01:12:22 +00:00
parent ac3d63926a
commit 5c4ab1dbdf
47 changed files with 1205 additions and 764 deletions

View File

@ -17,7 +17,13 @@
package org.apache.poi.sl.draw; package org.apache.poi.sl.draw;
import org.apache.poi.sl.usermodel.*; import java.awt.Graphics2D;
import org.apache.poi.sl.usermodel.MasterSheet;
import org.apache.poi.sl.usermodel.Placeholder;
import org.apache.poi.sl.usermodel.Shape;
import org.apache.poi.sl.usermodel.SimpleShape;
import org.apache.poi.sl.usermodel.Slide;
public class DrawMasterSheet extends DrawSheet { public class DrawMasterSheet extends DrawSheet {
@ -33,12 +39,15 @@ public class DrawMasterSheet extends DrawSheet {
* for instance, slide masters and layouts don't display placeholders * for instance, slide masters and layouts don't display placeholders
*/ */
@Override @Override
protected boolean canDraw(Shape<?,?> shape) { protected boolean canDraw(Graphics2D graphics, Shape<?,?> shape) {
if (shape instanceof SimpleShape) { if (shape instanceof SimpleShape) {
// in XSLF, slidenumber and date shapes aren't marked as placeholders opposed to HSLF
Placeholder ph = ((SimpleShape<?,?>)shape).getPlaceholder(); Placeholder ph = ((SimpleShape<?,?>)shape).getPlaceholder();
return ph == null; if (ph != null) {
} else { Slide<?,?> slide = (Slide<?,?>)graphics.getRenderingHint(Drawable.CURRENT_SLIDE);
return true; return slide.getDisplayPlaceholder(ph);
}
} }
return true;
} }
} }

View File

@ -38,18 +38,34 @@ public class DrawShape implements Drawable {
this.shape = shape; this.shape = shape;
} }
/**
* Sometimes it's necessary to distinguish between XSLF/HSLF for the rendering.
* Use this method on the shape to determine, if we work on the BIFF implementation
*
* @param shape the shape to render
* @return {@code true} if HSLF implementation is used
*/
protected static boolean isHSLF(Shape<?,?> shape) {
return shape.getClass().getCanonicalName().toLowerCase(Locale.ROOT).contains("hslf");
}
/** /**
* Apply 2-D transforms before drawing this shape. This includes rotation and flipping. * Apply 2-D transforms before drawing this shape. This includes rotation and flipping.
* *
* @param graphics the graphics whos transform matrix will be modified * @param graphics the graphics whos transform matrix will be modified
*/ */
@Override
public void applyTransform(Graphics2D graphics) { public void applyTransform(Graphics2D graphics) {
if (!(shape instanceof PlaceableShape)) return; if (!(shape instanceof PlaceableShape)) {
return;
}
PlaceableShape<?,?> ps = (PlaceableShape<?,?>)shape; PlaceableShape<?,?> ps = (PlaceableShape<?,?>)shape;
final boolean isHSLF = ps.getClass().getCanonicalName().toLowerCase(Locale.ROOT).contains("hslf"); final boolean isHSLF = isHSLF(shape);
AffineTransform tx = (AffineTransform)graphics.getRenderingHint(Drawable.GROUP_TRANSFORM); AffineTransform tx = (AffineTransform)graphics.getRenderingHint(Drawable.GROUP_TRANSFORM);
if (tx == null) tx = new AffineTransform(); if (tx == null) {
tx = new AffineTransform();
}
final Rectangle2D anchor = tx.createTransformedShape(ps.getAnchor()).getBounds2D(); final Rectangle2D anchor = tx.createTransformedShape(ps.getAnchor()).getBounds2D();
char cmds[] = isHSLF ? new char[]{ 'h','v','r' } : new char[]{ 'r','h','v' }; char cmds[] = isHSLF ? new char[]{ 'h','v','r' } : new char[]{ 'r','h','v' };
@ -81,7 +97,9 @@ public class DrawShape implements Drawable {
// normalize rotation // normalize rotation
rotation %= 360.; rotation %= 360.;
if (rotation < 0) rotation += 360.; if (rotation < 0) {
rotation += 360.;
}
int quadrant = (((int)rotation+45)/90)%4; int quadrant = (((int)rotation+45)/90)%4;
double scaleX = 1.0, scaleY = 1.0; double scaleX = 1.0, scaleY = 1.0;
@ -148,9 +166,11 @@ public class DrawShape implements Drawable {
return (dim2 == 0.) ? 1 : dim1/dim2; return (dim2 == 0.) ? 1 : dim1/dim2;
} }
@Override
public void draw(Graphics2D graphics) { public void draw(Graphics2D graphics) {
} }
@Override
public void drawContent(Graphics2D graphics) { public void drawContent(Graphics2D graphics) {
} }
@ -176,7 +196,10 @@ public class DrawShape implements Drawable {
protected static BasicStroke getStroke(StrokeStyle strokeStyle) { protected static BasicStroke getStroke(StrokeStyle strokeStyle) {
float lineWidth = (float) strokeStyle.getLineWidth(); float lineWidth = (float) strokeStyle.getLineWidth();
if (lineWidth == 0.0f) lineWidth = 0.25f; // Both PowerPoint and OOo draw zero-length lines as 0.25pt if (lineWidth == 0.0f) {
// Both PowerPoint and OOo draw zero-length lines as 0.25pt
lineWidth = 0.25f;
}
LineDash lineDash = strokeStyle.getLineDash(); LineDash lineDash = strokeStyle.getLineDash();
if (lineDash == null) { if (lineDash == null) {
@ -194,7 +217,9 @@ public class DrawShape implements Drawable {
} }
LineCap lineCapE = strokeStyle.getLineCap(); LineCap lineCapE = strokeStyle.getLineCap();
if (lineCapE == null) lineCapE = LineCap.FLAT; if (lineCapE == null) {
lineCapE = LineCap.FLAT;
}
int lineCap; int lineCap;
switch (lineCapE) { switch (lineCapE) {
case ROUND: case ROUND:

View File

@ -17,13 +17,14 @@
package org.apache.poi.sl.draw; package org.apache.poi.sl.draw;
import java.awt.Dimension;
import java.awt.Color; import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics2D; import java.awt.Graphics2D;
import java.awt.geom.AffineTransform; import java.awt.geom.AffineTransform;
import org.apache.poi.sl.usermodel.*; import org.apache.poi.sl.usermodel.MasterSheet;
import org.apache.poi.sl.usermodel.Shape;
import org.apache.poi.sl.usermodel.Sheet;
public class DrawSheet implements Drawable { public class DrawSheet implements Drawable {
@ -34,6 +35,7 @@ public class DrawSheet implements Drawable {
this.sheet = sheet; this.sheet = sheet;
} }
@Override
public void draw(Graphics2D graphics) { public void draw(Graphics2D graphics) {
Dimension dim = sheet.getSlideShow().getPageSize(); Dimension dim = sheet.getSlideShow().getPageSize();
Color whiteTrans = new Color(1f,1f,1f,0f); Color whiteTrans = new Color(1f,1f,1f,0f);
@ -51,7 +53,9 @@ public class DrawSheet implements Drawable {
graphics.setRenderingHint(Drawable.GROUP_TRANSFORM, new AffineTransform()); graphics.setRenderingHint(Drawable.GROUP_TRANSFORM, new AffineTransform());
for (Shape<?,?> shape : sheet.getShapes()) { for (Shape<?,?> shape : sheet.getShapes()) {
if(!canDraw(shape)) continue; if(!canDraw(graphics, shape)) {
continue;
}
// remember the initial transform and restore it after we are done with drawing // remember the initial transform and restore it after we are done with drawing
AffineTransform at = graphics.getTransform(); AffineTransform at = graphics.getTransform();
@ -73,9 +77,11 @@ public class DrawSheet implements Drawable {
} }
} }
@Override
public void applyTransform(Graphics2D context) { public void applyTransform(Graphics2D context) {
} }
@Override
public void drawContent(Graphics2D context) { public void drawContent(Graphics2D context) {
} }
@ -85,7 +91,7 @@ public class DrawSheet implements Drawable {
* Subclasses can override it and skip certain shapes from drawings, * Subclasses can override it and skip certain shapes from drawings,
* for instance, slide masters and layouts don't display placeholders * for instance, slide masters and layouts don't display placeholders
*/ */
protected boolean canDraw(Shape<?,?> shape){ protected boolean canDraw(Graphics2D graphics, Shape<?,?> shape){
return true; return true;
} }
} }

View File

@ -29,6 +29,8 @@ public class DrawSlide extends DrawSheet {
} }
public void draw(Graphics2D graphics) { public void draw(Graphics2D graphics) {
graphics.setRenderingHint(Drawable.CURRENT_SLIDE, this.sheet);
Background<?,?> bg = sheet.getBackground(); Background<?,?> bg = sheet.getBackground();
if(bg != null) { if(bg != null) {
DrawFactory drawFact = DrawFactory.getInstance(graphics); DrawFactory drawFact = DrawFactory.getInstance(graphics);
@ -37,5 +39,6 @@ public class DrawSlide extends DrawSheet {
} }
super.draw(graphics); super.draw(graphics);
graphics.setRenderingHint(Drawable.CURRENT_SLIDE, null);
} }
} }

View File

@ -41,10 +41,12 @@ import org.apache.poi.sl.usermodel.PaintStyle;
import org.apache.poi.sl.usermodel.PlaceableShape; import org.apache.poi.sl.usermodel.PlaceableShape;
import org.apache.poi.sl.usermodel.ShapeContainer; import org.apache.poi.sl.usermodel.ShapeContainer;
import org.apache.poi.sl.usermodel.Sheet; import org.apache.poi.sl.usermodel.Sheet;
import org.apache.poi.sl.usermodel.Slide;
import org.apache.poi.sl.usermodel.TextParagraph; import org.apache.poi.sl.usermodel.TextParagraph;
import org.apache.poi.sl.usermodel.TextParagraph.BulletStyle; import org.apache.poi.sl.usermodel.TextParagraph.BulletStyle;
import org.apache.poi.sl.usermodel.TextParagraph.TextAlign; import org.apache.poi.sl.usermodel.TextParagraph.TextAlign;
import org.apache.poi.sl.usermodel.TextRun; import org.apache.poi.sl.usermodel.TextRun;
import org.apache.poi.sl.usermodel.TextRun.FieldType;
import org.apache.poi.sl.usermodel.TextRun.TextCap; import org.apache.poi.sl.usermodel.TextRun.TextCap;
import org.apache.poi.sl.usermodel.TextShape; import org.apache.poi.sl.usermodel.TextShape;
import org.apache.poi.sl.usermodel.TextShape.TextDirection; import org.apache.poi.sl.usermodel.TextShape.TextDirection;
@ -82,6 +84,7 @@ public class DrawTextParagraph implements Drawable {
/** /**
* Resolves instances being deserialized to the predefined constants. * Resolves instances being deserialized to the predefined constants.
*/ */
@Override
protected Object readResolve() throws InvalidObjectException { protected Object readResolve() throws InvalidObjectException {
if (HYPERLINK_HREF.getName().equals(getName())) { if (HYPERLINK_HREF.getName().equals(getName())) {
return HYPERLINK_HREF; return HYPERLINK_HREF;
@ -116,8 +119,11 @@ public class DrawTextParagraph implements Drawable {
autoNbrIdx = index; autoNbrIdx = index;
} }
@Override
public void draw(Graphics2D graphics){ public void draw(Graphics2D graphics){
if (lines.isEmpty()) return; if (lines.isEmpty()) {
return;
}
double penY = y; double penY = y;
@ -144,7 +150,9 @@ public class DrawTextParagraph implements Drawable {
//The vertical line spacing //The vertical line spacing
Double spacing = paragraph.getLineSpacing(); Double spacing = paragraph.getLineSpacing();
if (spacing == null) spacing = 100d; if (spacing == null) {
spacing = 100d;
}
for(DrawTextFragment line : lines){ for(DrawTextFragment line : lines){
double penX; double penX;
@ -176,7 +184,9 @@ public class DrawTextParagraph implements Drawable {
double rightInset = insets.right; double rightInset = insets.right;
TextAlign ta = paragraph.getTextAlign(); TextAlign ta = paragraph.getTextAlign();
if (ta == null) ta = TextAlign.LEFT; if (ta == null) {
ta = TextAlign.LEFT;
}
switch (ta) { switch (ta) {
case CENTER: case CENTER:
penX += (anchor.getWidth() - line.getWidth() - leftInset - rightInset - leftMargin) / 2; penX += (anchor.getWidth() - line.getWidth() - leftInset - rightInset - leftMargin) / 2;
@ -217,9 +227,11 @@ public class DrawTextParagraph implements Drawable {
return (lines.isEmpty() || rawText.trim().isEmpty()); return (lines.isEmpty() || rawText.trim().isEmpty());
} }
@Override
public void applyTransform(Graphics2D graphics) { public void applyTransform(Graphics2D graphics) {
} }
@Override
public void drawContent(Graphics2D graphics) { public void drawContent(Graphics2D graphics) {
} }
@ -243,10 +255,14 @@ public class DrawTextParagraph implements Drawable {
double wrappingWidth = getWrappingWidth(lines.size() == 0, graphics) + 1; // add a pixel to compensate rounding errors double wrappingWidth = getWrappingWidth(lines.size() == 0, graphics) + 1; // add a pixel to compensate rounding errors
// shape width can be smaller that the sum of insets (this was proved by a test file) // shape width can be smaller that the sum of insets (this was proved by a test file)
if(wrappingWidth < 0) wrappingWidth = 1; if(wrappingWidth < 0) {
wrappingWidth = 1;
}
int nextBreak = text.indexOf("\n", startIndex + 1); int nextBreak = text.indexOf("\n", startIndex + 1);
if (nextBreak == -1) nextBreak = it.getEndIndex(); if (nextBreak == -1) {
nextBreak = it.getEndIndex();
}
TextLayout layout = measurer.nextLayout((float)wrappingWidth, nextBreak, true); TextLayout layout = measurer.nextLayout((float)wrappingWidth, nextBreak, true);
if (layout == null) { if (layout == null) {
@ -279,7 +295,9 @@ public class DrawTextParagraph implements Drawable {
maxLineHeight = Math.max(maxLineHeight, line.getHeight()); maxLineHeight = Math.max(maxLineHeight, line.getHeight());
if(endIndex == it.getEndIndex()) break; if(endIndex == it.getEndIndex()) {
break;
}
} }
rawText = text.toString(); rawText = text.toString();
@ -287,7 +305,9 @@ public class DrawTextParagraph implements Drawable {
protected DrawTextFragment getBullet(Graphics2D graphics, AttributedCharacterIterator firstLineAttr) { protected DrawTextFragment getBullet(Graphics2D graphics, AttributedCharacterIterator firstLineAttr) {
BulletStyle bulletStyle = paragraph.getBulletStyle(); BulletStyle bulletStyle = paragraph.getBulletStyle();
if (bulletStyle == null) return null; if (bulletStyle == null) {
return null;
}
String buCharacter; String buCharacter;
AutoNumberingScheme ans = bulletStyle.getAutoNumberingScheme(); AutoNumberingScheme ans = bulletStyle.getAutoNumberingScheme();
@ -296,10 +316,14 @@ public class DrawTextParagraph implements Drawable {
} else { } else {
buCharacter = bulletStyle.getBulletCharacter(); buCharacter = bulletStyle.getBulletCharacter();
} }
if (buCharacter == null) return null; if (buCharacter == null) {
return null;
}
String buFont = bulletStyle.getBulletFont(); String buFont = bulletStyle.getBulletFont();
if (buFont == null) buFont = paragraph.getDefaultFontFamily(); if (buFont == null) {
buFont = paragraph.getDefaultFontFamily();
}
assert(buFont != null); assert(buFont != null);
PlaceableShape<?,?> ps = getParagraphShape(); PlaceableShape<?,?> ps = getParagraphShape();
@ -313,9 +337,14 @@ public class DrawTextParagraph implements Drawable {
float fontSize = (Float)firstLineAttr.getAttribute(TextAttribute.SIZE); float fontSize = (Float)firstLineAttr.getAttribute(TextAttribute.SIZE);
Double buSz = bulletStyle.getBulletFontSize(); Double buSz = bulletStyle.getBulletFontSize();
if (buSz == null) buSz = 100d; if (buSz == null) {
if (buSz > 0) fontSize *= buSz* 0.01; buSz = 100d;
else fontSize = (float)-buSz; }
if (buSz > 0) {
fontSize *= buSz* 0.01;
} else {
fontSize = (float)-buSz;
}
AttributedString str = new AttributedString(mapFontCharset(buCharacter,buFont)); AttributedString str = new AttributedString(mapFontCharset(buCharacter,buFont));
@ -328,7 +357,11 @@ public class DrawTextParagraph implements Drawable {
return fact.getTextFragment(layout, str); return fact.getTextFragment(layout, str);
} }
protected String getRenderableText(TextRun tr) { protected String getRenderableText(Graphics2D graphics, TextRun tr) {
if (tr.getFieldType() == FieldType.SLIDE_NUMBER) {
Slide<?,?> slide = (Slide<?,?>)graphics.getRenderingHint(Drawable.CURRENT_SLIDE);
return (slide == null) ? "" : Integer.toString(slide.getSlideNumber());
}
StringBuilder buf = new StringBuilder(); StringBuilder buf = new StringBuilder();
TextCap cap = tr.getTextCap(); TextCap cap = tr.getTextCap();
String tabs = null; String tabs = null;
@ -364,18 +397,24 @@ public class DrawTextParagraph implements Drawable {
private String tab2space(TextRun tr) { private String tab2space(TextRun tr) {
AttributedString string = new AttributedString(" "); AttributedString string = new AttributedString(" ");
String fontFamily = tr.getFontFamily(); String fontFamily = tr.getFontFamily();
if (fontFamily == null) fontFamily = "Lucida Sans"; if (fontFamily == null) {
fontFamily = "Lucida Sans";
}
string.addAttribute(TextAttribute.FAMILY, fontFamily); string.addAttribute(TextAttribute.FAMILY, fontFamily);
Double fs = tr.getFontSize(); Double fs = tr.getFontSize();
if (fs == null) fs = 12d; if (fs == null) {
fs = 12d;
}
string.addAttribute(TextAttribute.SIZE, fs.floatValue()); string.addAttribute(TextAttribute.SIZE, fs.floatValue());
TextLayout l = new TextLayout(string.getIterator(), new FontRenderContext(null, true, true)); TextLayout l = new TextLayout(string.getIterator(), new FontRenderContext(null, true, true));
double wspace = l.getAdvance(); double wspace = l.getAdvance();
Double tabSz = paragraph.getDefaultTabSize(); Double tabSz = paragraph.getDefaultTabSize();
if (tabSz == null) tabSz = wspace*4; if (tabSz == null) {
tabSz = wspace*4;
}
int numSpaces = (int)Math.ceil(tabSz / wspace); int numSpaces = (int)Math.ceil(tabSz / wspace);
StringBuilder buf = new StringBuilder(); StringBuilder buf = new StringBuilder();
@ -449,10 +488,13 @@ public class DrawTextParagraph implements Drawable {
} }
if (firstLine && !isHSLF()) { if (firstLine && !isHSLF()) {
if (bullet != null){ if (bullet != null){
if (indent > 0) width -= indent; if (indent > 0) {
width -= indent;
}
} else { } else {
if (indent > 0) width -= indent; // first line indentation if (indent > 0) {
else if (indent < 0) { // hanging indentation: the first line start at the left margin width -= indent; // first line indentation
} else if (indent < 0) { // hanging indentation: the first line start at the left margin
width += leftMargin; width += leftMargin;
} }
} }
@ -480,25 +522,36 @@ public class DrawTextParagraph implements Drawable {
@SuppressWarnings("rawtypes") @SuppressWarnings("rawtypes")
private PlaceableShape<?,?> getParagraphShape() { private PlaceableShape<?,?> getParagraphShape() {
return new PlaceableShape(){ return new PlaceableShape(){
@Override
public ShapeContainer<?,?> getParent() { return null; } public ShapeContainer<?,?> getParent() { return null; }
@Override
public Rectangle2D getAnchor() { return paragraph.getParentShape().getAnchor(); } public Rectangle2D getAnchor() { return paragraph.getParentShape().getAnchor(); }
@Override
public void setAnchor(Rectangle2D anchor) {} public void setAnchor(Rectangle2D anchor) {}
@Override
public double getRotation() { return 0; } public double getRotation() { return 0; }
@Override
public void setRotation(double theta) {} public void setRotation(double theta) {}
@Override
public void setFlipHorizontal(boolean flip) {} public void setFlipHorizontal(boolean flip) {}
@Override
public void setFlipVertical(boolean flip) {} public void setFlipVertical(boolean flip) {}
@Override
public boolean getFlipHorizontal() { return false; } public boolean getFlipHorizontal() { return false; }
@Override
public boolean getFlipVertical() { return false; } public boolean getFlipVertical() { return false; }
@Override
public Sheet<?,?> getSheet() { return paragraph.getParentShape().getSheet(); } public Sheet<?,?> getSheet() { return paragraph.getParentShape().getSheet(); }
}; };
} }
protected AttributedString getAttributedString(Graphics2D graphics, StringBuilder text){ protected AttributedString getAttributedString(Graphics2D graphics, StringBuilder text){
List<AttributedStringData> attList = new ArrayList<AttributedStringData>(); List<AttributedStringData> attList = new ArrayList<AttributedStringData>();
if (text == null) text = new StringBuilder(); if (text == null) {
text = new StringBuilder();
}
PlaceableShape<?,?> ps = getParagraphShape(); PlaceableShape<?,?> ps = getParagraphShape();
DrawFontManager fontHandler = (DrawFontManager)graphics.getRenderingHint(Drawable.FONT_HANDLER); DrawFontManager fontHandler = (DrawFontManager)graphics.getRenderingHint(Drawable.FONT_HANDLER);
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
Map<String,String> fontMap = (Map<String,String>)graphics.getRenderingHint(Drawable.FONT_MAP); Map<String,String> fontMap = (Map<String,String>)graphics.getRenderingHint(Drawable.FONT_MAP);
@ -506,9 +559,11 @@ public class DrawTextParagraph implements Drawable {
Map<String,String> fallbackMap = (Map<String,String>)graphics.getRenderingHint(Drawable.FONT_FALLBACK); Map<String,String> fallbackMap = (Map<String,String>)graphics.getRenderingHint(Drawable.FONT_FALLBACK);
for (TextRun run : paragraph){ for (TextRun run : paragraph){
String runText = getRenderableText(run); String runText = getRenderableText(graphics, run);
// skip empty runs // skip empty runs
if (runText.isEmpty()) continue; if (runText.isEmpty()) {
continue;
}
// user can pass an custom object to convert fonts // user can pass an custom object to convert fonts
String mappedFont = run.getFontFamily(); String mappedFont = run.getFontFamily();
@ -633,8 +688,11 @@ public class DrawTextParagraph implements Drawable {
return string; return string;
} }
/**
* @return {@code true} if the HSLF implementation is used
*/
protected boolean isHSLF() { protected boolean isHSLF() {
return paragraph.getClass().getName().contains("HSLF"); return DrawShape.isHSLF(paragraph.getParentShape());
} }
/** /**

View File

@ -138,6 +138,7 @@ public class DrawTextShape extends DrawSimpleShape {
double y0 = y; double y0 = y;
//noinspection RedundantCast //noinspection RedundantCast
@SuppressWarnings("cast")
Iterator<? extends TextParagraph<?,?,? extends TextRun>> paragraphs = Iterator<? extends TextParagraph<?,?,? extends TextRun>> paragraphs =
(Iterator<? extends TextParagraph<?,?,? extends TextRun>>) getShape().iterator(); (Iterator<? extends TextParagraph<?,?,? extends TextRun>>) getShape().iterator();

View File

@ -130,6 +130,12 @@ public interface Drawable {
DrawableHint GSAVE = new DrawableHint(10); DrawableHint GSAVE = new DrawableHint(10);
DrawableHint GRESTORE = new DrawableHint(11); DrawableHint GRESTORE = new DrawableHint(11);
/**
* The Common SL Draw API works sometimes cascading, but there are places
* where the current slide context need to be evaluated, e.g. when slide numbers
* are printed. In this situation we need to have a way to access the current slide
*/
DrawableHint CURRENT_SLIDE = new DrawableHint(12);
/** /**

View File

@ -114,12 +114,30 @@ public enum Placeholder {
this.ooxmlId = ooxmlId; this.ooxmlId = ooxmlId;
} }
public static Placeholder lookupNative(int nativeId) { public static Placeholder lookupNativeSlide(int nativeId) {
return lookupNative(nativeId, 0);
}
public static Placeholder lookupNativeSlideMaster(int nativeId) {
return lookupNative(nativeId, 1);
}
public static Placeholder lookupNativeNotes(int nativeId) {
return lookupNative(nativeId, 2);
}
public static Placeholder lookupNativeNotesMaster(int nativeId) {
return lookupNative(nativeId, 3);
}
private static Placeholder lookupNative(int nativeId, int type) {
for (Placeholder ph : values()) { for (Placeholder ph : values()) {
if (ph.nativeSlideId == nativeId || if (
ph.nativeSlideMasterId == nativeId || type == 0 && ph.nativeSlideId == nativeId ||
ph.nativeNotesId == nativeId || type == 1 && ph.nativeSlideMasterId == nativeId ||
ph.nativeNotesMasterId == nativeId type == 2 && ph.nativeNotesId == nativeId ||
type == 3 && ph.nativeNotesMasterId == nativeId
) { ) {
return ph; return ph;
} }

View File

@ -43,4 +43,14 @@ public interface Slide<
*/ */
String getTitle(); String getTitle();
/**
* In XSLF, slidenumber and date shapes aren't marked as placeholders
* whereas in HSLF they are activated via a HeadersFooter configuration.
* This method is used to generalize that handling.
*
* @param placeholder
* @return {@code true} if the placeholder should be displayed/rendered
* @since POI 3.16-beta2
*/
boolean getDisplayPlaceholder(Placeholder placeholder);
} }

View File

@ -20,6 +20,7 @@ package org.apache.poi.sl.usermodel;
import java.awt.Color; import java.awt.Color;
import org.apache.poi.sl.usermodel.PaintStyle.SolidPaint; import org.apache.poi.sl.usermodel.PaintStyle.SolidPaint;
import org.apache.poi.util.Internal;
/** /**
* Some text. * Some text.
@ -30,6 +31,10 @@ public interface TextRun {
SMALL, SMALL,
ALL ALL
} }
enum FieldType {
SLIDE_NUMBER, DATE_TIME
}
String getRawText(); String getRawText();
void setText(String text); void setText(String text);
@ -176,4 +181,12 @@ public interface TextRun {
* @since POI 3.14-Beta2 * @since POI 3.14-Beta2
*/ */
Hyperlink<?,?> createHyperlink(); Hyperlink<?,?> createHyperlink();
/**
* Experimental method to determine the field type, e.g. slide number
*
* @return the field type or {@code null} if text run is not a field
*/
@Internal
FieldType getFieldType();
} }

View File

@ -19,20 +19,11 @@
package org.apache.poi.xslf.usermodel; package org.apache.poi.xslf.usermodel;
import org.openxmlformats.schemas.drawingml.x2006.main.CTRegularTextRun; import org.openxmlformats.schemas.drawingml.x2006.main.CTTextLineBreak;
import org.openxmlformats.schemas.drawingml.x2006.main.CTTextCharacterProperties;
class XSLFLineBreak extends XSLFTextRun { class XSLFLineBreak extends XSLFTextRun {
private final CTTextCharacterProperties _brProps; protected XSLFLineBreak(CTTextLineBreak r, XSLFTextParagraph p) {
XSLFLineBreak(CTRegularTextRun r, XSLFTextParagraph p, CTTextCharacterProperties brProps){
super(r, p); super(r, p);
_brProps = brProps;
}
@Override
protected CTTextCharacterProperties getRPr(boolean create){
return _brProps;
} }
public void setText(String text){ public void setText(String text){

View File

@ -1341,106 +1341,138 @@ import org.openxmlformats.schemas.presentationml.x2006.main.CTBackgroundProperti
this.props = props; this.props = props;
} }
@Override
public CTNoFillProperties getNoFill() { public CTNoFillProperties getNoFill() {
return isSetNoFill() ? (CTNoFillProperties)props : null; return isSetNoFill() ? (CTNoFillProperties)props : null;
} }
@Override
public boolean isSetNoFill() { public boolean isSetNoFill() {
return (props instanceof CTNoFillProperties); return (props instanceof CTNoFillProperties);
} }
@Override
public void setNoFill(CTNoFillProperties noFill) {} public void setNoFill(CTNoFillProperties noFill) {}
@Override
public CTNoFillProperties addNewNoFill() { public CTNoFillProperties addNewNoFill() {
return null; return null;
} }
@Override
public void unsetNoFill() {} public void unsetNoFill() {}
@Override
public CTSolidColorFillProperties getSolidFill() { public CTSolidColorFillProperties getSolidFill() {
return isSetSolidFill() ? (CTSolidColorFillProperties)props : null; return isSetSolidFill() ? (CTSolidColorFillProperties)props : null;
} }
@Override
public boolean isSetSolidFill() { public boolean isSetSolidFill() {
return (props instanceof CTSolidColorFillProperties); return (props instanceof CTSolidColorFillProperties);
} }
@Override
public void setSolidFill(CTSolidColorFillProperties solidFill) {} public void setSolidFill(CTSolidColorFillProperties solidFill) {}
@Override
public CTSolidColorFillProperties addNewSolidFill() { public CTSolidColorFillProperties addNewSolidFill() {
return null; return null;
} }
@Override
public void unsetSolidFill() {} public void unsetSolidFill() {}
@Override
public CTGradientFillProperties getGradFill() { public CTGradientFillProperties getGradFill() {
return isSetGradFill() ? (CTGradientFillProperties)props : null; return isSetGradFill() ? (CTGradientFillProperties)props : null;
} }
@Override
public boolean isSetGradFill() { public boolean isSetGradFill() {
return (props instanceof CTGradientFillProperties); return (props instanceof CTGradientFillProperties);
} }
@Override
public void setGradFill(CTGradientFillProperties gradFill) {} public void setGradFill(CTGradientFillProperties gradFill) {}
@Override
public CTGradientFillProperties addNewGradFill() { public CTGradientFillProperties addNewGradFill() {
return null; return null;
} }
@Override
public void unsetGradFill() {} public void unsetGradFill() {}
@Override
public CTBlipFillProperties getBlipFill() { public CTBlipFillProperties getBlipFill() {
return isSetBlipFill() ? (CTBlipFillProperties)props : null; return isSetBlipFill() ? (CTBlipFillProperties)props : null;
} }
@Override
public boolean isSetBlipFill() { public boolean isSetBlipFill() {
return (props instanceof CTBlipFillProperties); return (props instanceof CTBlipFillProperties);
} }
@Override
public void setBlipFill(CTBlipFillProperties blipFill) {} public void setBlipFill(CTBlipFillProperties blipFill) {}
@Override
public CTBlipFillProperties addNewBlipFill() { public CTBlipFillProperties addNewBlipFill() {
return null; return null;
} }
@Override
public void unsetBlipFill() {} public void unsetBlipFill() {}
@Override
public CTPatternFillProperties getPattFill() { public CTPatternFillProperties getPattFill() {
return isSetPattFill() ? (CTPatternFillProperties)props : null; return isSetPattFill() ? (CTPatternFillProperties)props : null;
} }
@Override
public boolean isSetPattFill() { public boolean isSetPattFill() {
return (props instanceof CTPatternFillProperties); return (props instanceof CTPatternFillProperties);
} }
@Override
public void setPattFill(CTPatternFillProperties pattFill) {} public void setPattFill(CTPatternFillProperties pattFill) {}
@Override
public CTPatternFillProperties addNewPattFill() { public CTPatternFillProperties addNewPattFill() {
return null; return null;
} }
@Override
public void unsetPattFill() {} public void unsetPattFill() {}
@Override
public CTGroupFillProperties getGrpFill() { public CTGroupFillProperties getGrpFill() {
return isSetGrpFill() ? (CTGroupFillProperties)props : null; return isSetGrpFill() ? (CTGroupFillProperties)props : null;
} }
@Override
public boolean isSetGrpFill() { public boolean isSetGrpFill() {
return (props instanceof CTGroupFillProperties); return (props instanceof CTGroupFillProperties);
} }
@Override
public void setGrpFill(CTGroupFillProperties grpFill) {} public void setGrpFill(CTGroupFillProperties grpFill) {}
@Override
public CTGroupFillProperties addNewGrpFill() { public CTGroupFillProperties addNewGrpFill() {
return null; return null;
} }
@Override
public void unsetGrpFill() {} public void unsetGrpFill() {}
@Override
public boolean isSetMatrixStyle() { public boolean isSetMatrixStyle() {
return false; return false;
} }
@Override
public CTStyleMatrixReference getMatrixStyle() { public CTStyleMatrixReference getMatrixStyle() {
return null; return null;
} }

View File

@ -32,6 +32,7 @@ import org.apache.poi.openxml4j.opc.PackageRelationship;
import org.apache.poi.sl.draw.DrawFactory; import org.apache.poi.sl.draw.DrawFactory;
import org.apache.poi.sl.draw.DrawPaint; import org.apache.poi.sl.draw.DrawPaint;
import org.apache.poi.sl.usermodel.ColorStyle; import org.apache.poi.sl.usermodel.ColorStyle;
import org.apache.poi.sl.usermodel.MasterSheet;
import org.apache.poi.sl.usermodel.PaintStyle; import org.apache.poi.sl.usermodel.PaintStyle;
import org.apache.poi.sl.usermodel.PaintStyle.GradientPaint; import org.apache.poi.sl.usermodel.PaintStyle.GradientPaint;
import org.apache.poi.sl.usermodel.PaintStyle.TexturePaint; import org.apache.poi.sl.usermodel.PaintStyle.TexturePaint;
@ -57,6 +58,7 @@ import org.openxmlformats.schemas.drawingml.x2006.main.CTSolidColorFillPropertie
import org.openxmlformats.schemas.drawingml.x2006.main.CTStyleMatrix; import org.openxmlformats.schemas.drawingml.x2006.main.CTStyleMatrix;
import org.openxmlformats.schemas.drawingml.x2006.main.CTStyleMatrixReference; import org.openxmlformats.schemas.drawingml.x2006.main.CTStyleMatrixReference;
import org.openxmlformats.schemas.drawingml.x2006.main.STPathShadeType; import org.openxmlformats.schemas.drawingml.x2006.main.STPathShadeType;
import org.openxmlformats.schemas.drawingml.x2006.main.STSchemeColorVal;
import org.openxmlformats.schemas.presentationml.x2006.main.CTApplicationNonVisualDrawingProps; import org.openxmlformats.schemas.presentationml.x2006.main.CTApplicationNonVisualDrawingProps;
import org.openxmlformats.schemas.presentationml.x2006.main.CTBackgroundProperties; import org.openxmlformats.schemas.presentationml.x2006.main.CTBackgroundProperties;
import org.openxmlformats.schemas.presentationml.x2006.main.CTPlaceholder; import org.openxmlformats.schemas.presentationml.x2006.main.CTPlaceholder;
@ -150,6 +152,7 @@ public abstract class XSLFShape implements Shape<XSLFShape,XSLFTextParagraph> {
protected PaintStyle getFillPaint() { protected PaintStyle getFillPaint() {
final XSLFTheme theme = getSheet().getTheme(); final XSLFTheme theme = getSheet().getTheme();
final boolean hasPlaceholder = getPlaceholder() != null;
PropertyFetcher<PaintStyle> fetcher = new PropertyFetcher<PaintStyle>() { PropertyFetcher<PaintStyle> fetcher = new PropertyFetcher<PaintStyle>() {
public boolean fetch(XSLFShape shape) { public boolean fetch(XSLFShape shape) {
XSLFFillProperties fp = XSLFPropertiesDelegate.getFillDelegate(shape.getShapeProperties()); XSLFFillProperties fp = XSLFPropertiesDelegate.getFillDelegate(shape.getShapeProperties());
@ -163,7 +166,7 @@ public abstract class XSLFShape implements Shape<XSLFShape,XSLFTextParagraph> {
} }
PackagePart pp = shape.getSheet().getPackagePart(); PackagePart pp = shape.getSheet().getPackagePart();
PaintStyle paint = selectPaint(fp, null, pp, theme); PaintStyle paint = selectPaint(fp, null, pp, theme, hasPlaceholder);
if (paint != null) { if (paint != null) {
setValue(paint); setValue(paint);
return true; return true;
@ -172,7 +175,7 @@ public abstract class XSLFShape implements Shape<XSLFShape,XSLFTextParagraph> {
CTShapeStyle style = shape.getSpStyle(); CTShapeStyle style = shape.getSpStyle();
if (style != null) { if (style != null) {
fp = XSLFPropertiesDelegate.getFillDelegate(style.getFillRef()); fp = XSLFPropertiesDelegate.getFillDelegate(style.getFillRef());
paint = selectPaint(fp, null, pp, theme); paint = selectPaint(fp, null, pp, theme, hasPlaceholder);
} }
if (paint != null) { if (paint != null) {
setValue(paint); setValue(paint);
@ -230,6 +233,9 @@ public abstract class XSLFShape implements Shape<XSLFShape,XSLFTextParagraph> {
if (cur.toChild(namespace, nodename)) { if (cur.toChild(namespace, nodename)) {
child = (T)cur.getObject(); child = (T)cur.getObject();
} }
if (cur.toChild("http://schemas.openxmlformats.org/drawingml/2006/main", nodename)) {
child = (T)cur.getObject();
}
cur.dispose(); cur.dispose();
return child; return child;
} }
@ -290,61 +296,71 @@ public abstract class XSLFShape implements Shape<XSLFShape,XSLFTextParagraph> {
} }
/** /**
* Walk up the inheritance tree and fetch shape properties. * Walk up the inheritance tree and fetch shape properties.<p>
* *
* The following order of inheritance is assumed: * The following order of inheritance is assumed:<p>
* <p> * <ol>
* slide <-- slideLayout <-- slideMaster * <li>slide
* </p> * <li>slideLayout
* <li>slideMaster
* </ol>
*
* Currently themes and their defaults aren't correctly handled
* *
* @param visitor the object that collects the desired property * @param visitor the object that collects the desired property
* @return true if the property was fetched * @return true if the property was fetched
*/ */
protected boolean fetchShapeProperty(PropertyFetcher<?> visitor) { protected boolean fetchShapeProperty(PropertyFetcher<?> visitor) {
boolean ok = visitor.fetch(this); // try shape properties in slide
if (visitor.fetch(this)) {
return true;
}
XSLFSimpleShape masterShape;
XSLFSheet masterSheet = (XSLFSheet)getSheet().getMasterSheet();
CTPlaceholder ph = getCTPlaceholder(); CTPlaceholder ph = getCTPlaceholder();
if (ph == null) {
if (masterSheet != null && ph != null) { return false;
if (!ok) { }
masterShape = masterSheet.getPlaceholder(ph); MasterSheet<XSLFShape,XSLFTextParagraph> sm = getSheet().getMasterSheet();
if (masterShape != null) {
ok = visitor.fetch(masterShape); // try slide layout
} if (sm instanceof XSLFSlideLayout) {
XSLFSlideLayout slideLayout = (XSLFSlideLayout)sm;
XSLFSimpleShape placeholderShape = slideLayout.getPlaceholder(ph);
if (placeholderShape != null && visitor.fetch(placeholderShape)) {
return true;
} }
sm = slideLayout.getMasterSheet();
// try slide master }
if (!ok ) {
int textType; // try slide master
if ( !ph.isSetType()) textType = STPlaceholderType.INT_BODY; if (sm instanceof XSLFSlideMaster) {
else { XSLFSlideMaster master = (XSLFSlideMaster)sm;
switch (ph.getType().intValue()) { int textType = getPlaceholderType(ph);
case STPlaceholderType.INT_TITLE: XSLFSimpleShape masterShape = master.getPlaceholderByType(textType);
case STPlaceholderType.INT_CTR_TITLE: if (masterShape != null && visitor.fetch(masterShape)) {
textType = STPlaceholderType.INT_TITLE; return true;
break;
case STPlaceholderType.INT_FTR:
case STPlaceholderType.INT_SLD_NUM:
case STPlaceholderType.INT_DT:
textType = ph.getType().intValue();
break;
default:
textType = STPlaceholderType.INT_BODY;
break;
}
}
XSLFSheet master = (XSLFSheet)masterSheet.getMasterSheet();
if (master != null) {
masterShape = master.getPlaceholderByType(textType);
if (masterShape != null) {
ok = visitor.fetch(masterShape);
}
}
} }
} }
return ok;
return false;
}
private static int getPlaceholderType(CTPlaceholder ph) {
if ( !ph.isSetType()) {
return STPlaceholderType.INT_BODY;
}
switch (ph.getType().intValue()) {
case STPlaceholderType.INT_TITLE:
case STPlaceholderType.INT_CTR_TITLE:
return STPlaceholderType.INT_TITLE;
case STPlaceholderType.INT_FTR:
case STPlaceholderType.INT_SLD_NUM:
case STPlaceholderType.INT_DT:
return ph.getType().intValue();
default:
return STPlaceholderType.INT_BODY;
}
} }
/** /**
@ -358,7 +374,7 @@ public abstract class XSLFShape implements Shape<XSLFShape,XSLFTextParagraph> {
* *
* @return the applied Paint or null if none was applied * @return the applied Paint or null if none was applied
*/ */
protected static PaintStyle selectPaint(XSLFFillProperties fp, final CTSchemeColor phClr, final PackagePart parentPart, final XSLFTheme theme) { protected static PaintStyle selectPaint(XSLFFillProperties fp, final CTSchemeColor phClr, final PackagePart parentPart, final XSLFTheme theme, boolean hasPlaceholder) {
if (fp == null || fp.isSetNoFill()) { if (fp == null || fp.isSetNoFill()) {
return null; return null;
} else if (fp.isSetSolidFill()) { } else if (fp.isSetSolidFill()) {
@ -368,15 +384,23 @@ public abstract class XSLFShape implements Shape<XSLFShape,XSLFTextParagraph> {
} else if (fp.isSetGradFill()) { } else if (fp.isSetGradFill()) {
return selectPaint(fp.getGradFill(), phClr, theme); return selectPaint(fp.getGradFill(), phClr, theme);
} else if (fp.isSetMatrixStyle()) { } else if (fp.isSetMatrixStyle()) {
return selectPaint(fp.getMatrixStyle(), theme, fp.isLineStyle()); return selectPaint(fp.getMatrixStyle(), theme, fp.isLineStyle(), hasPlaceholder);
} else { } else {
return null; return null;
} }
} }
protected static PaintStyle selectPaint(CTSolidColorFillProperties solidFill, CTSchemeColor phClr, final XSLFTheme theme) { protected static PaintStyle selectPaint(CTSolidColorFillProperties solidFill, CTSchemeColor phClr, final XSLFTheme theme) {
if (phClr == null && solidFill.isSetSchemeClr()) { if (solidFill.isSetSchemeClr()) {
phClr = solidFill.getSchemeClr(); // if there's a reference to the placeholder color,
// stop evaluating further and let the caller select
// the next style inheritance level
if (STSchemeColorVal.PH_CLR.equals(solidFill.getSchemeClr().getVal())) {
return null;
}
if (phClr == null) {
phClr = solidFill.getSchemeClr();
}
} }
final XSLFColor c = new XSLFColor(solidFill, theme, phClr); final XSLFColor c = new XSLFColor(solidFill, theme, phClr);
return DrawPaint.createSolidPaint(c.getColorStyle()); return DrawPaint.createSolidPaint(c.getColorStyle());
@ -483,7 +507,7 @@ public abstract class XSLFShape implements Shape<XSLFShape,XSLFTextParagraph> {
}; };
} }
protected static PaintStyle selectPaint(CTStyleMatrixReference fillRef, final XSLFTheme theme, boolean isLineStyle) { protected static PaintStyle selectPaint(CTStyleMatrixReference fillRef, final XSLFTheme theme, boolean isLineStyle, boolean hasPlaceholder) {
if (fillRef == null) return null; if (fillRef == null) return null;
// The idx attribute refers to the index of a fill style or // The idx attribute refers to the index of a fill style or
@ -492,7 +516,6 @@ public abstract class XSLFShape implements Shape<XSLFShape,XSLFTextParagraph> {
// values 1-999 refer to the index of a fill style within the fillStyleLst element // values 1-999 refer to the index of a fill style within the fillStyleLst element
// values 1001 and above refer to the index of a background fill style within the bgFillStyleLst element. // values 1001 and above refer to the index of a background fill style within the bgFillStyleLst element.
int idx = (int)fillRef.getIdx(); int idx = (int)fillRef.getIdx();
CTSchemeColor phClr = fillRef.getSchemeClr();
CTStyleMatrix matrix = theme.getXmlObject().getThemeElements().getFmtScheme(); CTStyleMatrix matrix = theme.getXmlObject().getThemeElements().getFmtScheme();
final XmlObject styleLst; final XmlObject styleLst;
int childIdx; int childIdx;
@ -511,8 +534,16 @@ public abstract class XSLFShape implements Shape<XSLFShape,XSLFTextParagraph> {
fp = XSLFPropertiesDelegate.getFillDelegate(cur.getObject()); fp = XSLFPropertiesDelegate.getFillDelegate(cur.getObject());
} }
cur.dispose(); cur.dispose();
return selectPaint(fp, phClr, theme.getPackagePart(), theme); CTSchemeColor phClr = fillRef.getSchemeClr();
PaintStyle res = selectPaint(fp, phClr, theme.getPackagePart(), theme, hasPlaceholder);
// check for empty placeholder value
// see http://officeopenxml.com/prSlide-color.php - "Color Placeholders within Themes"
if (res != null || hasPlaceholder) {
return res;
}
XSLFColor col = new XSLFColor(fillRef, theme, phClr);
return DrawPaint.createSolidPaint(col.getColorStyle());
} }
@Override @Override

View File

@ -121,6 +121,7 @@ public abstract class XSLFSimpleShape extends XSLFShape
protected CTTransform2D getXfrm(boolean create) { protected CTTransform2D getXfrm(boolean create) {
PropertyFetcher<CTTransform2D> fetcher = new PropertyFetcher<CTTransform2D>() { PropertyFetcher<CTTransform2D> fetcher = new PropertyFetcher<CTTransform2D>() {
@Override
public boolean fetch(XSLFShape shape) { public boolean fetch(XSLFShape shape) {
XmlObject xo = shape.getShapeProperties(); XmlObject xo = shape.getShapeProperties();
if (xo instanceof CTShapeProperties && ((CTShapeProperties)xo).isSetXfrm()) { if (xo instanceof CTShapeProperties && ((CTShapeProperties)xo).isSetXfrm()) {
@ -234,20 +235,32 @@ public abstract class XSLFSimpleShape extends XSLFShape
*/ */
CTLineProperties getDefaultLineProperties() { CTLineProperties getDefaultLineProperties() {
CTShapeStyle style = getSpStyle(); CTShapeStyle style = getSpStyle();
if (style == null) return null; if (style == null) {
return null;
}
CTStyleMatrixReference lnRef = style.getLnRef(); CTStyleMatrixReference lnRef = style.getLnRef();
if (lnRef == null) return null; if (lnRef == null) {
return null;
}
// 1-based index of a line style within the style matrix // 1-based index of a line style within the style matrix
int idx = (int)lnRef.getIdx(); int idx = (int)lnRef.getIdx();
XSLFTheme theme = getSheet().getTheme(); XSLFTheme theme = getSheet().getTheme();
if (theme == null) return null; if (theme == null) {
return null;
}
CTBaseStyles styles = theme.getXmlObject().getThemeElements(); CTBaseStyles styles = theme.getXmlObject().getThemeElements();
if (styles == null) return null; if (styles == null) {
return null;
}
CTStyleMatrix styleMatrix = styles.getFmtScheme(); CTStyleMatrix styleMatrix = styles.getFmtScheme();
if (styleMatrix == null) return null; if (styleMatrix == null) {
return null;
}
CTLineStyleList lineStyles = styleMatrix.getLnStyleLst(); CTLineStyleList lineStyles = styleMatrix.getLnStyleLst();
if (lineStyles == null || lineStyles.sizeOfLnArray() < idx) return null; if (lineStyles == null || lineStyles.sizeOfLnArray() < idx) {
return null;
}
return lineStyles.getLnArray(idx - 1); return lineStyles.getLnArray(idx - 1);
} }
@ -301,12 +314,14 @@ public abstract class XSLFSimpleShape extends XSLFShape
protected PaintStyle getLinePaint() { protected PaintStyle getLinePaint() {
XSLFSheet sheet = getSheet(); XSLFSheet sheet = getSheet();
final XSLFTheme theme = sheet.getTheme(); final XSLFTheme theme = sheet.getTheme();
final boolean hasPlaceholder = getPlaceholder() != null;
PropertyFetcher<PaintStyle> fetcher = new PropertyFetcher<PaintStyle>() { PropertyFetcher<PaintStyle> fetcher = new PropertyFetcher<PaintStyle>() {
@Override
public boolean fetch(XSLFShape shape) { public boolean fetch(XSLFShape shape) {
CTLineProperties spPr = getLn(shape, false); CTLineProperties spPr = getLn(shape, false);
XSLFFillProperties fp = XSLFPropertiesDelegate.getFillDelegate(spPr); XSLFFillProperties fp = XSLFPropertiesDelegate.getFillDelegate(spPr);
PackagePart pp = shape.getSheet().getPackagePart(); PackagePart pp = shape.getSheet().getPackagePart();
PaintStyle paint = selectPaint(fp, null, pp, theme); PaintStyle paint = selectPaint(fp, null, pp, theme, hasPlaceholder);
if (paint != null) { if (paint != null) {
setValue(paint); setValue(paint);
return true; return true;
@ -315,7 +330,7 @@ public abstract class XSLFSimpleShape extends XSLFShape
CTShapeStyle style = shape.getSpStyle(); CTShapeStyle style = shape.getSpStyle();
if (style != null) { if (style != null) {
fp = XSLFPropertiesDelegate.getFillDelegate(style.getLnRef()); fp = XSLFPropertiesDelegate.getFillDelegate(style.getLnRef());
paint = selectPaint(fp, null, pp, theme); paint = selectPaint(fp, null, pp, theme, hasPlaceholder);
} }
if (paint != null) { if (paint != null) {
setValue(paint); setValue(paint);
@ -327,11 +342,15 @@ public abstract class XSLFSimpleShape extends XSLFShape
fetchShapeProperty(fetcher); fetchShapeProperty(fetcher);
PaintStyle paint = fetcher.getValue(); PaintStyle paint = fetcher.getValue();
if (paint != null) return paint; if (paint != null) {
return paint;
}
// line color was not found, check if it is defined in the theme // line color was not found, check if it is defined in the theme
CTShapeStyle style = getSpStyle(); CTShapeStyle style = getSpStyle();
if (style == null) return null; if (style == null) {
return null;
}
// get a reference to a line style within the style matrix. // get a reference to a line style within the style matrix.
CTStyleMatrixReference lnRef = style.getLnRef(); CTStyleMatrixReference lnRef = style.getLnRef();
@ -341,7 +360,7 @@ public abstract class XSLFSimpleShape extends XSLFShape
CTLineProperties props = theme.getXmlObject().getThemeElements().getFmtScheme().getLnStyleLst().getLnArray(idx - 1); CTLineProperties props = theme.getXmlObject().getThemeElements().getFmtScheme().getLnStyleLst().getLnArray(idx - 1);
XSLFFillProperties fp = XSLFPropertiesDelegate.getFillDelegate(props); XSLFFillProperties fp = XSLFPropertiesDelegate.getFillDelegate(props);
PackagePart pp = sheet.getPackagePart(); PackagePart pp = sheet.getPackagePart();
paint = selectPaint(fp, phClr, pp, theme); paint = selectPaint(fp, phClr, pp, theme, hasPlaceholder);
} }
return paint; return paint;
@ -387,6 +406,7 @@ public abstract class XSLFSimpleShape extends XSLFShape
*/ */
public double getLineWidth() { public double getLineWidth() {
PropertyFetcher<Double> fetcher = new PropertyFetcher<Double>() { PropertyFetcher<Double> fetcher = new PropertyFetcher<Double>() {
@Override
public boolean fetch(XSLFShape shape) { public boolean fetch(XSLFShape shape) {
CTLineProperties ln = getLn(shape, false); CTLineProperties ln = getLn(shape, false);
if (ln != null) { if (ln != null) {
@ -409,7 +429,9 @@ public abstract class XSLFSimpleShape extends XSLFShape
if (fetcher.getValue() == null) { if (fetcher.getValue() == null) {
CTLineProperties defaultLn = getDefaultLineProperties(); CTLineProperties defaultLn = getDefaultLineProperties();
if (defaultLn != null) { if (defaultLn != null) {
if (defaultLn.isSetW()) lineWidth = Units.toPoints(defaultLn.getW()); if (defaultLn.isSetW()) {
lineWidth = Units.toPoints(defaultLn.getW());
}
} }
} else { } else {
lineWidth = fetcher.getValue(); lineWidth = fetcher.getValue();
@ -460,6 +482,7 @@ public abstract class XSLFSimpleShape extends XSLFShape
*/ */
public LineCompound getLineCompound() { public LineCompound getLineCompound() {
PropertyFetcher<Integer> fetcher = new PropertyFetcher<Integer>() { PropertyFetcher<Integer> fetcher = new PropertyFetcher<Integer>() {
@Override
public boolean fetch(XSLFShape shape) { public boolean fetch(XSLFShape shape) {
CTLineProperties ln = getLn(shape, false); CTLineProperties ln = getLn(shape, false);
if (ln != null) { if (ln != null) {
@ -522,6 +545,7 @@ public abstract class XSLFSimpleShape extends XSLFShape
public LineDash getLineDash() { public LineDash getLineDash() {
PropertyFetcher<LineDash> fetcher = new PropertyFetcher<LineDash>() { PropertyFetcher<LineDash> fetcher = new PropertyFetcher<LineDash>() {
@Override
public boolean fetch(XSLFShape shape) { public boolean fetch(XSLFShape shape) {
CTLineProperties ln = getLn(shape, false); CTLineProperties ln = getLn(shape, false);
if (ln == null || !ln.isSetPrstDash()) { if (ln == null || !ln.isSetPrstDash()) {
@ -569,6 +593,7 @@ public abstract class XSLFSimpleShape extends XSLFShape
*/ */
public LineCap getLineCap() { public LineCap getLineCap() {
PropertyFetcher<LineCap> fetcher = new PropertyFetcher<LineCap>() { PropertyFetcher<LineCap> fetcher = new PropertyFetcher<LineCap>() {
@Override
public boolean fetch(XSLFShape shape) { public boolean fetch(XSLFShape shape) {
CTLineProperties ln = getLn(shape, false); CTLineProperties ln = getLn(shape, false);
if (ln != null && ln.isSetCap()) { if (ln != null && ln.isSetCap()) {
@ -640,8 +665,10 @@ public abstract class XSLFSimpleShape extends XSLFShape
/** /**
* @return shadow of this shape or null if shadow is disabled * @return shadow of this shape or null if shadow is disabled
*/ */
@Override
public XSLFShadow getShadow() { public XSLFShadow getShadow() {
PropertyFetcher<CTOuterShadowEffect> fetcher = new PropertyFetcher<CTOuterShadowEffect>() { PropertyFetcher<CTOuterShadowEffect> fetcher = new PropertyFetcher<CTOuterShadowEffect>() {
@Override
public boolean fetch(XSLFShape shape) { public boolean fetch(XSLFShape shape) {
XSLFEffectProperties ep = XSLFPropertiesDelegate.getEffectDelegate(shape.getShapeProperties()); XSLFEffectProperties ep = XSLFPropertiesDelegate.getEffectDelegate(shape.getShapeProperties());
if (ep != null && ep.isSetEffectLst()) { if (ep != null && ep.isSetEffectLst()) {
@ -675,6 +702,7 @@ public abstract class XSLFSimpleShape extends XSLFShape
* *
* @return definition of the shape geometry * @return definition of the shape geometry
*/ */
@Override
public CustomGeometry getGeometry() { public CustomGeometry getGeometry() {
XSLFGeometryProperties gp = XSLFPropertiesDelegate.getGeometryDelegate(getShapeProperties()); XSLFGeometryProperties gp = XSLFPropertiesDelegate.getGeometryDelegate(getShapeProperties());
@ -949,6 +977,7 @@ public abstract class XSLFSimpleShape extends XSLFShape
return ph != null; return ph != null;
} }
@Override
public Guide getAdjustValue(String name) { public Guide getAdjustValue(String name) {
XSLFGeometryProperties gp = XSLFPropertiesDelegate.getGeometryDelegate(getShapeProperties()); XSLFGeometryProperties gp = XSLFPropertiesDelegate.getGeometryDelegate(getShapeProperties());
@ -963,28 +992,35 @@ public abstract class XSLFSimpleShape extends XSLFShape
return null; return null;
} }
@Override
public LineDecoration getLineDecoration() { public LineDecoration getLineDecoration() {
return new LineDecoration() { return new LineDecoration() {
@Override
public DecorationShape getHeadShape() { public DecorationShape getHeadShape() {
return getLineHeadDecoration(); return getLineHeadDecoration();
} }
@Override
public DecorationSize getHeadWidth() { public DecorationSize getHeadWidth() {
return getLineHeadWidth(); return getLineHeadWidth();
} }
@Override
public DecorationSize getHeadLength() { public DecorationSize getHeadLength() {
return getLineHeadLength(); return getLineHeadLength();
} }
@Override
public DecorationShape getTailShape() { public DecorationShape getTailShape() {
return getLineTailDecoration(); return getLineTailDecoration();
} }
@Override
public DecorationSize getTailWidth() { public DecorationSize getTailWidth() {
return getLineTailWidth(); return getLineTailWidth();
} }
@Override
public DecorationSize getTailLength() { public DecorationSize getTailLength() {
return getLineTailLength(); return getLineTailLength();
} }
@ -996,32 +1032,40 @@ public abstract class XSLFSimpleShape extends XSLFShape
* *
* @return either Color or GradientPaint or TexturePaint or null * @return either Color or GradientPaint or TexturePaint or null
*/ */
@Override
public FillStyle getFillStyle() { public FillStyle getFillStyle() {
return new FillStyle() { return new FillStyle() {
@Override
public PaintStyle getPaint() { public PaintStyle getPaint() {
return XSLFSimpleShape.this.getFillPaint(); return XSLFSimpleShape.this.getFillPaint();
} }
}; };
} }
@Override
public StrokeStyle getStrokeStyle() { public StrokeStyle getStrokeStyle() {
return new StrokeStyle() { return new StrokeStyle() {
@Override
public PaintStyle getPaint() { public PaintStyle getPaint() {
return XSLFSimpleShape.this.getLinePaint(); return XSLFSimpleShape.this.getLinePaint();
} }
@Override
public LineCap getLineCap() { public LineCap getLineCap() {
return XSLFSimpleShape.this.getLineCap(); return XSLFSimpleShape.this.getLineCap();
} }
@Override
public LineDash getLineDash() { public LineDash getLineDash() {
return XSLFSimpleShape.this.getLineDash(); return XSLFSimpleShape.this.getLineDash();
} }
@Override
public double getLineWidth() { public double getLineWidth() {
return XSLFSimpleShape.this.getLineWidth(); return XSLFSimpleShape.this.getLineWidth();
} }
@Override
public LineCompound getLineCompound() { public LineCompound getLineCompound() {
return XSLFSimpleShape.this.getLineCompound(); return XSLFSimpleShape.this.getLineCompound();
} }

View File

@ -207,7 +207,7 @@ implements Slide<XSLFShape,XSLFTextParagraph> {
@Override @Override
public boolean getFollowMasterGraphics(){ public boolean getFollowMasterGraphics(){
return _slide.isSetShowMasterSp() && _slide.getShowMasterSp(); return _slide.getShowMasterSp();
} }
/** /**
@ -306,4 +306,9 @@ implements Slide<XSLFShape,XSLFTextParagraph> {
Drawable draw = drawFact.getDrawable(this); Drawable draw = drawFact.getDrawable(this);
draw.draw(graphics); draw.draw(graphics);
} }
@Override
public boolean getDisplayPlaceholder(Placeholder placeholder) {
return false;
}
} }

View File

@ -104,7 +104,7 @@ implements MasterSheet<XSLFShape,XSLFTextParagraph> {
@Override @Override
public boolean getFollowMasterGraphics() { public boolean getFollowMasterGraphics() {
return _layout.isSetShowMasterSp() && _layout.getShowMasterSp(); return _layout.getShowMasterSp();
} }
/** /**

View File

@ -145,7 +145,9 @@ public class XSLFTableCell extends XSLFTextShape implements TableCell<XSLFShape,
} }
CTTableCellProperties pr = getCellProperties(create); CTTableCellProperties pr = getCellProperties(create);
if (pr == null) return null; if (pr == null) {
return null;
}
switch (edge) { switch (edge) {
case bottom: case bottom:
@ -164,7 +166,9 @@ public class XSLFTableCell extends XSLFTextShape implements TableCell<XSLFShape,
@Override @Override
public void removeBorder(BorderEdge edge) { public void removeBorder(BorderEdge edge) {
CTTableCellProperties pr = getCellProperties(false); CTTableCellProperties pr = getCellProperties(false);
if (pr == null) return; if (pr == null) {
return;
}
switch (edge) { switch (edge) {
case bottom: case bottom:
if (pr.isSetLnB()) { if (pr.isSetLnB()) {
@ -195,22 +199,27 @@ public class XSLFTableCell extends XSLFTextShape implements TableCell<XSLFShape,
public StrokeStyle getBorderStyle(final BorderEdge edge) { public StrokeStyle getBorderStyle(final BorderEdge edge) {
final Double width = getBorderWidth(edge); final Double width = getBorderWidth(edge);
return (width == null) ? null : new StrokeStyle() { return (width == null) ? null : new StrokeStyle() {
@Override
public PaintStyle getPaint() { public PaintStyle getPaint() {
return DrawPaint.createSolidPaint(getBorderColor(edge)); return DrawPaint.createSolidPaint(getBorderColor(edge));
} }
@Override
public LineCap getLineCap() { public LineCap getLineCap() {
return getBorderCap(edge); return getBorderCap(edge);
} }
@Override
public LineDash getLineDash() { public LineDash getLineDash() {
return getBorderDash(edge); return getBorderDash(edge);
} }
@Override
public LineCompound getLineCompound() { public LineCompound getLineCompound() {
return getBorderCompound(edge); return getBorderCompound(edge);
} }
@Override
public double getLineWidth() { public double getLineWidth() {
return width; return width;
} }
@ -306,7 +315,9 @@ public class XSLFTableCell extends XSLFTextShape implements TableCell<XSLFShape,
public Color getBorderColor(BorderEdge edge) { public Color getBorderColor(BorderEdge edge) {
CTLineProperties ln = getCTLine(edge, false); CTLineProperties ln = getCTLine(edge, false);
if (ln == null || ln.isSetNoFill() || !ln.isSetSolidFill()) return null; if (ln == null || ln.isSetNoFill() || !ln.isSetSolidFill()) {
return null;
}
CTSolidColorFillProperties fill = ln.getSolidFill(); CTSolidColorFillProperties fill = ln.getSolidFill();
XSLFColor c = new XSLFColor(fill, getSheet().getTheme(), fill.getSchemeClr()); XSLFColor c = new XSLFColor(fill, getSheet().getTheme(), fill.getSchemeClr());
@ -381,7 +392,9 @@ public class XSLFTableCell extends XSLFTextShape implements TableCell<XSLFShape,
public void setFillColor(Color color) { public void setFillColor(Color color) {
CTTableCellProperties spPr = getCellProperties(true); CTTableCellProperties spPr = getCellProperties(true);
if (color == null) { if (color == null) {
if(spPr.isSetSolidFill()) spPr.unsetSolidFill(); if(spPr.isSetSolidFill()) {
spPr.unsetSolidFill();
}
} else { } else {
CTSolidColorFillProperties fill = spPr.isSetSolidFill() ? spPr.getSolidFill() : spPr.addNewSolidFill(); CTSolidColorFillProperties fill = spPr.isSetSolidFill() ? spPr.getSolidFill() : spPr.addNewSolidFill();
XSLFColor c = new XSLFColor(fill, getSheet().getTheme(), fill.getSchemeClr()); XSLFColor c = new XSLFColor(fill, getSheet().getTheme(), fill.getSchemeClr());
@ -409,10 +422,11 @@ public class XSLFTableCell extends XSLFTextShape implements TableCell<XSLFShape,
public PaintStyle getFillPaint() { public PaintStyle getFillPaint() {
XSLFSheet sheet = getSheet(); XSLFSheet sheet = getSheet();
XSLFTheme theme = sheet.getTheme(); XSLFTheme theme = sheet.getTheme();
final boolean hasPlaceholder = getPlaceholder() != null;
XmlObject props = getCellProperties(false); XmlObject props = getCellProperties(false);
XSLFFillProperties fp = XSLFPropertiesDelegate.getFillDelegate(props); XSLFFillProperties fp = XSLFPropertiesDelegate.getFillDelegate(props);
if (fp != null) { if (fp != null) {
PaintStyle paint = selectPaint(fp, null, sheet.getPackagePart(), theme); PaintStyle paint = selectPaint(fp, null, sheet.getPackagePart(), theme, hasPlaceholder);
if (paint != null) { if (paint != null) {
return paint; return paint;
} }
@ -438,7 +452,7 @@ public class XSLFTableCell extends XSLFTextShape implements TableCell<XSLFShape,
fp = XSLFPropertiesDelegate.getFillDelegate(props); fp = XSLFPropertiesDelegate.getFillDelegate(props);
if (fp != null) { if (fp != null) {
PaintStyle paint = XSLFShape.selectPaint(fp, null, slideShow.getPackagePart(), theme); PaintStyle paint = XSLFShape.selectPaint(fp, null, slideShow.getPackagePart(), theme, hasPlaceholder);
if (paint != null) { if (paint != null) {
return paint; return paint;
} }

View File

@ -72,23 +72,20 @@ public class XSLFTextParagraph implements TextParagraph<XSLFShape,XSLFTextParagr
_runs = new ArrayList<XSLFTextRun>(); _runs = new ArrayList<XSLFTextRun>();
_shape = shape; _shape = shape;
for(XmlObject ch : _p.selectPath("*")){ XmlCursor c = _p.newCursor();
if(ch instanceof CTRegularTextRun){ try {
CTRegularTextRun r = (CTRegularTextRun)ch; if (c.toFirstChild()) {
_runs.add(newTextRun(r)); do {
} else if (ch instanceof CTTextLineBreak){ XmlObject r = c.getObject();
CTTextLineBreak br = (CTTextLineBreak)ch; if (r instanceof CTTextLineBreak) {
CTRegularTextRun r = CTRegularTextRun.Factory.newInstance(); _runs.add(new XSLFLineBreak((CTTextLineBreak)r, this));
r.setRPr(br.getRPr()); } else if (r instanceof CTRegularTextRun || r instanceof CTTextField) {
r.setT("\n"); _runs.add(new XSLFTextRun(r, this));
_runs.add(newTextRun(r)); }
} else if (ch instanceof CTTextField){ } while (c.toNextSibling());
CTTextField f = (CTTextField)ch;
CTRegularTextRun r = CTRegularTextRun.Factory.newInstance();
r.setRPr(f.getRPr());
r.setT(f.getT());
_runs.add(newTextRun(r));
} }
} finally {
c.dispose();
} }
} }
@ -147,17 +144,13 @@ public class XSLFTextParagraph implements TextParagraph<XSLFShape,XSLFTextParagr
* @return text run representing this line break ('\n') * @return text run representing this line break ('\n')
*/ */
public XSLFTextRun addLineBreak(){ public XSLFTextRun addLineBreak(){
CTTextLineBreak br = _p.addNewBr(); XSLFLineBreak run = new XSLFLineBreak(_p.addNewBr(), this);
CTTextCharacterProperties brProps = br.addNewRPr(); CTTextCharacterProperties brProps = run.getRPr(true);
if(_runs.size() > 0){ if(_runs.size() > 0){
// by default line break has the font size of the last text run // by default line break has the font size of the last text run
CTTextCharacterProperties prevRun = _runs.get(_runs.size() - 1).getRPr(true); CTTextCharacterProperties prevRun = _runs.get(_runs.size() - 1).getRPr(true);
brProps.set(prevRun); brProps.set(prevRun);
} }
CTRegularTextRun r = CTRegularTextRun.Factory.newInstance();
r.setRPr(brProps);
r.setT("\n");
XSLFTextRun run = new XSLFLineBreak(r, this, brProps);
_runs.add(run); _runs.add(run);
return run; return run;
} }

View File

@ -18,6 +18,7 @@ package org.apache.poi.xslf.usermodel;
import java.awt.Color; import java.awt.Color;
import org.apache.poi.openxml4j.exceptions.OpenXML4JRuntimeException;
import org.apache.poi.openxml4j.opc.PackagePart; import org.apache.poi.openxml4j.opc.PackagePart;
import org.apache.poi.sl.draw.DrawPaint; import org.apache.poi.sl.draw.DrawPaint;
import org.apache.poi.sl.usermodel.PaintStyle; import org.apache.poi.sl.usermodel.PaintStyle;
@ -26,13 +27,16 @@ import org.apache.poi.sl.usermodel.TextRun;
import org.apache.poi.util.Beta; import org.apache.poi.util.Beta;
import org.apache.poi.xslf.model.CharacterPropertyFetcher; import org.apache.poi.xslf.model.CharacterPropertyFetcher;
import org.apache.poi.xslf.usermodel.XSLFPropertiesDelegate.XSLFFillProperties; import org.apache.poi.xslf.usermodel.XSLFPropertiesDelegate.XSLFFillProperties;
import org.apache.xmlbeans.XmlObject;
import org.openxmlformats.schemas.drawingml.x2006.main.CTHyperlink; import org.openxmlformats.schemas.drawingml.x2006.main.CTHyperlink;
import org.openxmlformats.schemas.drawingml.x2006.main.CTRegularTextRun; import org.openxmlformats.schemas.drawingml.x2006.main.CTRegularTextRun;
import org.openxmlformats.schemas.drawingml.x2006.main.CTSchemeColor; import org.openxmlformats.schemas.drawingml.x2006.main.CTSchemeColor;
import org.openxmlformats.schemas.drawingml.x2006.main.CTShapeStyle; import org.openxmlformats.schemas.drawingml.x2006.main.CTShapeStyle;
import org.openxmlformats.schemas.drawingml.x2006.main.CTSolidColorFillProperties; import org.openxmlformats.schemas.drawingml.x2006.main.CTSolidColorFillProperties;
import org.openxmlformats.schemas.drawingml.x2006.main.CTTextCharacterProperties; import org.openxmlformats.schemas.drawingml.x2006.main.CTTextCharacterProperties;
import org.openxmlformats.schemas.drawingml.x2006.main.CTTextField;
import org.openxmlformats.schemas.drawingml.x2006.main.CTTextFont; import org.openxmlformats.schemas.drawingml.x2006.main.CTTextFont;
import org.openxmlformats.schemas.drawingml.x2006.main.CTTextLineBreak;
import org.openxmlformats.schemas.drawingml.x2006.main.CTTextNormalAutofit; import org.openxmlformats.schemas.drawingml.x2006.main.CTTextNormalAutofit;
import org.openxmlformats.schemas.drawingml.x2006.main.CTTextParagraphProperties; import org.openxmlformats.schemas.drawingml.x2006.main.CTTextParagraphProperties;
import org.openxmlformats.schemas.drawingml.x2006.main.STTextStrikeType; import org.openxmlformats.schemas.drawingml.x2006.main.STTextStrikeType;
@ -45,12 +49,15 @@ import org.openxmlformats.schemas.presentationml.x2006.main.CTPlaceholder;
*/ */
@Beta @Beta
public class XSLFTextRun implements TextRun { public class XSLFTextRun implements TextRun {
private final CTRegularTextRun _r; private final XmlObject _r;
private final XSLFTextParagraph _p; private final XSLFTextParagraph _p;
protected XSLFTextRun(CTRegularTextRun r, XSLFTextParagraph p){ protected XSLFTextRun(XmlObject r, XSLFTextParagraph p){
_r = r; _r = r;
_p = p; _p = p;
if (!(r instanceof CTRegularTextRun || r instanceof CTTextLineBreak || r instanceof CTTextField)) {
throw new OpenXML4JRuntimeException("unsupported text run of type "+r.getClass());
}
} }
XSLFTextParagraph getParentParagraph(){ XSLFTextParagraph getParentParagraph(){
@ -58,11 +65,28 @@ public class XSLFTextRun implements TextRun {
} }
public String getRawText(){ public String getRawText(){
return _r.getT(); if (_r instanceof CTTextField) {
return ((CTTextField)_r).getT();
} else if (_r instanceof CTTextLineBreak) {
return "\n";
}
return ((CTRegularTextRun)_r).getT();
} }
String getRenderableText(){ String getRenderableText(){
String txt = _r.getT(); if (_r instanceof CTTextField) {
CTTextField tf = (CTTextField)_r;
XSLFSheet sheet = _p.getParentShape().getSheet();
if ("slidenum".equals(tf.getType()) && sheet instanceof XSLFSlide) {
return Integer.toString(((XSLFSlide)sheet).getSlideNumber());
}
return tf.getT();
} else if (_r instanceof CTTextLineBreak) {
return "\n";
}
String txt = ((CTRegularTextRun)_r).getT();
TextCap cap = getTextCap(); TextCap cap = getTextCap();
StringBuffer buf = new StringBuffer(); StringBuffer buf = new StringBuffer();
for(int i = 0; i < txt.length(); i++) { for(int i = 0; i < txt.length(); i++) {
@ -88,10 +112,24 @@ public class XSLFTextRun implements TextRun {
} }
public void setText(String text){ public void setText(String text){
_r.setT(text); if (_r instanceof CTTextField) {
((CTTextField)_r).setT(text);
} else if (_r instanceof CTTextLineBreak) {
// ignored
return;
} else {
((CTRegularTextRun)_r).setT(text);
}
} }
public CTRegularTextRun getXmlObject(){ /**
* Return the text run xmlbeans object.
* Depending on the type of text run, this can be {@link CTTextField},
* {@link CTTextLineBreak} or usually a {@link CTRegularTextRun}
*
* @return the xmlbeans object
*/
public XmlObject getXmlObject(){
return _r; return _r;
} }
@ -117,6 +155,7 @@ public class XSLFTextRun implements TextRun {
@Override @Override
public PaintStyle getFontColor(){ public PaintStyle getFontColor(){
final boolean hasPlaceholder = getParentParagraph().getParentShape().getPlaceholder() != null;
CharacterPropertyFetcher<PaintStyle> fetcher = new CharacterPropertyFetcher<PaintStyle>(_p.getIndentLevel()){ CharacterPropertyFetcher<PaintStyle> fetcher = new CharacterPropertyFetcher<PaintStyle>(_p.getIndentLevel()){
public boolean fetch(CTTextCharacterProperties props){ public boolean fetch(CTTextCharacterProperties props){
if (props == null) { if (props == null) {
@ -134,7 +173,7 @@ public class XSLFTextRun implements TextRun {
XSLFSheet sheet = shape.getSheet(); XSLFSheet sheet = shape.getSheet();
PackagePart pp = sheet.getPackagePart(); PackagePart pp = sheet.getPackagePart();
XSLFTheme theme = sheet.getTheme(); XSLFTheme theme = sheet.getTheme();
PaintStyle ps = XSLFShape.selectPaint(fp, phClr, pp, theme); PaintStyle ps = XSLFShape.selectPaint(fp, phClr, pp, theme, hasPlaceholder);
if (ps != null) { if (ps != null) {
setValue(ps); setValue(ps);
@ -459,13 +498,29 @@ public class XSLFTextRun implements TextRun {
* @return the character properties or null if create was false and the properties haven't exist * @return the character properties or null if create was false and the properties haven't exist
*/ */
protected CTTextCharacterProperties getRPr(boolean create) { protected CTTextCharacterProperties getRPr(boolean create) {
if (_r.isSetRPr()) { if (_r instanceof CTTextField) {
return _r.getRPr(); CTTextField tf = (CTTextField)_r;
} else if (create) { if (tf.isSetRPr()) {
return _r.addNewRPr(); return tf.getRPr();
} else if (create) {
return tf.addNewRPr();
}
} else if (_r instanceof CTTextLineBreak) {
CTTextLineBreak tlb = (CTTextLineBreak)_r;
if (tlb.isSetRPr()) {
return tlb.getRPr();
} else if (create) {
return tlb.addNewRPr();
}
} else { } else {
return null; CTRegularTextRun tr = (CTRegularTextRun)_r;
if (tr.isSetRPr()) {
return tr.getRPr();
} else if (create) {
return tr.addNewRPr();
}
} }
return null;
} }
@Override @Override
@ -476,15 +531,17 @@ public class XSLFTextRun implements TextRun {
@Override @Override
public XSLFHyperlink createHyperlink(){ public XSLFHyperlink createHyperlink(){
XSLFHyperlink hl = getHyperlink(); XSLFHyperlink hl = getHyperlink();
if (hl == null) { if (hl != null) {
hl = new XSLFHyperlink(_r.getRPr().addNewHlinkClick(), _p.getParentShape().getSheet()); return hl;
} }
return hl;
CTTextCharacterProperties rPr = getRPr(true);
return new XSLFHyperlink(rPr.addNewHlinkClick(), _p.getParentShape().getSheet());
} }
@Override @Override
public XSLFHyperlink getHyperlink(){ public XSLFHyperlink getHyperlink(){
CTTextCharacterProperties rPr = _r.getRPr(); CTTextCharacterProperties rPr = getRPr(false);
if (rPr == null) { if (rPr == null) {
return null; return null;
} }
@ -498,33 +555,33 @@ public class XSLFTextRun implements TextRun {
private boolean fetchCharacterProperty(CharacterPropertyFetcher<?> fetcher){ private boolean fetchCharacterProperty(CharacterPropertyFetcher<?> fetcher){
XSLFTextShape shape = _p.getParentShape(); XSLFTextShape shape = _p.getParentShape();
XSLFSheet sheet = shape.getSheet(); XSLFSheet sheet = shape.getSheet();
boolean ok = false;
if (_r.isSetRPr()) ok = fetcher.fetch(getRPr(false)); CTTextCharacterProperties rPr = getRPr(false);
if (ok) return true; if (rPr != null && fetcher.fetch(rPr)) {
return true;
}
ok = shape.fetchShapeProperty(fetcher); if (shape.fetchShapeProperty(fetcher)) {
if (ok) return true; return true;
}
CTPlaceholder ph = shape.getCTPlaceholder(); CTPlaceholder ph = shape.getCTPlaceholder();
if (ph == null){ if (ph == null){
// if it is a plain text box then take defaults from presentation.xml // if it is a plain text box then take defaults from presentation.xml
@SuppressWarnings("resource") @SuppressWarnings("resource")
XMLSlideShow ppt = sheet.getSlideShow(); XMLSlideShow ppt = sheet.getSlideShow();
// TODO: determine master shape
CTTextParagraphProperties themeProps = ppt.getDefaultParagraphStyle(_p.getIndentLevel()); CTTextParagraphProperties themeProps = ppt.getDefaultParagraphStyle(_p.getIndentLevel());
if (themeProps != null) { if (themeProps != null && fetcher.fetch(themeProps)) {
// TODO: determine master shape return true;
ok = fetcher.fetch(themeProps);
} }
} }
if (ok) return true;
// TODO: determine master shape
CTTextParagraphProperties defaultProps = _p.getDefaultMasterStyle(); CTTextParagraphProperties defaultProps = _p.getDefaultMasterStyle();
if(defaultProps != null) { if(defaultProps != null && fetcher.fetch(defaultProps)) {
// TODO: determine master shape return true;
ok = fetcher.fetch(defaultProps);
} }
if (ok) return true;
return false; return false;
} }
@ -557,4 +614,16 @@ public class XSLFTextRun implements TextRun {
boolean strike = r.isStrikethrough(); boolean strike = r.isStrikethrough();
if(strike != isStrikethrough()) setStrikethrough(strike); if(strike != isStrikethrough()) setStrikethrough(strike);
} }
@Override
public FieldType getFieldType() {
if (_r instanceof CTTextField) {
CTTextField tf = (CTTextField)_r;
if ("slidenum".equals(tf.getType())) {
return FieldType.SLIDE_NUMBER;
}
}
return null;
}
} }

View File

@ -169,5 +169,4 @@ public class XSLFTheme extends POIXMLDocumentPart {
} }
return null; return null;
} }
} }

View File

@ -108,7 +108,8 @@ public class TestXSLFSlideShow {
// And again for the master // And again for the master
CTSlideMasterIdListEntry[] masters = xml.getSlideMasterReferences().getSldMasterIdArray(); CTSlideMasterIdListEntry[] masters = xml.getSlideMasterReferences().getSldMasterIdArray();
assertEquals(2147483648l, masters[0].getId()); // see SlideAtom.USES_MASTER_SLIDE_ID
assertEquals(0x80000000L, masters[0].getId());
assertEquals("rId1", masters[0].getId2()); assertEquals("rId1", masters[0].getId2());
assertNotNull(xml.getSlideMaster(masters[0])); assertNotNull(xml.getSlideMaster(masters[0]));

View File

@ -105,7 +105,8 @@ public class TestXMLSlideShow extends BaseTestSlideShow {
// Next up look for the slide master // Next up look for the slide master
CTSlideMasterIdListEntry[] masters = xml.getCTPresentation().getSldMasterIdLst().getSldMasterIdArray(); CTSlideMasterIdListEntry[] masters = xml.getCTPresentation().getSldMasterIdLst().getSldMasterIdArray();
assertEquals(2147483648l, masters[0].getId()); // see SlideAtom.USES_MASTER_SLIDE_ID
assertEquals(0x80000000L, masters[0].getId());
assertEquals("rId1", masters[0].getId2()); assertEquals("rId1", masters[0].getId2());
assertNotNull(xml.getSlideMasters().get(0)); assertNotNull(xml.getSlideMasters().get(0));

View File

@ -16,22 +16,26 @@
==================================================================== */ ==================================================================== */
package org.apache.poi.xslf.usermodel; package org.apache.poi.xslf.usermodel;
import static org.junit.Assert.*; import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertSame;
import static org.junit.Assert.assertTrue;
import java.io.IOException; import java.io.IOException;
import org.apache.poi.sl.usermodel.*; import org.apache.poi.sl.usermodel.ShapeType;
import org.apache.poi.sl.usermodel.TextParagraph.TextAlign; import org.apache.poi.sl.usermodel.TextParagraph.TextAlign;
import org.apache.poi.sl.usermodel.TextShape.TextAutofit; import org.apache.poi.sl.usermodel.TextShape.TextAutofit;
import org.apache.poi.sl.usermodel.TextShape.TextDirection; import org.apache.poi.sl.usermodel.TextShape.TextDirection;
import org.apache.poi.sl.usermodel.VerticalAlignment;
import org.apache.poi.util.Units; import org.apache.poi.util.Units;
import org.junit.Test; import org.junit.Test;
import org.openxmlformats.schemas.drawingml.x2006.main.CTTextCharacterProperties;
import org.openxmlformats.schemas.drawingml.x2006.main.STTextStrikeType; import org.openxmlformats.schemas.drawingml.x2006.main.STTextStrikeType;
import org.openxmlformats.schemas.drawingml.x2006.main.STTextUnderlineType; import org.openxmlformats.schemas.drawingml.x2006.main.STTextUnderlineType;
/**
* @author Yegor Kozlov
*/
public class TestXSLFAutoShape { public class TestXSLFAutoShape {
@Test @Test
public void testTextBodyProperies() throws IOException { public void testTextBodyProperies() throws IOException {
@ -222,56 +226,58 @@ public class TestXSLFAutoShape {
assertEquals(1, shape.getTextParagraphs().size()); assertEquals(1, shape.getTextParagraphs().size());
assertEquals(0, p.getTextRuns().size()); assertEquals(0, p.getTextRuns().size());
XSLFTextRun r = p.addNewTextRun(); XSLFTextRun r = p.addNewTextRun();
CTTextCharacterProperties rPr = r.getRPr(false);
assertNotNull(rPr);
assertEquals(1, p.getTextRuns().size()); assertEquals(1, p.getTextRuns().size());
assertSame(r, p.getTextRuns().get(0)); assertSame(r, p.getTextRuns().get(0));
assertEquals(18.0, r.getFontSize(), 0); // default font size for text boxes assertEquals(18.0, r.getFontSize(), 0); // default font size for text boxes
assertFalse(r.getXmlObject().getRPr().isSetSz()); assertFalse(rPr.isSetSz());
r.setFontSize(10.0); r.setFontSize(10.0);
assertTrue(r.getXmlObject().isSetRPr()); assertEquals(1000, rPr.getSz());
assertEquals(1000, r.getXmlObject().getRPr().getSz());
r.setFontSize(12.5); r.setFontSize(12.5);
assertEquals(1250, r.getXmlObject().getRPr().getSz()); assertEquals(1250, rPr.getSz());
r.setFontSize(null); r.setFontSize(null);
assertFalse(r.getXmlObject().getRPr().isSetSz()); assertFalse(rPr.isSetSz());
assertFalse(r.getXmlObject().getRPr().isSetLatin()); assertFalse(rPr.isSetLatin());
assertEquals("Calibri", r.getFontFamily()); // comes from the slide master assertEquals("Calibri", r.getFontFamily()); // comes from the slide master
r.setFontFamily(null); r.setFontFamily(null);
assertEquals("Calibri", r.getFontFamily()); // comes from the slide master assertEquals("Calibri", r.getFontFamily()); // comes from the slide master
r.setFontFamily("Arial"); r.setFontFamily("Arial");
assertEquals("Arial", r.getFontFamily()); assertEquals("Arial", r.getFontFamily());
assertEquals("Arial", r.getXmlObject().getRPr().getLatin().getTypeface()); assertEquals("Arial", rPr.getLatin().getTypeface());
r.setFontFamily("Symbol"); r.setFontFamily("Symbol");
assertEquals("Symbol", r.getFontFamily()); assertEquals("Symbol", r.getFontFamily());
assertEquals("Symbol", r.getXmlObject().getRPr().getLatin().getTypeface()); assertEquals("Symbol", rPr.getLatin().getTypeface());
r.setFontFamily(null); r.setFontFamily(null);
assertEquals("Calibri", r.getFontFamily()); // comes from the slide master assertEquals("Calibri", r.getFontFamily()); // comes from the slide master
assertFalse(r.getXmlObject().getRPr().isSetLatin()); assertFalse(rPr.isSetLatin());
assertFalse(r.isStrikethrough()); assertFalse(r.isStrikethrough());
assertFalse(r.getXmlObject().getRPr().isSetStrike()); assertFalse(rPr.isSetStrike());
r.setStrikethrough(true); r.setStrikethrough(true);
assertTrue(r.isStrikethrough()); assertTrue(r.isStrikethrough());
assertEquals(STTextStrikeType.SNG_STRIKE, r.getXmlObject().getRPr().getStrike()); assertEquals(STTextStrikeType.SNG_STRIKE, rPr.getStrike());
assertFalse(r.isBold()); assertFalse(r.isBold());
assertFalse(r.getXmlObject().getRPr().isSetB()); assertFalse(rPr.isSetB());
r.setBold(true); r.setBold(true);
assertTrue(r.isBold()); assertTrue(r.isBold());
assertEquals(true, r.getXmlObject().getRPr().getB()); assertEquals(true, rPr.getB());
assertFalse(r.isItalic()); assertFalse(r.isItalic());
assertFalse(r.getXmlObject().getRPr().isSetI()); assertFalse(rPr.isSetI());
r.setItalic(true); r.setItalic(true);
assertTrue(r.isItalic()); assertTrue(r.isItalic());
assertEquals(true, r.getXmlObject().getRPr().getI()); assertEquals(true, rPr.getI());
assertFalse(r.isUnderlined()); assertFalse(r.isUnderlined());
assertFalse(r.getXmlObject().getRPr().isSetU()); assertFalse(rPr.isSetU());
r.setUnderlined(true); r.setUnderlined(true);
assertTrue(r.isUnderlined()); assertTrue(r.isUnderlined());
assertEquals(STTextUnderlineType.SNG, r.getXmlObject().getRPr().getU()); assertEquals(STTextUnderlineType.SNG, rPr.getU());
r.setText("Apache"); r.setText("Apache");
assertEquals("Apache", r.getRawText()); assertEquals("Apache", r.getRawText());

View File

@ -123,10 +123,11 @@ public class TestXSLFHyperlink {
XSLFTextBox tb3 = sl3.createTextBox(); XSLFTextBox tb3 = sl3.createTextBox();
tb3.setAnchor(anchor); tb3.setAnchor(anchor);
tb3.setText("text1 "); tb3.setText("text1 ");
XSLFTextRun r3 = tb3.appendText("lin\u000bk", false); tb3.appendText("lin\u000bk", false);
tb3.appendText(" text2", false); tb3.appendText(" text2", false);
XSLFHyperlink hl3 = r3.createHyperlink(); List<XSLFTextRun> tb3runs = tb3.getTextParagraphs().get(0).getTextRuns();
hl3.linkToSlide(slide1); tb3runs.get(1).createHyperlink().linkToSlide(slide1); // "lin"
tb3runs.get(3).createHyperlink().linkToSlide(slide1); // "k"
XSLFTextBox tb4 = ppt1.createSlide().createTextBox(); XSLFTextBox tb4 = ppt1.createSlide().createTextBox();
tb4.setAnchor(anchor); tb4.setAnchor(anchor);
XSLFTextRun r4 = tb4.setText("page4"); XSLFTextRun r4 = tb4.setText("page4");
@ -155,6 +156,8 @@ public class TestXSLFHyperlink {
assertEquals(HyperlinkType.DOCUMENT, hl2.getTypeEnum()); assertEquals(HyperlinkType.DOCUMENT, hl2.getTypeEnum());
tb3 = (XSLFTextBox)slides.get(2).getShapes().get(0); tb3 = (XSLFTextBox)slides.get(2).getShapes().get(0);
XSLFHyperlink hl3 = tb3.getTextParagraphs().get(0).getTextRuns().get(1).getHyperlink();
assertNotNull(hl3);
hl3 = tb3.getTextParagraphs().get(0).getTextRuns().get(3).getHyperlink(); hl3 = tb3.getTextParagraphs().get(0).getTextRuns().get(3).getHyperlink();
assertNotNull(hl3); assertNotNull(hl3);
assertEquals("/ppt/slides/slide1.xml", hl3.getAddress()); assertEquals("/ppt/slides/slide1.xml", hl3.getAddress());

View File

@ -16,18 +16,17 @@
==================================================================== */ ==================================================================== */
package org.apache.poi.xslf.usermodel; package org.apache.poi.xslf.usermodel;
import static org.junit.Assert.*; import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertSame;
import static org.junit.Assert.assertTrue;
import java.io.IOException;
import java.util.List;
import org.apache.poi.xslf.XSLFTestDataSamples; import org.apache.poi.xslf.XSLFTestDataSamples;
import org.junit.Test; import org.junit.Test;
import org.openxmlformats.schemas.drawingml.x2006.main.STTextUnderlineType; import org.openxmlformats.schemas.drawingml.x2006.main.STTextUnderlineType;
import java.io.IOException;
import java.util.List;
/**
* @author Yegor Kozlov
*/
public class TestXSLFShape { public class TestXSLFShape {
@Test @Test
@ -63,7 +62,7 @@ public class TestXSLFShape {
assertEquals("PPTX ", r2.get(0).getRawText()); assertEquals("PPTX ", r2.get(0).getRawText());
assertEquals("Title", r2.get(1).getRawText()); assertEquals("Title", r2.get(1).getRawText());
// Title is underlined // Title is underlined
assertEquals(STTextUnderlineType.SNG, r2.get(1).getXmlObject().getRPr().getU()); assertEquals(STTextUnderlineType.SNG, r2.get(1).getRPr(false).getU());
assertTrue(shapes2.get(1) instanceof XSLFAutoShape); assertTrue(shapes2.get(1) instanceof XSLFAutoShape);
@ -78,7 +77,7 @@ public class TestXSLFShape {
assertEquals(1, paragraphs2.get(1).getTextRuns().size()); assertEquals(1, paragraphs2.get(1).getTextRuns().size());
assertEquals("Subtitle", paragraphs2.get(0).getTextRuns().get(0).getRawText()); assertEquals("Subtitle", paragraphs2.get(0).getTextRuns().get(0).getRawText());
assertTrue(paragraphs2.get(0).getTextRuns().get(0).getXmlObject().getRPr().getB()); assertTrue(paragraphs2.get(0).getTextRuns().get(0).getRPr(false).getB());
assertEquals("And second line", paragraphs2.get(1).getTextRuns().get(0).getRawText()); assertEquals("And second line", paragraphs2.get(1).getTextRuns().get(0).getRawText());
ppt.close(); ppt.close();

View File

@ -111,7 +111,7 @@ public class TestXSLFSlide {
assertEquals(0, ppt.getSlides().size()); assertEquals(0, ppt.getSlides().size());
XSLFSlide slide = ppt.createSlide(); XSLFSlide slide = ppt.createSlide();
assertFalse(slide.getFollowMasterGraphics()); assertTrue(slide.getFollowMasterGraphics());
slide.setFollowMasterGraphics(false); slide.setFollowMasterGraphics(false);
assertFalse(slide.getFollowMasterGraphics()); assertFalse(slide.getFollowMasterGraphics());
slide.setFollowMasterGraphics(true); slide.setFollowMasterGraphics(true);

View File

@ -714,7 +714,7 @@ public class TestXSLFTextShape {
// level 5: text properties are defined in the text run // level 5: text properties are defined in the text run
CTTextParagraphProperties lv5PPr = paragraph.getXmlObject().addNewPPr(); CTTextParagraphProperties lv5PPr = paragraph.getXmlObject().addNewPPr();
CTTextCharacterProperties lv5CPr = textRun.getXmlObject().getRPr(); CTTextCharacterProperties lv5CPr = textRun.getRPr(false);
lv5CPr.setSz(3600); lv5CPr.setSz(3600);
assertEquals(36.0, textRun.getFontSize(), 0); assertEquals(36.0, textRun.getFontSize(), 0);
lv5CPr.addNewLatin().setTypeface("Calibri"); lv5CPr.addNewLatin().setTypeface("Calibri");
@ -899,11 +899,11 @@ public class TestXSLFTextShape {
// level 5: text properties are defined in the text run // level 5: text properties are defined in the text run
lv1PPr = p1.getXmlObject().isSetPPr() ? p1.getXmlObject().getPPr() : p1.getXmlObject().addNewPPr(); lv1PPr = p1.getXmlObject().isSetPPr() ? p1.getXmlObject().getPPr() : p1.getXmlObject().addNewPPr();
lv1CPr = r1.getXmlObject().getRPr(); lv1CPr = r1.getRPr(false);
lv2PPr = p2.getXmlObject().isSetPPr() ? p2.getXmlObject().getPPr() : p2.getXmlObject().addNewPPr(); lv2PPr = p2.getXmlObject().isSetPPr() ? p2.getXmlObject().getPPr() : p2.getXmlObject().addNewPPr();
lv2CPr = r2.getXmlObject().getRPr(); lv2CPr = r2.getRPr(false);
lv3PPr = p3.getXmlObject().isSetPPr() ? p3.getXmlObject().getPPr() : p3.getXmlObject().addNewPPr(); lv3PPr = p3.getXmlObject().isSetPPr() ? p3.getXmlObject().getPPr() : p3.getXmlObject().addNewPPr();
lv3CPr = r3.getXmlObject().getRPr(); lv3CPr = r3.getRPr(false);
lv1CPr.setSz(3600); lv1CPr.setSz(3600);
assertEquals(36.0, r1.getFontSize(), 0); assertEquals(36.0, r1.getFontSize(), 0);

View File

@ -17,12 +17,15 @@
package org.apache.poi.xslf.usermodel; package org.apache.poi.xslf.usermodel;
import static org.apache.poi.sl.TestCommonSL.sameColor; import static org.apache.poi.sl.TestCommonSL.sameColor;
import static org.junit.Assert.*; import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import java.awt.Color; import java.awt.Color;
import java.util.List; import java.util.List;
import org.apache.poi.sl.usermodel.*; import org.apache.poi.sl.usermodel.PaintStyle;
import org.apache.poi.sl.usermodel.PaintStyle.GradientPaint; import org.apache.poi.sl.usermodel.PaintStyle.GradientPaint;
import org.apache.poi.sl.usermodel.PaintStyle.SolidPaint; import org.apache.poi.sl.usermodel.PaintStyle.SolidPaint;
import org.apache.poi.sl.usermodel.PaintStyle.TexturePaint; import org.apache.poi.sl.usermodel.PaintStyle.TexturePaint;
@ -54,7 +57,9 @@ public class TestXSLFTheme {
private XSLFShape getShape(XSLFSheet sheet, String name){ private XSLFShape getShape(XSLFSheet sheet, String name){
for(XSLFShape sh : sheet.getShapes()){ for(XSLFShape sh : sheet.getShapes()){
if(sh.getShapeName().equals(name)) return sh; if(sh.getShapeName().equals(name)) {
return sh;
}
} }
throw new IllegalArgumentException("Shape not found: " + name); throw new IllegalArgumentException("Shape not found: " + name);
} }
@ -99,7 +104,7 @@ public class TestXSLFTheme {
assertTrue(sameColor(new Color(148, 198, 0), run2.getFontColor())); assertTrue(sameColor(new Color(148, 198, 0), run2.getFontColor()));
assertNull(sh2.getFillColor()); // no fill assertNull(sh2.getFillColor()); // no fill
assertFalse(slide.getSlideLayout().getFollowMasterGraphics()); assertTrue(slide.getSlideLayout().getFollowMasterGraphics());
} }
void slide5(XSLFSlide slide){ void slide5(XSLFSlide slide){
@ -113,7 +118,7 @@ public class TestXSLFTheme {
// font size is 40pt and scale factor is 90% // font size is 40pt and scale factor is 90%
assertEquals(36.0, run2.getFontSize(), 0); assertEquals(36.0, run2.getFontSize(), 0);
assertFalse(slide.getSlideLayout().getFollowMasterGraphics()); assertTrue(slide.getSlideLayout().getFollowMasterGraphics());
} }
void slide6(XSLFSlide slide){ void slide6(XSLFSlide slide){

View File

@ -21,13 +21,14 @@ import org.apache.poi.hslf.record.CString;
import org.apache.poi.hslf.record.Document; import org.apache.poi.hslf.record.Document;
import org.apache.poi.hslf.record.HeadersFootersAtom; import org.apache.poi.hslf.record.HeadersFootersAtom;
import org.apache.poi.hslf.record.HeadersFootersContainer; import org.apache.poi.hslf.record.HeadersFootersContainer;
import org.apache.poi.hslf.record.OEPlaceholderAtom;
import org.apache.poi.hslf.record.Record; import org.apache.poi.hslf.record.Record;
import org.apache.poi.hslf.record.RecordTypes; import org.apache.poi.hslf.record.RecordTypes;
import org.apache.poi.hslf.record.SheetContainer; import org.apache.poi.hslf.record.SheetContainer;
import org.apache.poi.hslf.usermodel.HSLFSheet; import org.apache.poi.hslf.usermodel.HSLFSheet;
import org.apache.poi.hslf.usermodel.HSLFSimpleShape;
import org.apache.poi.hslf.usermodel.HSLFSlideShow; import org.apache.poi.hslf.usermodel.HSLFSlideShow;
import org.apache.poi.hslf.usermodel.HSLFTextShape; import org.apache.poi.hslf.usermodel.HSLFTextShape;
import org.apache.poi.sl.usermodel.Placeholder;
/** /**
* Header / Footer settings. * Header / Footer settings.
@ -87,7 +88,7 @@ public final class HeadersFooters {
*/ */
public String getHeaderText(){ public String getHeaderText(){
CString cs = _container == null ? null : _container.getHeaderAtom(); CString cs = _container == null ? null : _container.getHeaderAtom();
return getPlaceholderText(OEPlaceholderAtom.MasterHeader, cs); return getPlaceholderText(Placeholder.HEADER, cs);
} }
/** /**
@ -112,7 +113,7 @@ public final class HeadersFooters {
*/ */
public String getFooterText(){ public String getFooterText(){
CString cs = _container == null ? null : _container.getFooterAtom(); CString cs = _container == null ? null : _container.getFooterAtom();
return getPlaceholderText(OEPlaceholderAtom.MasterFooter, cs); return getPlaceholderText(Placeholder.FOOTER, cs);
} }
/** /**
@ -137,7 +138,7 @@ public final class HeadersFooters {
*/ */
public String getDateTimeText(){ public String getDateTimeText(){
CString cs = _container == null ? null : _container.getUserDateAtom(); CString cs = _container == null ? null : _container.getUserDateAtom();
return getPlaceholderText(OEPlaceholderAtom.MasterDate, cs); return getPlaceholderText(Placeholder.DATETIME, cs);
} }
/** /**
@ -160,7 +161,7 @@ public final class HeadersFooters {
* whether the footer text is displayed. * whether the footer text is displayed.
*/ */
public boolean isFooterVisible(){ public boolean isFooterVisible(){
return isVisible(HeadersFootersAtom.fHasFooter, OEPlaceholderAtom.MasterFooter); return isVisible(HeadersFootersAtom.fHasFooter, Placeholder.FOOTER);
} }
/** /**
@ -174,7 +175,7 @@ public final class HeadersFooters {
* whether the header text is displayed. * whether the header text is displayed.
*/ */
public boolean isHeaderVisible(){ public boolean isHeaderVisible(){
return isVisible(HeadersFootersAtom.fHasHeader, OEPlaceholderAtom.MasterHeader); return isVisible(HeadersFootersAtom.fHasHeader, Placeholder.HEADER);
} }
/** /**
@ -188,7 +189,7 @@ public final class HeadersFooters {
* whether the date is displayed in the footer. * whether the date is displayed in the footer.
*/ */
public boolean isDateTimeVisible(){ public boolean isDateTimeVisible(){
return isVisible(HeadersFootersAtom.fHasDate, OEPlaceholderAtom.MasterDate); return isVisible(HeadersFootersAtom.fHasDate, Placeholder.DATETIME);
} }
/** /**
@ -202,7 +203,7 @@ public final class HeadersFooters {
* whether the custom user date is used instead of today's date. * whether the custom user date is used instead of today's date.
*/ */
public boolean isUserDateVisible(){ public boolean isUserDateVisible(){
return isVisible(HeadersFootersAtom.fHasUserDate, OEPlaceholderAtom.MasterDate); return isVisible(HeadersFootersAtom.fHasUserDate, Placeholder.DATETIME);
} }
/** /**
@ -216,7 +217,7 @@ public final class HeadersFooters {
* whether the slide number is displayed in the footer. * whether the slide number is displayed in the footer.
*/ */
public boolean isSlideNumberVisible(){ public boolean isSlideNumberVisible(){
return isVisible(HeadersFootersAtom.fHasSlideNumber, OEPlaceholderAtom.MasterSlideNumber); return isVisible(HeadersFootersAtom.fHasSlideNumber, Placeholder.SLIDE_NUMBER);
} }
/** /**
@ -244,31 +245,29 @@ public final class HeadersFooters {
_container.getHeadersFootersAtom().setFormatId(formatId); _container.getHeadersFootersAtom().setFormatId(formatId);
} }
private boolean isVisible(int flag, int placeholderId){ private boolean isVisible(int flag, Placeholder placeholderId){
boolean visible; boolean visible;
if(_ppt2007){ if(_ppt2007){
HSLFTextShape placeholder = _sheet.getPlaceholder(placeholderId); HSLFSimpleShape ss = _sheet.getPlaceholder(placeholderId);
visible = placeholder != null && placeholder.getText() != null; visible = ss instanceof HSLFTextShape && ((HSLFTextShape)ss).getText() != null;
} else { } else {
visible = _container.getHeadersFootersAtom().getFlag(flag); visible = _container.getHeadersFootersAtom().getFlag(flag);
} }
return visible; return visible;
} }
private String getPlaceholderText(int placeholderId, CString cs){ private String getPlaceholderText(Placeholder ph, CString cs) {
String text = null; String text;
if (_ppt2007) { if (_ppt2007) {
HSLFTextShape placeholder = _sheet.getPlaceholder(placeholderId); HSLFSimpleShape ss = _sheet.getPlaceholder(ph);
if (placeholder != null) { text = (ss instanceof HSLFTextShape) ? ((HSLFTextShape)ss).getText() : null;
text = placeholder.getText();
}
// default text in master placeholders is not visible // default text in master placeholders is not visible
if("*".equals(text)) { if("*".equals(text)) {
text = null; text = null;
} }
} else { } else {
text = cs == null ? null : cs.getText(); text = (cs == null) ? null : cs.getText();
} }
return text; return text;
} }

View File

@ -17,17 +17,18 @@
package org.apache.poi.hslf.record; package org.apache.poi.hslf.record;
import org.apache.poi.util.LittleEndian;
import java.io.IOException; import java.io.IOException;
import java.io.OutputStream; import java.io.OutputStream;
import org.apache.poi.sl.usermodel.Placeholder;
import org.apache.poi.util.LittleEndian;
/** /**
* OEPlaceholderAtom (3011). * OEPlaceholderAtom (3011).<p>
* <p> *
* An atom record that specifies whether a shape is a placeholder shape. * An atom record that specifies whether a shape is a placeholder shape.
* </p>
* *
* @author Yegor Kozlov * @see Placeholder
*/ */
public final class OEPlaceholderAtom extends RecordAtom{ public final class OEPlaceholderAtom extends RecordAtom{
@ -47,155 +48,6 @@ public final class OEPlaceholderAtom extends RecordAtom{
*/ */
public static final int PLACEHOLDER_QUARTSIZE = 2; public static final int PLACEHOLDER_QUARTSIZE = 2;
/**
* MUST NOT be used for this field.
*/
public static final byte None = 0;
/**
* The corresponding shape contains the master title text.
* The corresponding slide MUST be a main master slide.
*/
public static final byte MasterTitle = 1;
/**
* The corresponding shape contains the master body text.
* The corresponding slide MUST be a main master slide.
*/
public static final byte MasterBody = 2;
/**
* The corresponding shape contains the master center title text.
* The corresponding slide MUST be a title master slide.
*/
public static final byte MasterCenteredTitle = 3;
/**
* The corresponding shape contains the master sub-title text.
* The corresponding slide MUST be a title master slide.
*/
public static final byte MasterSubTitle = 4;
/**
* The corresponding shape contains the shared properties for slide image shapes.
* The corresponding slide MUST be a notes master slide.
*/
public static final byte MasterNotesSlideImage = 5;
/**
* The corresponding shape contains the master body text.
* The corresponding slide MUST be a notes master slide.
*/
public static final byte MasterNotesBody = 6;
/**
* The corresponding shape contains the date text field.
* The corresponding slide MUST be a main master slide, title master slide, notes master slide, or handout master slide.
*/
public static final byte MasterDate = 7;
/**
* The corresponding shape contains a slide number text field.
* The corresponding slide MUST be a main master slide, title master slide, notes master slide, or handout master slide.
*/
public static final byte MasterSlideNumber = 8;
/**
* The corresponding shape contains a footer text field.
* The corresponding slide MUST be a main master slide, title master slide, notes master slide, or handout master slide.
*/
public static final byte MasterFooter = 9;
/**
* The corresponding shape contains a header text field.
* The corresponding slide must be a notes master slide or handout master slide.
*/
public static final byte MasterHeader = 10;
/**
* The corresponding shape contains a presentation slide image.
* The corresponding slide MUST be a notes slide.
*/
public static final byte NotesSlideImage = 11;
/**
* The corresponding shape contains the notes text.
* The corresponding slide MUST be a notes slide.
*/
public static final byte NotesBody = 12;
/**
* The corresponding shape contains the title text.
* The corresponding slide MUST be a presentation slide.
*/
public static final byte Title = 13;
/**
* The corresponding shape contains the body text.
* The corresponding slide MUST be a presentation slide.
*/
public static final byte Body = 14;
/**
* The corresponding shape contains the title text.
* The corresponding slide MUST be a presentation slide.
*/
public static final byte CenteredTitle = 15;
/**
* The corresponding shape contains the sub-title text.
* The corresponding slide MUST be a presentation slide.
*/
public static final byte Subtitle = 16;
/**
* The corresponding shape contains the title text with vertical text flow.
* The corresponding slide MUST be a presentation slide.
*/
public static final byte VerticalTextTitle = 17;
/**
* The corresponding shape contains the body text with vertical text flow.
* The corresponding slide MUST be a presentation slide.
*/
public static final byte VerticalTextBody = 18;
/**
* The corresponding shape contains a generic object.
* The corresponding slide MUST be a presentation slide.
*/
public static final byte Object = 19;
/**
* The corresponding shape contains a chart object.
* The corresponding slide MUST be a presentation slide.
*/
public static final byte Graph = 20;
/**
* The corresponding shape contains a table object.
* The corresponding slide MUST be a presentation slide.
*/
public static final byte Table = 21;
/**
* The corresponding shape contains a clipart object.
* The corresponding slide MUST be a presentation slide.
*/
public static final byte ClipArt = 22;
/**
* The corresponding shape contains an organization chart object.
* The corresponding slide MUST be a presentation slide.
*/
public static final byte OrganizationChart = 23;
/**
* The corresponding shape contains a media object.
* The corresponding slide MUST be a presentation slide.
*/
public static final byte MediaClip = 24;
private byte[] _header; private byte[] _header;
private int placementId; private int placementId;
@ -205,7 +57,7 @@ public final class OEPlaceholderAtom extends RecordAtom{
/** /**
* Create a new instance of <code>OEPlaceholderAtom</code> * Create a new instance of {@code OEPlaceholderAtom}
*/ */
public OEPlaceholderAtom(){ public OEPlaceholderAtom(){
_header = new byte[8]; _header = new byte[8];
@ -219,7 +71,7 @@ public final class OEPlaceholderAtom extends RecordAtom{
} }
/** /**
* Build an instance of <code>OEPlaceholderAtom</code> from on-disk data * Build an instance of {@code OEPlaceholderAtom} from on-disk data
*/ */
protected OEPlaceholderAtom(byte[] source, int start, int len) { protected OEPlaceholderAtom(byte[] source, int start, int len) {
_header = new byte[8]; _header = new byte[8];
@ -236,15 +88,15 @@ public final class OEPlaceholderAtom extends RecordAtom{
/** /**
* @return type of this record {@link RecordTypes#OEPlaceholderAtom}. * @return type of this record {@link RecordTypes#OEPlaceholderAtom}.
*/ */
public long getRecordType() { return RecordTypes.OEPlaceholderAtom.typeID; } @Override
public long getRecordType() { return RecordTypes.OEPlaceholderAtom.typeID; }
/** /**
* Returns the placement Id. * Returns the placement Id.<p>
* <p> *
* The placement Id is a number assigned to the placeholder. It goes from -1 to the number of placeholders. * The placement Id is a number assigned to the placeholder. It goes from -1 to the number of placeholders.
* It SHOULD be unique among all PlacholderAtom records contained in the corresponding slide. * It SHOULD be unique among all PlacholderAtom records contained in the corresponding slide.
* The value 0xFFFFFFFF specifies that the corresponding shape is not a placeholder shape. * The value 0xFFFFFFFF specifies that the corresponding shape is not a placeholder shape.
* </p>
* *
* @return the placement Id. * @return the placement Id.
*/ */
@ -253,12 +105,11 @@ public final class OEPlaceholderAtom extends RecordAtom{
} }
/** /**
* Sets the placement Id. * Sets the placement Id.<p>
* <p> *
* The placement Id is a number assigned to the placeholder. It goes from -1 to the number of placeholders. * The placement Id is a number assigned to the placeholder. It goes from -1 to the number of placeholders.
* It SHOULD be unique among all PlacholderAtom records contained in the corresponding slide. * It SHOULD be unique among all PlacholderAtom records contained in the corresponding slide.
* The value 0xFFFFFFFF specifies that the corresponding shape is not a placeholder shape. * The value 0xFFFFFFFF specifies that the corresponding shape is not a placeholder shape.
* </p>
* *
* @param id the placement Id. * @param id the placement Id.
*/ */
@ -267,12 +118,10 @@ public final class OEPlaceholderAtom extends RecordAtom{
} }
/** /**
* Returns the placeholder Id. * Returns the placeholder Id.<p>
* *
* <p>
* placeholder Id specifies the type of the placeholder shape. * placeholder Id specifies the type of the placeholder shape.
* The value MUST be one of the static constants defined in this class * The value MUST be one of the static constants defined in this class
* </p>
* *
* @return the placeholder Id. * @return the placeholder Id.
*/ */
@ -281,12 +130,11 @@ public final class OEPlaceholderAtom extends RecordAtom{
} }
/** /**
* Sets the placeholder Id. * Sets the placeholder Id.<p>
* *
* <p>
* placeholder Id specifies the type of the placeholder shape. * placeholder Id specifies the type of the placeholder shape.
* The value MUST be one of the static constants defined in this class * The value MUST be one of the static constants defined in this class
* </p> *
* @param id the placeholder Id. * @param id the placeholder Id.
*/ */
public void setPlaceholderId(byte id){ public void setPlaceholderId(byte id){
@ -314,10 +162,10 @@ public final class OEPlaceholderAtom extends RecordAtom{
} }
/** /**
* Write the contents of the record back, so it can be written * Write the contents of the record back, so it can be written to disk
* to disk
*/ */
public void writeOut(OutputStream out) throws IOException { @Override
public void writeOut(OutputStream out) throws IOException {
out.write(_header); out.write(_header);
byte[] recdata = new byte[8]; byte[] recdata = new byte[8];

View File

@ -20,23 +20,21 @@ package org.apache.poi.hslf.record;
import java.io.IOException; import java.io.IOException;
import java.io.OutputStream; import java.io.OutputStream;
import org.apache.poi.hslf.exceptions.HSLFException; import org.apache.poi.hslf.record.SlideAtomLayout.SlideLayoutType;
import org.apache.poi.util.LittleEndian; import org.apache.poi.util.LittleEndian;
/** /**
* A Slide Atom (type 1007). Holds information on the parent Slide, what * A Slide Atom (type 1007). Holds information on the parent Slide, what
* Master Slide it uses, what Notes is attached to it, that sort of thing. * Master Slide it uses, what Notes is attached to it, that sort of thing.
* It also has a SSlideLayoutAtom embeded in it, but without the Atom header * It also has a SSlideLayoutAtom embedded in it, but without the Atom header
*
* @author Nick Burch
*/ */
public final class SlideAtom extends RecordAtom public final class SlideAtom extends RecordAtom {
{ public static final int USES_MASTER_SLIDE_ID = 0x80000000;
private byte[] _header; // private static final int MASTER_SLIDE_ID = 0x00000000;
private byte[] _header;
private static long _type = 1007l; private static long _type = 1007l;
public static final int MASTER_SLIDE_ID = 0;
public static final int USES_MASTER_SLIDE_ID = -2147483648;
private int masterID; private int masterID;
private int notesID; private int notesID;
@ -44,7 +42,7 @@ public final class SlideAtom extends RecordAtom
private boolean followMasterObjects; private boolean followMasterObjects;
private boolean followMasterScheme; private boolean followMasterScheme;
private boolean followMasterBackground; private boolean followMasterBackground;
private SSlideLayoutAtom layoutAtom; private SlideAtomLayout layoutAtom;
private byte[] reserved; private byte[] reserved;
@ -54,8 +52,8 @@ public final class SlideAtom extends RecordAtom
public void setMasterID(int id) { masterID = id; } public void setMasterID(int id) { masterID = id; }
/** Get the ID of the notes for this slide. 0 if doesn't have one */ /** Get the ID of the notes for this slide. 0 if doesn't have one */
public int getNotesID() { return notesID; } public int getNotesID() { return notesID; }
/** Get the embeded SSlideLayoutAtom */ /** Get the embedded SSlideLayoutAtom */
public SSlideLayoutAtom getSSlideLayoutAtom() { return layoutAtom; } public SlideAtomLayout getSSlideLayoutAtom() { return layoutAtom; }
/** Change the ID of the notes for this slide. 0 if it no longer has one */ /** Change the ID of the notes for this slide. 0 if it no longer has one */
public void setNotesID(int id) { notesID = id; } public void setNotesID(int id) { notesID = id; }
@ -85,7 +83,7 @@ public final class SlideAtom extends RecordAtom
byte[] SSlideLayoutAtomData = new byte[12]; byte[] SSlideLayoutAtomData = new byte[12];
System.arraycopy(source,start+8,SSlideLayoutAtomData,0,12); System.arraycopy(source,start+8,SSlideLayoutAtomData,0,12);
// Use them to build up the SSlideLayoutAtom // Use them to build up the SSlideLayoutAtom
layoutAtom = new SSlideLayoutAtom(SSlideLayoutAtomData); layoutAtom = new SlideAtomLayout(SSlideLayoutAtomData);
// Get the IDs of the master and notes // Get the IDs of the master and notes
masterID = LittleEndian.getInt(source,start+12+8); masterID = LittleEndian.getInt(source,start+12+8);
@ -125,13 +123,13 @@ public final class SlideAtom extends RecordAtom
LittleEndian.putInt(_header, 4, 24); LittleEndian.putInt(_header, 4, 24);
byte[] ssdate = new byte[12]; byte[] ssdate = new byte[12];
layoutAtom = new SSlideLayoutAtom(ssdate); layoutAtom = new SlideAtomLayout(ssdate);
layoutAtom.setGeometryType(SSlideLayoutAtom.BLANK_SLIDE); layoutAtom.setGeometryType(SlideLayoutType.BLANK_SLIDE);
followMasterObjects = true; followMasterObjects = true;
followMasterScheme = true; followMasterScheme = true;
followMasterBackground = true; followMasterBackground = true;
masterID = -2147483648; masterID = USES_MASTER_SLIDE_ID; // -2147483648;
notesID = 0; notesID = 0;
reserved = new byte[2]; reserved = new byte[2];
} }
@ -168,70 +166,4 @@ public final class SlideAtom extends RecordAtom
// Reserved data // Reserved data
out.write(reserved); out.write(reserved);
} }
/**
* Holds the geometry of the Slide, and the ID of the placeholders
* on the slide.
* (Embeded inside SlideAtom is a SSlideLayoutAtom, without the
* usual record header. Since it's a fixed size and tied to
* the SlideAtom, we'll hold it here.)
*/
public static class SSlideLayoutAtom {
// The different kinds of geometry
public static final int TITLE_SLIDE = 0;
public static final int TITLE_BODY_SLIDE = 1;
public static final int TITLE_MASTER_SLIDE = 2;
public static final int MASTER_SLIDE = 3;
public static final int MASTER_NOTES = 4;
public static final int NOTES_TITLE_BODY = 5;
public static final int HANDOUT = 6; // Only header, footer and date placeholders
public static final int TITLE_ONLY = 7;
public static final int TITLE_2_COLUMN_BODY = 8;
public static final int TITLE_2_ROW_BODY = 9;
public static final int TITLE_2_COLUNM_RIGHT_2_ROW_BODY = 10;
public static final int TITLE_2_COLUNM_LEFT_2_ROW_BODY = 11;
public static final int TITLE_2_ROW_BOTTOM_2_COLUMN_BODY = 12;
public static final int TITLE_2_ROW_TOP_2_COLUMN_BODY = 13;
public static final int FOUR_OBJECTS = 14;
public static final int BIG_OBJECT = 15;
public static final int BLANK_SLIDE = 16;
public static final int VERTICAL_TITLE_BODY_LEFT = 17;
public static final int VERTICAL_TITLE_2_ROW_BODY_LEFT = 17;
/** What geometry type we are */
private int geometry;
/** What placeholder IDs we have */
private byte[] placeholderIDs;
/** Retrieve the geometry type */
public int getGeometryType() { return geometry; }
/** Set the geometry type */
public void setGeometryType(int geom) { geometry = geom; }
/**
* Create a new Embeded SSlideLayoutAtom, from 12 bytes of data
*/
public SSlideLayoutAtom(byte[] data) {
if(data.length != 12) {
throw new HSLFException("SSlideLayoutAtom created with byte array not 12 bytes long - was " + data.length + " bytes in size");
}
// Grab out our data
geometry = LittleEndian.getInt(data,0);
placeholderIDs = new byte[8];
System.arraycopy(data,4,placeholderIDs,0,8);
}
/**
* Write the contents of the record back, so it can be written
* to disk. Skips the record header
*/
public void writeOut(OutputStream out) throws IOException {
// Write the geometry
writeLittleEndian(geometry,out);
// Write the placeholder IDs
out.write(placeholderIDs);
}
}
} }

View File

@ -0,0 +1,133 @@
/* ====================================================================
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.hslf.record;
import java.io.IOException;
import java.io.OutputStream;
import org.apache.poi.hslf.exceptions.HSLFException;
import org.apache.poi.util.Internal;
import org.apache.poi.util.LittleEndian;
/**
* Holds the geometry of the Slide, and the ID of the placeholders on the slide.
* Embedded inside a SlideAtom is a SlideAtomLayout, without the usual record header.
* Since it's a fixed size and tied to the SlideAtom, we'll hold it here.<p>
*
* This might eventually merged with the XSLF counterpart
*/
@Internal
public class SlideAtomLayout {
// The different kinds of geometry
public enum SlideLayoutType {
/** One title and one subtitle placeholder shapes. */
TITLE_SLIDE(0x0000),
/** Presentation slide or main master slide layout with one title and one body placeholder shape. */
TITLE_BODY(0x0001),
/** Title master slide layout with one title and one subtitle placeholder shape. */
MASTER_TITLE(0x0002),
/** ??? (not documented in spec) */
MASTER_SLIDE(0x0003),
/** ??? (not documented in spec) */
MASTER_NOTES(0x0004),
/** ??? (not documented in spec) */
NOTES_TITLE_BODY(0x0005),
/** Only header, footer and date placeholders */
HANDOUT(0x0006),
/** Presentation slide layout with one title placeholder shape. */
TITLE_ONLY(0x0007),
/** Presentation slide layout with one title and two body placeholder shapes stacked horizontally. */
TWO_COLUMNS(0x0008),
/** Presentation slide layout with one title and two body placeholder shapes stacked vertically. */
TWO_ROWS(0x0009),
/** Presentation slide layout with one title and three body placeholder shapes split into two columns. The right column has two rows. */
COLUMN_TWO_ROWS(0x000A),
/** Presentation slide layout with one title and three body placeholder shapes split into two columns. The left column has two rows. */
TWO_ROWS_COLUMN(0x000B),
/** ??? (not documented in spec) */
TITLE_2_ROW_BOTTOM_2_COLUMN_BODY(0x000C),
/** Presentation slide layout with one title and three body placeholder shapes split into two rows. The top row has two columns. */
TWO_COLUMNS_ROW(0x000D),
/** Presentation slide layout with one title and four body placeholder shapes. */
FOUR_OBJECTS(0x000E),
/** Presentation slide layout with one body placeholder shape. */
BIG_OBJECT(0x000F),
/** Presentation slide layout with no placeholder shape. */
BLANK_SLIDE(0x0010),
/** Presentation slide layout with a vertical title placeholder shape on the right and a body placeholder shape on the left. */
VERTICAL_TITLE_BODY(0x0011),
/** Presentation slide layout with a vertical title placeholder shape on the right and two body placeholder shapes in two columns on the left. */
VERTICAL_TWO_ROWS(0x0012);
private int nativeId;
SlideLayoutType(int nativeId) {
this.nativeId = nativeId;
}
public int getNativeId() {
return nativeId;
}
public static SlideLayoutType forNativeID(int nativeId) {
for (SlideLayoutType ans : values()) {
if (ans.nativeId == nativeId) {
return ans;
}
}
return null;
}
}
/** What geometry type we are */
private SlideLayoutType geometry;
/** What placeholder IDs we have */
private byte[] placeholderIDs;
/** Retrieve the geometry type */
public SlideLayoutType getGeometryType() { return geometry; }
/** Set the geometry type */
public void setGeometryType(SlideLayoutType geom) { geometry = geom; }
/**
* Create a new Embedded SSlideLayoutAtom, from 12 bytes of data
*/
public SlideAtomLayout(byte[] data) {
if(data.length != 12) {
throw new HSLFException("SSlideLayoutAtom created with byte array not 12 bytes long - was " + data.length + " bytes in size");
}
// Grab out our data
geometry = SlideLayoutType.forNativeID(LittleEndian.getInt(data,0));
placeholderIDs = new byte[8];
System.arraycopy(data,4,placeholderIDs,0,8);
}
/**
* Write the contents of the record back, so it can be written
* to disk. Skips the record header
*/
public void writeOut(OutputStream out) throws IOException {
// Write the geometry
byte[] buf = new byte[4];
LittleEndian.putInt(buf, 0, geometry.getNativeId());
out.write(buf);
// Write the placeholder IDs
out.write(placeholderIDs);
}
}

View File

@ -42,15 +42,11 @@ import org.apache.poi.util.POILogger;
* the style applies to, and what style elements make up the style (another * the style applies to, and what style elements make up the style (another
* list, this time of TextProps). Each TextProp has a value, which somehow * list, this time of TextProps). Each TextProp has a value, which somehow
* encapsulates a property of the style * encapsulates a property of the style
*
* @author Nick Burch
* @author Yegor Kozlov
*/ */
public final class StyleTextPropAtom extends RecordAtom public final class StyleTextPropAtom extends RecordAtom {
{ public static final long _type = RecordTypes.StyleTextPropAtom.typeID;
private byte[] _header; private byte[] _header;
private static final long _type = RecordTypes.StyleTextPropAtom.typeID;
private byte[] reserved; private byte[] reserved;
private byte[] rawContents; // Holds the contents between write-outs private byte[] rawContents; // Holds the contents between write-outs

View File

@ -17,25 +17,23 @@
package org.apache.poi.hslf.record; package org.apache.poi.hslf.record;
import java.io.IOException;
import java.io.OutputStream;
import org.apache.poi.util.HexDump; import org.apache.poi.util.HexDump;
import org.apache.poi.util.LittleEndian; import org.apache.poi.util.LittleEndian;
import org.apache.poi.util.StringUtil; import org.apache.poi.util.StringUtil;
import java.io.IOException;
import java.io.OutputStream;
/** /**
* A TextBytesAtom (type 4008). Holds text in ascii form (unknown * A TextBytesAtom (type 4008). Holds text in ascii form (unknown
* code page, for now assumed to be the default of * code page, for now assumed to be the default of
* org.apache.poi.util.StringUtil, which is the Excel default). * org.apache.poi.util.StringUtil, which is the Excel default).
* The trailing return character is always stripped from this * The trailing return character is always stripped from this
*
* @author Nick Burch
*/ */
public final class TextBytesAtom extends RecordAtom public final class TextBytesAtom extends RecordAtom {
{ public static final long _type = RecordTypes.TextBytesAtom.typeID;
private byte[] _header; private byte[] _header;
private static long _type = RecordTypes.TextBytesAtom.typeID;
/** The bytes that make up the text */ /** The bytes that make up the text */
private byte[] _text; private byte[] _text;
@ -87,13 +85,15 @@ public final class TextBytesAtom extends RecordAtom
/** /**
* We are of type 4008 * We are of type 4008
*/ */
public long getRecordType() { return _type; } @Override
public long getRecordType() { return _type; }
/** /**
* Write the contents of the record back, so it can be written * Write the contents of the record back, so it can be written
* to disk * to disk
*/ */
public void writeOut(OutputStream out) throws IOException { @Override
public void writeOut(OutputStream out) throws IOException {
// Header - size or type unchanged // Header - size or type unchanged
out.write(_header); out.write(_header);
@ -105,7 +105,8 @@ public final class TextBytesAtom extends RecordAtom
* dump debug info; use getText() to return a string * dump debug info; use getText() to return a string
* representation of the atom * representation of the atom
*/ */
public String toString() { @Override
public String toString() {
StringBuffer out = new StringBuffer(); StringBuffer out = new StringBuffer();
out.append( "TextBytesAtom:\n"); out.append( "TextBytesAtom:\n");
out.append( HexDump.dump(_text, 0, 0) ); out.append( HexDump.dump(_text, 0, 0) );

View File

@ -17,23 +17,21 @@
package org.apache.poi.hslf.record; package org.apache.poi.hslf.record;
import java.io.IOException;
import java.io.OutputStream;
import org.apache.poi.util.HexDump; import org.apache.poi.util.HexDump;
import org.apache.poi.util.LittleEndian; import org.apache.poi.util.LittleEndian;
import org.apache.poi.util.StringUtil; import org.apache.poi.util.StringUtil;
import java.io.IOException;
import java.io.OutputStream;
/** /**
* A TextCharsAtom (type 4000). Holds text in byte swapped unicode form. * A TextCharsAtom (type 4000). Holds text in byte swapped unicode form.
* The trailing return character is always stripped from this * The trailing return character is always stripped from this
*
* @author Nick Burch
*/ */
public final class TextCharsAtom extends RecordAtom public final class TextCharsAtom extends RecordAtom {
{ public static final long _type = RecordTypes.TextCharsAtom.typeID;
private byte[] _header; private byte[] _header;
private static long _type = RecordTypes.TextCharsAtom.typeID;
/** The bytes that make up the text */ /** The bytes that make up the text */
private byte[] _text; private byte[] _text;
@ -83,13 +81,15 @@ public final class TextCharsAtom extends RecordAtom
/** /**
* We are of type 4000 * We are of type 4000
*/ */
public long getRecordType() { return _type; } @Override
public long getRecordType() { return _type; }
/** /**
* Write the contents of the record back, so it can be written * Write the contents of the record back, so it can be written
* to disk * to disk
*/ */
public void writeOut(OutputStream out) throws IOException { @Override
public void writeOut(OutputStream out) throws IOException {
// Header - size or type unchanged // Header - size or type unchanged
out.write(_header); out.write(_header);
@ -101,7 +101,8 @@ public final class TextCharsAtom extends RecordAtom
* dump debug info; use getText() to return a string * dump debug info; use getText() to return a string
* representation of the atom * representation of the atom
*/ */
public String toString() { @Override
public String toString() {
StringBuffer out = new StringBuffer(); StringBuffer out = new StringBuffer();
out.append( "TextCharsAtom:\n"); out.append( "TextCharsAtom:\n");
out.append( HexDump.dump(_text, 0, 0) ); out.append( HexDump.dump(_text, 0, 0) );

View File

@ -27,14 +27,11 @@ import org.apache.poi.util.LittleEndian;
* A TextHeaderAtom (type 3999). Holds information on what kind of * A TextHeaderAtom (type 3999). Holds information on what kind of
* text is contained in the TextBytesAtom / TextCharsAtom that follows * text is contained in the TextBytesAtom / TextCharsAtom that follows
* straight after * straight after
*
* @author Nick Burch
*/ */
public final class TextHeaderAtom extends RecordAtom implements ParentAwareRecord public final class TextHeaderAtom extends RecordAtom implements ParentAwareRecord {
{ public static final long _type = RecordTypes.TextHeaderAtom.typeID;
private byte[] _header; private byte[] _header;
private static long _type = RecordTypes.TextHeaderAtom.typeID;
private RecordContainer parentRecord; private RecordContainer parentRecord;
public static final int TITLE_TYPE = 0; public static final int TITLE_TYPE = 0;

View File

@ -30,15 +30,14 @@ import org.apache.poi.ddf.EscherRecord;
import org.apache.poi.hslf.exceptions.HSLFException; import org.apache.poi.hslf.exceptions.HSLFException;
import org.apache.poi.hslf.record.CString; import org.apache.poi.hslf.record.CString;
import org.apache.poi.hslf.record.ColorSchemeAtom; import org.apache.poi.hslf.record.ColorSchemeAtom;
import org.apache.poi.hslf.record.OEPlaceholderAtom;
import org.apache.poi.hslf.record.PPDrawing; import org.apache.poi.hslf.record.PPDrawing;
import org.apache.poi.hslf.record.RecordContainer; import org.apache.poi.hslf.record.RecordContainer;
import org.apache.poi.hslf.record.RecordTypes; import org.apache.poi.hslf.record.RecordTypes;
import org.apache.poi.hslf.record.RoundTripHFPlaceholder12;
import org.apache.poi.hslf.record.SheetContainer; import org.apache.poi.hslf.record.SheetContainer;
import org.apache.poi.sl.draw.DrawFactory; import org.apache.poi.sl.draw.DrawFactory;
import org.apache.poi.sl.draw.Drawable; import org.apache.poi.sl.draw.Drawable;
import org.apache.poi.sl.usermodel.PictureData; import org.apache.poi.sl.usermodel.PictureData;
import org.apache.poi.sl.usermodel.Placeholder;
import org.apache.poi.sl.usermodel.ShapeType; import org.apache.poi.sl.usermodel.ShapeType;
import org.apache.poi.sl.usermodel.Sheet; import org.apache.poi.sl.usermodel.Sheet;
import org.apache.poi.util.Internal; import org.apache.poi.util.Internal;
@ -108,6 +107,7 @@ public abstract class HSLFSheet implements HSLFShapeContainer, Sheet<HSLFShape,H
/** /**
* Fetch the SlideShow we're attached to * Fetch the SlideShow we're attached to
*/ */
@Override
public HSLFSlideShow getSlideShow() { public HSLFSlideShow getSlideShow() {
return _slideShow; return _slideShow;
} }
@ -131,7 +131,9 @@ public abstract class HSLFSheet implements HSLFShapeContainer, Sheet<HSLFShape,H
_slideShow = ss; _slideShow = ss;
List<List<HSLFTextParagraph>> trs = getTextParagraphs(); List<List<HSLFTextParagraph>> trs = getTextParagraphs();
if (trs == null) return; if (trs == null) {
return;
}
for (List<HSLFTextParagraph> ltp : trs) { for (List<HSLFTextParagraph> ltp : trs) {
HSLFTextParagraph.supplySheet(ltp, this); HSLFTextParagraph.supplySheet(ltp, this);
HSLFTextParagraph.applyHyperlinks(ltp); HSLFTextParagraph.applyHyperlinks(ltp);
@ -192,6 +194,7 @@ public abstract class HSLFSheet implements HSLFShapeContainer, Sheet<HSLFShape,H
* *
* @param shape - the Shape to add * @param shape - the Shape to add
*/ */
@Override
public void addShape(HSLFShape shape) { public void addShape(HSLFShape shape) {
PPDrawing ppdrawing = getPPDrawing(); PPDrawing ppdrawing = getPPDrawing();
@ -226,8 +229,9 @@ public abstract class HSLFSheet implements HSLFShapeContainer, Sheet<HSLFShape,H
c.incrementShapeId(); c.incrementShapeId();
dg.setNumShapes( dg.getNumShapes() + 1 ); dg.setNumShapes( dg.getNumShapes() + 1 );
dg.setLastMSOSPID( result ); dg.setLastMSOSPID( result );
if (result >= dgg.getShapeIdMax()) if (result >= dgg.getShapeIdMax()) {
dgg.setShapeIdMax( result + 1 ); dgg.setShapeIdMax( result + 1 );
}
return result; return result;
} }
} }
@ -238,8 +242,9 @@ public abstract class HSLFSheet implements HSLFShapeContainer, Sheet<HSLFShape,H
dg.setNumShapes( dg.getNumShapes() + 1 ); dg.setNumShapes( dg.getNumShapes() + 1 );
int result = (1024 * dgg.getFileIdClusters().length); int result = (1024 * dgg.getFileIdClusters().length);
dg.setLastMSOSPID( result ); dg.setLastMSOSPID( result );
if (result >= dgg.getShapeIdMax()) if (result >= dgg.getShapeIdMax()) {
dgg.setShapeIdMax( result + 1 ); dgg.setShapeIdMax( result + 1 );
}
return result; return result;
} }
@ -249,6 +254,7 @@ public abstract class HSLFSheet implements HSLFShapeContainer, Sheet<HSLFShape,H
* @param shape shape to be removed from this sheet, if present. * @param shape shape to be removed from this sheet, if present.
* @return <tt>true</tt> if the shape was deleted. * @return <tt>true</tt> if the shape was deleted.
*/ */
@Override
public boolean removeShape(HSLFShape shape) { public boolean removeShape(HSLFShape shape) {
PPDrawing ppdrawing = getPPDrawing(); PPDrawing ppdrawing = getPPDrawing();
@ -274,6 +280,7 @@ public abstract class HSLFSheet implements HSLFShapeContainer, Sheet<HSLFShape,H
/** /**
* Return the master sheet . * Return the master sheet .
*/ */
@Override
public abstract HSLFMasterSheet getMasterSheet(); public abstract HSLFMasterSheet getMasterSheet();
/** /**
@ -288,6 +295,7 @@ public abstract class HSLFSheet implements HSLFShapeContainer, Sheet<HSLFShape,H
* *
* @return the background shape for this sheet. * @return the background shape for this sheet.
*/ */
@Override
public HSLFBackground getBackground() { public HSLFBackground getBackground() {
if (_background == null) { if (_background == null) {
PPDrawing ppdrawing = getPPDrawing(); PPDrawing ppdrawing = getPPDrawing();
@ -335,26 +343,17 @@ public abstract class HSLFSheet implements HSLFShapeContainer, Sheet<HSLFShape,H
} }
/** /**
* Search text placeholer by its type * Search placeholder by its type
* *
* @param type type of placeholder to search. See {@link org.apache.poi.hslf.record.OEPlaceholderAtom} * @param type type of placeholder to search. See {@link org.apache.poi.hslf.record.OEPlaceholderAtom}
* @return <code>TextShape</code> or <code>null</code> * @return {@code SimpleShape} or {@code null}
*/ */
public HSLFTextShape getPlaceholder(int type){ public HSLFSimpleShape getPlaceholder(Placeholder type){
for (HSLFShape shape : getShapes()) { for (HSLFShape shape : getShapes()) {
if(shape instanceof HSLFTextShape){ if (shape instanceof HSLFSimpleShape) {
HSLFTextShape tx = (HSLFTextShape)shape; HSLFSimpleShape ss = (HSLFSimpleShape)shape;
int placeholderId = 0; if (type == ss.getPlaceholder()) {
OEPlaceholderAtom oep = tx.getPlaceholderAtom(); return ss;
if(oep != null) {
placeholderId = oep.getPlaceholderId();
} else {
//special case for files saved in Office 2007
RoundTripHFPlaceholder12 hldr = tx.getClientDataRecord(RecordTypes.RoundTripHFPlaceholder12.typeID);
if(hldr != null) placeholderId = hldr.getPlaceholderId();
}
if(placeholderId == type){
return tx;
} }
} }
} }
@ -382,7 +381,9 @@ public abstract class HSLFSheet implements HSLFShapeContainer, Sheet<HSLFShape,H
progBinaryTag.findFirstOfType( progBinaryTag.findFirstOfType(
RecordTypes.CString.typeID RecordTypes.CString.typeID
); );
if(binaryTag != null) tag = binaryTag.getText(); if(binaryTag != null) {
tag = binaryTag.getText();
}
} }
} }
@ -390,6 +391,7 @@ public abstract class HSLFSheet implements HSLFShapeContainer, Sheet<HSLFShape,H
} }
@Override
public Iterator<HSLFShape> iterator() { public Iterator<HSLFShape> iterator() {
return getShapes().iterator(); return getShapes().iterator();
} }
@ -400,6 +402,7 @@ public abstract class HSLFSheet implements HSLFShapeContainer, Sheet<HSLFShape,H
* Sheets that support the notion of master (slide, slideLayout) should override it and * Sheets that support the notion of master (slide, slideLayout) should override it and
* check this setting * check this setting
*/ */
@Override
public boolean getFollowMasterGraphics() { public boolean getFollowMasterGraphics() {
return false; return false;
} }

View File

@ -42,6 +42,7 @@ import org.apache.poi.sl.draw.geom.PresetGeometries;
import org.apache.poi.sl.usermodel.LineDecoration; import org.apache.poi.sl.usermodel.LineDecoration;
import org.apache.poi.sl.usermodel.LineDecoration.DecorationShape; import org.apache.poi.sl.usermodel.LineDecoration.DecorationShape;
import org.apache.poi.sl.usermodel.LineDecoration.DecorationSize; import org.apache.poi.sl.usermodel.LineDecoration.DecorationSize;
import org.apache.poi.sl.usermodel.MasterSheet;
import org.apache.poi.sl.usermodel.PaintStyle; import org.apache.poi.sl.usermodel.PaintStyle;
import org.apache.poi.sl.usermodel.PaintStyle.SolidPaint; import org.apache.poi.sl.usermodel.PaintStyle.SolidPaint;
import org.apache.poi.sl.usermodel.Placeholder; import org.apache.poi.sl.usermodel.Placeholder;
@ -546,13 +547,40 @@ public abstract class HSLFSimpleShape extends HSLFShape implements SimpleShape<H
if (clRecords == null) { if (clRecords == null) {
return null; return null;
} }
int phSource;
HSLFSheet sheet = getSheet();
if (sheet instanceof HSLFSlideMaster) {
phSource = 1;
} else if (sheet instanceof HSLFNotes) {
phSource = 2;
} else if (sheet instanceof MasterSheet) {
// notes master aren't yet supported ...
phSource = 3;
} else {
phSource = 0;
}
for (Record r : clRecords) { for (Record r : clRecords) {
int phId;
if (r instanceof OEPlaceholderAtom) { if (r instanceof OEPlaceholderAtom) {
OEPlaceholderAtom oep = (OEPlaceholderAtom)r; phId = ((OEPlaceholderAtom)r).getPlaceholderId();
return Placeholder.lookupNative(oep.getPlaceholderId());
} else if (r instanceof RoundTripHFPlaceholder12) { } else if (r instanceof RoundTripHFPlaceholder12) {
RoundTripHFPlaceholder12 rtp = (RoundTripHFPlaceholder12)r; //special case for files saved in Office 2007
return Placeholder.lookupNative(rtp.getPlaceholderId()); phId = ((RoundTripHFPlaceholder12)r).getPlaceholderId();
} else {
continue;
}
switch (phSource) {
case 0:
return Placeholder.lookupNativeSlide(phId);
default:
case 1:
return Placeholder.lookupNativeSlideMaster(phId);
case 2:
return Placeholder.lookupNativeNotes(phId);
case 3:
return Placeholder.lookupNativeNotesMaster(phId);
} }
} }

View File

@ -36,6 +36,7 @@ import org.apache.poi.hslf.record.RecordContainer;
import org.apache.poi.hslf.record.RecordTypes; import org.apache.poi.hslf.record.RecordTypes;
import org.apache.poi.hslf.record.SSSlideInfoAtom; import org.apache.poi.hslf.record.SSSlideInfoAtom;
import org.apache.poi.hslf.record.SlideAtom; import org.apache.poi.hslf.record.SlideAtom;
import org.apache.poi.hslf.record.SlideAtomLayout.SlideLayoutType;
import org.apache.poi.hslf.record.SlideListWithText.SlideAtomsSet; import org.apache.poi.hslf.record.SlideListWithText.SlideAtomsSet;
import org.apache.poi.hslf.record.StyleTextProp9Atom; import org.apache.poi.hslf.record.StyleTextProp9Atom;
import org.apache.poi.hslf.record.TextHeaderAtom; import org.apache.poi.hslf.record.TextHeaderAtom;
@ -501,4 +502,27 @@ public final class HSLFSlide extends HSLFSheet implements Slide<HSLFShape,HSLFTe
public boolean getFollowMasterGraphics() { public boolean getFollowMasterGraphics() {
return getFollowMasterObjects(); return getFollowMasterObjects();
} }
@Override
public boolean getDisplayPlaceholder(Placeholder placeholder) {
HeadersFooters hf = getHeadersFooters();
SlideLayoutType slt = getSlideRecord().getSlideAtom().getSSlideLayoutAtom().getGeometryType();
boolean isTitle =
(slt == SlideLayoutType.TITLE_SLIDE || slt == SlideLayoutType.TITLE_ONLY || slt == SlideLayoutType.MASTER_TITLE);
if (hf != null) {
switch (placeholder) {
case DATETIME:
return hf.isDateTimeVisible() && !isTitle;
case SLIDE_NUMBER:
return hf.isSlideNumberVisible() && !isTitle;
case HEADER:
return hf.isHeaderVisible() && !isTitle;
case FOOTER:
return hf.isFooterVisible() && !isTitle;
default:
break;
}
}
return false;
}
} }

View File

@ -23,7 +23,9 @@ import java.util.List;
import org.apache.poi.hslf.exceptions.HSLFException; import org.apache.poi.hslf.exceptions.HSLFException;
import org.apache.poi.hslf.model.textproperties.TextProp; import org.apache.poi.hslf.model.textproperties.TextProp;
import org.apache.poi.hslf.model.textproperties.TextPropCollection; import org.apache.poi.hslf.model.textproperties.TextPropCollection;
import org.apache.poi.hslf.record.*; import org.apache.poi.hslf.record.MainMaster;
import org.apache.poi.hslf.record.TextHeaderAtom;
import org.apache.poi.hslf.record.TxMasterStyleAtom;
import org.apache.poi.util.Internal; import org.apache.poi.util.Internal;
/** /**
@ -49,13 +51,16 @@ public final class HSLFSlideMaster extends HSLFMasterSheet {
super(record, sheetNo); super(record, sheetNo);
for (List<HSLFTextParagraph> l : HSLFTextParagraph.findTextParagraphs(getPPDrawing(), this)) { for (List<HSLFTextParagraph> l : HSLFTextParagraph.findTextParagraphs(getPPDrawing(), this)) {
if (!_paragraphs.contains(l)) _paragraphs.add(l); if (!_paragraphs.contains(l)) {
_paragraphs.add(l);
}
} }
} }
/** /**
* Returns an array of all the TextRuns found * Returns an array of all the TextRuns found
*/ */
@Override
public List<List<HSLFTextParagraph>> getTextParagraphs() { public List<List<HSLFTextParagraph>> getTextParagraphs() {
return _paragraphs; return _paragraphs;
} }
@ -63,6 +68,7 @@ public final class HSLFSlideMaster extends HSLFMasterSheet {
/** /**
* Returns <code>null</code> since SlideMasters doen't have master sheet. * Returns <code>null</code> since SlideMasters doen't have master sheet.
*/ */
@Override
public HSLFMasterSheet getMasterSheet() { public HSLFMasterSheet getMasterSheet() {
return null; return null;
} }
@ -71,8 +77,11 @@ public final class HSLFSlideMaster extends HSLFMasterSheet {
* Pickup a style attribute from the master. * Pickup a style attribute from the master.
* This is the "workhorse" which returns the default style attributes. * This is the "workhorse" which returns the default style attributes.
*/ */
@Override
public TextProp getStyleAttribute(int txtype, int level, String name, boolean isCharacter) { public TextProp getStyleAttribute(int txtype, int level, String name, boolean isCharacter) {
if (_txmaster.length <= txtype) return null; if (_txmaster.length <= txtype) {
return null;
}
TxMasterStyleAtom t = _txmaster[txtype]; TxMasterStyleAtom t = _txmaster[txtype];
List<TextPropCollection> styles = isCharacter ? t.getCharacterStyles() : t.getParagraphStyles(); List<TextPropCollection> styles = isCharacter ? t.getCharacterStyles() : t.getParagraphStyles();
@ -81,7 +90,9 @@ public final class HSLFSlideMaster extends HSLFMasterSheet {
prop = styles.get(i).findByName(name); prop = styles.get(i).findByName(name);
} }
if (prop != null) return prop; if (prop != null) {
return prop;
}
switch (txtype) { switch (txtype) {
case TextHeaderAtom.CENTRE_BODY_TYPE: case TextHeaderAtom.CENTRE_BODY_TYPE:
@ -146,6 +157,7 @@ public final class HSLFSlideMaster extends HSLFMasterSheet {
} }
} }
@Override
protected void onAddTextShape(HSLFTextShape shape) { protected void onAddTextShape(HSLFTextShape shape) {
List<HSLFTextParagraph> runs = shape.getTextParagraphs(); List<HSLFTextParagraph> runs = shape.getTextParagraphs();
_paragraphs.add(runs); _paragraphs.add(runs);

View File

@ -36,14 +36,35 @@ import org.apache.poi.hslf.model.textproperties.TextPFException9;
import org.apache.poi.hslf.model.textproperties.TextProp; import org.apache.poi.hslf.model.textproperties.TextProp;
import org.apache.poi.hslf.model.textproperties.TextPropCollection; import org.apache.poi.hslf.model.textproperties.TextPropCollection;
import org.apache.poi.hslf.model.textproperties.TextPropCollection.TextPropType; import org.apache.poi.hslf.model.textproperties.TextPropCollection.TextPropType;
import org.apache.poi.hslf.record.*; import org.apache.poi.hslf.record.ColorSchemeAtom;
import org.apache.poi.hslf.record.EscherTextboxWrapper;
import org.apache.poi.hslf.record.FontCollection;
import org.apache.poi.hslf.record.InteractiveInfo;
import org.apache.poi.hslf.record.MasterTextPropAtom;
import org.apache.poi.hslf.record.OutlineTextRefAtom;
import org.apache.poi.hslf.record.PPDrawing;
import org.apache.poi.hslf.record.Record;
import org.apache.poi.hslf.record.RecordContainer;
import org.apache.poi.hslf.record.RecordTypes;
import org.apache.poi.hslf.record.RoundTripHFPlaceholder12;
import org.apache.poi.hslf.record.SlideListWithText;
import org.apache.poi.hslf.record.SlidePersistAtom;
import org.apache.poi.hslf.record.StyleTextProp9Atom;
import org.apache.poi.hslf.record.StyleTextPropAtom;
import org.apache.poi.hslf.record.TextBytesAtom;
import org.apache.poi.hslf.record.TextCharsAtom;
import org.apache.poi.hslf.record.TextHeaderAtom;
import org.apache.poi.hslf.record.TextRulerAtom;
import org.apache.poi.hslf.record.TextSpecInfoAtom;
import org.apache.poi.hslf.record.TxInteractiveInfoAtom;
import org.apache.poi.sl.draw.DrawPaint; import org.apache.poi.sl.draw.DrawPaint;
import org.apache.poi.sl.usermodel.AutoNumberingScheme; import org.apache.poi.sl.usermodel.AutoNumberingScheme;
import org.apache.poi.sl.usermodel.MasterSheet;
import org.apache.poi.sl.usermodel.PaintStyle; import org.apache.poi.sl.usermodel.PaintStyle;
import org.apache.poi.sl.usermodel.PaintStyle.SolidPaint; import org.apache.poi.sl.usermodel.PaintStyle.SolidPaint;
import org.apache.poi.sl.usermodel.Placeholder;
import org.apache.poi.sl.usermodel.TextParagraph; import org.apache.poi.sl.usermodel.TextParagraph;
import org.apache.poi.util.Internal; import org.apache.poi.util.Internal;
import org.apache.poi.util.LocaleUtil;
import org.apache.poi.util.POILogFactory; import org.apache.poi.util.POILogFactory;
import org.apache.poi.util.POILogger; import org.apache.poi.util.POILogger;
import org.apache.poi.util.StringUtil; import org.apache.poi.util.StringUtil;
@ -53,8 +74,6 @@ import org.apache.poi.util.Units;
* This class represents a run of text in a powerpoint document. That * This class represents a run of text in a powerpoint document. That
* run could be text on a sheet, or text in a note. * run could be text on a sheet, or text in a note.
* It is only a very basic class for now * It is only a very basic class for now
*
* @author Nick Burch
*/ */
public final class HSLFTextParagraph implements TextParagraph<HSLFShape,HSLFTextParagraph,HSLFTextRun> { public final class HSLFTextParagraph implements TextParagraph<HSLFShape,HSLFTextParagraph,HSLFTextRun> {
@ -74,6 +93,7 @@ public final class HSLFTextParagraph implements TextParagraph<HSLFShape,HSLFText
private TextBytesAtom _byteAtom; private TextBytesAtom _byteAtom;
private TextCharsAtom _charAtom; private TextCharsAtom _charAtom;
private TextPropCollection _paragraphStyle = new TextPropCollection(1, TextPropType.paragraph); private TextPropCollection _paragraphStyle = new TextPropCollection(1, TextPropType.paragraph);
private TextPropCollection _masterStyle;
protected TextRulerAtom _ruler; protected TextRulerAtom _ruler;
protected final List<HSLFTextRun> _runs = new ArrayList<HSLFTextRun>(); protected final List<HSLFTextRun> _runs = new ArrayList<HSLFTextRun>();
@ -139,7 +159,7 @@ public final class HSLFTextParagraph implements TextParagraph<HSLFShape,HSLFText
public void setParagraphStyle(TextPropCollection paragraphStyle) { public void setParagraphStyle(TextPropCollection paragraphStyle) {
_paragraphStyle.copy(paragraphStyle); _paragraphStyle.copy(paragraphStyle);
} }
/** /**
* Setting a master style reference * Setting a master style reference
* *
@ -148,8 +168,8 @@ public final class HSLFTextParagraph implements TextParagraph<HSLFShape,HSLFText
* @since POI 3.14-Beta1 * @since POI 3.14-Beta1
*/ */
@Internal @Internal
/* package */ void setMasterStyleReference(TextPropCollection paragraphStyle) { /* package */ void setMasterStyleReference(TextPropCollection masterStyle) {
_paragraphStyle = paragraphStyle; _masterStyle = masterStyle;
} }
/** /**
@ -321,8 +341,8 @@ public final class HSLFTextParagraph implements TextParagraph<HSLFShape,HSLFText
@Override @Override
public Double getLeftMargin() { public Double getLeftMargin() {
TextProp val = getPropVal(_paragraphStyle, "text.offset", this); TextProp tp = getPropVal(_paragraphStyle, _masterStyle, "text.offset");
return (val == null) ? null : Units.masterToPoints(val.getValue()); return (tp == null) ? null : Units.masterToPoints(tp.getValue());
} }
@Override @Override
@ -344,8 +364,8 @@ public final class HSLFTextParagraph implements TextParagraph<HSLFShape,HSLFText
@Override @Override
public Double getIndent() { public Double getIndent() {
TextProp val = getPropVal(_paragraphStyle, "bullet.offset", this); TextProp tp = getPropVal(_paragraphStyle, _masterStyle, "bullet.offset");
return (val == null) ? null : Units.masterToPoints(val.getValue()); return (tp == null) ? null : Units.masterToPoints(tp.getValue());
} }
@Override @Override
@ -393,7 +413,7 @@ public final class HSLFTextParagraph implements TextParagraph<HSLFShape,HSLFText
@Override @Override
public TextAlign getTextAlign() { public TextAlign getTextAlign() {
TextProp tp = getPropVal(_paragraphStyle, "alignment", this); TextProp tp = getPropVal(_paragraphStyle, _masterStyle, "alignment");
if (tp == null) { if (tp == null) {
return null; return null;
} }
@ -411,7 +431,7 @@ public final class HSLFTextParagraph implements TextParagraph<HSLFShape,HSLFText
@Override @Override
public FontAlign getFontAlign() { public FontAlign getFontAlign() {
TextProp tp = getPropVal(_paragraphStyle, FontAlignmentProp.NAME, this); TextProp tp = getPropVal(_paragraphStyle, _masterStyle, FontAlignmentProp.NAME);
if (tp == null) { if (tp == null) {
return null; return null;
} }
@ -577,7 +597,7 @@ public final class HSLFTextParagraph implements TextParagraph<HSLFShape,HSLFText
* Returns the bullet character * Returns the bullet character
*/ */
public Character getBulletChar() { public Character getBulletChar() {
TextProp tp = getPropVal(_paragraphStyle, "bullet.char", this); TextProp tp = getPropVal(_paragraphStyle, _masterStyle, "bullet.char");
return (tp == null) ? null : (char)tp.getValue(); return (tp == null) ? null : (char)tp.getValue();
} }
@ -608,7 +628,7 @@ public final class HSLFTextParagraph implements TextParagraph<HSLFShape,HSLFText
* Returns the bullet color * Returns the bullet color
*/ */
public Color getBulletColor() { public Color getBulletColor() {
TextProp tp = getPropVal(_paragraphStyle, "bullet.color", this); TextProp tp = getPropVal(_paragraphStyle, _masterStyle, "bullet.color");
boolean hasColor = getFlag(ParagraphFlagsTextProp.BULLET_HARDCOLOR_IDX); boolean hasColor = getFlag(ParagraphFlagsTextProp.BULLET_HARDCOLOR_IDX);
if (tp == null || !hasColor) { if (tp == null || !hasColor) {
// if bullet color is undefined, return color of first run // if bullet color is undefined, return color of first run
@ -632,8 +652,9 @@ public final class HSLFTextParagraph implements TextParagraph<HSLFShape,HSLFText
*/ */
public void setBulletFont(String typeface) { public void setBulletFont(String typeface) {
if (typeface == null) { if (typeface == null) {
setPropVal(_paragraphStyle, "bullet.font", null); setPropVal(_paragraphStyle, _masterStyle, "bullet.font", null);
setFlag(ParagraphFlagsTextProp.BULLET_HARDFONT_IDX, false); setFlag(ParagraphFlagsTextProp.BULLET_HARDFONT_IDX, false);
return;
} }
FontCollection fc = getSheet().getSlideShow().getFontCollection(); FontCollection fc = getSheet().getSlideShow().getFontCollection();
@ -647,7 +668,7 @@ public final class HSLFTextParagraph implements TextParagraph<HSLFShape,HSLFText
* Returns the bullet font * Returns the bullet font
*/ */
public String getBulletFont() { public String getBulletFont() {
TextProp tp = getPropVal(_paragraphStyle, "bullet.font", this); TextProp tp = getPropVal(_paragraphStyle, _masterStyle, "bullet.font");
boolean hasFont = getFlag(ParagraphFlagsTextProp.BULLET_HARDFONT_IDX); boolean hasFont = getFlag(ParagraphFlagsTextProp.BULLET_HARDFONT_IDX);
if (tp == null || !hasFont) { if (tp == null || !hasFont) {
return getDefaultFontFamily(); return getDefaultFontFamily();
@ -694,7 +715,7 @@ public final class HSLFTextParagraph implements TextParagraph<HSLFShape,HSLFText
} }
private Double getPctOrPoints(String propName) { private Double getPctOrPoints(String propName) {
TextProp tp = getPropVal(_paragraphStyle, propName, this); TextProp tp = getPropVal(_paragraphStyle, _masterStyle, propName);
if (tp == null) { if (tp == null) {
return null; return null;
} }
@ -711,7 +732,7 @@ public final class HSLFTextParagraph implements TextParagraph<HSLFShape,HSLFText
} }
private boolean getFlag(int index) { private boolean getFlag(int index) {
BitMaskTextProp tp = (BitMaskTextProp)getPropVal(_paragraphStyle, ParagraphFlagsTextProp.NAME, this); BitMaskTextProp tp = (BitMaskTextProp)getPropVal(_paragraphStyle, _masterStyle, ParagraphFlagsTextProp.NAME);
return (tp == null) ? false : tp.getSubValue(index); return (tp == null) ? false : tp.getSubValue(index);
} }
@ -729,7 +750,7 @@ public final class HSLFTextParagraph implements TextParagraph<HSLFShape,HSLFText
* The propName can be a comma-separated list, in case multiple equivalent values * The propName can be a comma-separated list, in case multiple equivalent values
* are queried * are queried
*/ */
protected static TextProp getPropVal(TextPropCollection props, String propName, HSLFTextParagraph paragraph) { protected TextProp getPropVal(TextPropCollection props, TextPropCollection masterProps, String propName) {
String propNames[] = propName.split(","); String propNames[] = propName.split(",");
for (String pn : propNames) { for (String pn : propNames) {
TextProp prop = props.findByName(pn); TextProp prop = props.findByName(pn);
@ -740,41 +761,52 @@ public final class HSLFTextParagraph implements TextParagraph<HSLFShape,HSLFText
// Font properties (maybe other too???) can have an index of -1 // Font properties (maybe other too???) can have an index of -1
// so we check the master for this font index then // so we check the master for this font index then
if (pn.contains("font") && prop.getValue() == -1) { if (pn.contains("font") && prop.getValue() == -1) {
return getMasterPropVal(props, pn, paragraph); return getMasterPropVal(props, masterProps, pn);
} }
return prop; return prop;
} }
return getMasterPropVal(props, propName, paragraph); return getMasterPropVal(props, masterProps, propName);
} }
private static TextProp getMasterPropVal(TextPropCollection props, String propName, HSLFTextParagraph paragraph) { private TextProp getMasterPropVal(TextPropCollection props, TextPropCollection masterProps, String propName) {
String propNames[] = propName.split(",");
BitMaskTextProp maskProp = (BitMaskTextProp) props.findByName(ParagraphFlagsTextProp.NAME);
boolean hardAttribute = (maskProp != null && maskProp.getValue() == 0);
if (hardAttribute) {
return null;
}
HSLFSheet sheet = paragraph.getSheet();
int txtype = paragraph.getRunType();
HSLFMasterSheet master = sheet.getMasterSheet();
if (master == null) {
logger.log(POILogger.WARN, "MasterSheet is not available");
return null;
}
boolean isChar = props.getTextPropType() == TextPropType.character; boolean isChar = props.getTextPropType() == TextPropType.character;
for (String pn : propNames) { // check if we can delegate to master for the property
TextProp prop = master.getStyleAttribute(txtype, paragraph.getIndentLevel(), pn, isChar); if (!isChar) {
if (prop != null) { BitMaskTextProp maskProp = (BitMaskTextProp) props.findByName(ParagraphFlagsTextProp.NAME);
return prop; boolean hardAttribute = (maskProp != null && maskProp.getValue() == 0);
if (hardAttribute) {
return null;
} }
} }
String propNames[] = propName.split(",");
if (masterProps == null) {
HSLFSheet sheet = getSheet();
int txtype = getRunType();
HSLFMasterSheet master = sheet.getMasterSheet();
if (master == null) {
logger.log(POILogger.WARN, "MasterSheet is not available");
return null;
}
for (String pn : propNames) {
TextProp prop = master.getStyleAttribute(txtype, getIndentLevel(), pn, isChar);
if (prop != null) {
return prop;
}
}
} else {
for (String pn : propNames) {
TextProp prop = masterProps.findByName(pn);
if (prop != null) {
return prop;
}
}
}
return null; return null;
} }
@ -786,14 +818,19 @@ public final class HSLFTextParagraph implements TextParagraph<HSLFShape,HSLFText
* @param name the name of the TextProp to fetch/add * @param name the name of the TextProp to fetch/add
* @param val the value, null if unset * @param val the value, null if unset
*/ */
protected static void setPropVal(TextPropCollection props, String name, Integer val) { protected void setPropVal(TextPropCollection props, TextPropCollection masterProps, String name, Integer val) {
TextPropCollection pc = props;
if (getSheet() instanceof MasterSheet && masterProps != null) {
pc = masterProps;
}
if (val == null) { if (val == null) {
props.removeByName(name); pc.removeByName(name);
return; return;
} }
// Fetch / Add the TextProp // Fetch / Add the TextProp
TextProp tp = props.addWithName(name); TextProp tp = pc.addWithName(name);
tp.setValue(val); tp.setValue(val);
} }
@ -1517,38 +1554,6 @@ public final class HSLFTextParagraph implements TextParagraph<HSLFShape,HSLFText
} }
} }
protected static List<HSLFTextParagraph> createEmptyParagraph() {
EscherTextboxWrapper wrapper = new EscherTextboxWrapper();
return createEmptyParagraph(wrapper);
}
protected static List<HSLFTextParagraph> createEmptyParagraph(EscherTextboxWrapper wrapper) {
TextHeaderAtom tha = new TextHeaderAtom();
tha.setParentRecord(wrapper);
wrapper.appendChildRecord(tha);
TextBytesAtom tba = new TextBytesAtom();
tba.setText("".getBytes(LocaleUtil.CHARSET_1252));
wrapper.appendChildRecord(tba);
StyleTextPropAtom sta = new StyleTextPropAtom(1);
TextPropCollection paraStyle = sta.addParagraphTextPropCollection(1);
TextPropCollection charStyle = sta.addCharacterTextPropCollection(1);
wrapper.appendChildRecord(sta);
List<HSLFTextParagraph> paragraphs = new ArrayList<HSLFTextParagraph>(1);
HSLFTextParagraph htp = new HSLFTextParagraph(tha, tba, null, paragraphs);
htp.setParagraphStyle(paraStyle);
paragraphs.add(htp);
HSLFTextRun htr = new HSLFTextRun(htp);
htr.setCharacterStyle(charStyle);
htr.setText("");
htp.addTextRun(htr);
return paragraphs;
}
public EscherTextboxWrapper getTextboxWrapper() { public EscherTextboxWrapper getTextboxWrapper() {
return (EscherTextboxWrapper) _headerAtom.getParentRecord(); return (EscherTextboxWrapper) _headerAtom.getParentRecord();
} }
@ -1583,7 +1588,7 @@ public final class HSLFTextParagraph implements TextParagraph<HSLFShape,HSLFText
* @param val The value to set for the TextProp * @param val The value to set for the TextProp
*/ */
public void setParagraphTextPropVal(String propName, Integer val) { public void setParagraphTextPropVal(String propName, Integer val) {
setPropVal(_paragraphStyle, propName, val); setPropVal(_paragraphStyle, _masterStyle, propName, val);
setDirty(); setDirty();
} }
@ -1624,21 +1629,19 @@ public final class HSLFTextParagraph implements TextParagraph<HSLFShape,HSLFText
*/ */
@Override @Override
public boolean isHeaderOrFooter() { public boolean isHeaderOrFooter() {
HSLFShape s = getParentShape(); HSLFTextShape s = getParentShape();
if (s == null) { if (s == null) {
return false; return false;
} }
RoundTripHFPlaceholder12 hfPl = s.getClientDataRecord(RecordTypes.RoundTripHFPlaceholder12.typeID); Placeholder ph = s.getPlaceholder();
if (hfPl == null) { if (ph == null) {
return false; return false;
} }
switch (ph) {
int plId = hfPl.getPlaceholderId(); case DATETIME:
switch (plId) { case SLIDE_NUMBER:
case OEPlaceholderAtom.MasterDate: case FOOTER:
case OEPlaceholderAtom.MasterSlideNumber: case HEADER:
case OEPlaceholderAtom.MasterFooter:
case OEPlaceholderAtom.MasterHeader:
return true; return true;
default: default:
return false; return false;

View File

@ -17,8 +17,6 @@
package org.apache.poi.hslf.usermodel; package org.apache.poi.hslf.usermodel;
import static org.apache.poi.hslf.usermodel.HSLFTextParagraph.getPropVal;
import java.awt.Color; import java.awt.Color;
import org.apache.poi.hslf.exceptions.HSLFException; import org.apache.poi.hslf.exceptions.HSLFException;
@ -30,6 +28,7 @@ import org.apache.poi.hslf.model.textproperties.TextPropCollection.TextPropType;
import org.apache.poi.sl.draw.DrawPaint; import org.apache.poi.sl.draw.DrawPaint;
import org.apache.poi.sl.usermodel.PaintStyle; import org.apache.poi.sl.usermodel.PaintStyle;
import org.apache.poi.sl.usermodel.PaintStyle.SolidPaint; import org.apache.poi.sl.usermodel.PaintStyle.SolidPaint;
import org.apache.poi.sl.usermodel.Placeholder;
import org.apache.poi.sl.usermodel.TextRun; import org.apache.poi.sl.usermodel.TextRun;
import org.apache.poi.util.Internal; import org.apache.poi.util.Internal;
import org.apache.poi.util.POILogFactory; import org.apache.poi.util.POILogFactory;
@ -54,6 +53,8 @@ public final class HSLFTextRun implements TextRun {
* Note - we may share these styles with other RichTextRuns * Note - we may share these styles with other RichTextRuns
*/ */
private TextPropCollection characterStyle = new TextPropCollection(1, TextPropType.character); private TextPropCollection characterStyle = new TextPropCollection(1, TextPropType.character);
private TextPropCollection masterStyle;
/** /**
* Create a new wrapper around a rich text string * Create a new wrapper around a rich text string
@ -80,8 +81,8 @@ public final class HSLFTextRun implements TextRun {
* @since POI 3.14-Beta1 * @since POI 3.14-Beta1
*/ */
@Internal @Internal
/* package */ void setMasterStyleReference(TextPropCollection characterStyle) { /* package */ void setMasterStyleReference(TextPropCollection masterStyle) {
this.characterStyle = characterStyle; this.masterStyle = masterStyle;
} }
@ -105,14 +106,16 @@ public final class HSLFTextRun implements TextRun {
/** /**
* Fetch the text, in raw storage form * Fetch the text, in raw storage form
*/ */
public String getRawText() { @Override
public String getRawText() {
return _runText; return _runText;
} }
/** /**
* Change the text * Change the text
*/ */
public void setText(String text) { @Override
public void setText(String text) {
if (text == null) { if (text == null) {
throw new HSLFException("text must not be null"); throw new HSLFException("text must not be null");
} }
@ -137,7 +140,9 @@ public final class HSLFTextRun implements TextRun {
} }
protected boolean getFlag(int index) { protected boolean getFlag(int index) {
if (characterStyle == null) return false; if (characterStyle == null) {
return false;
}
BitMaskTextProp prop = (BitMaskTextProp)characterStyle.findByName(CharFlagsTextProp.NAME); BitMaskTextProp prop = (BitMaskTextProp)characterStyle.findByName(CharFlagsTextProp.NAME);
@ -175,8 +180,8 @@ public final class HSLFTextRun implements TextRun {
* @param val The value to set for the TextProp * @param val The value to set for the TextProp
*/ */
public void setCharTextPropVal(String propName, Integer val) { public void setCharTextPropVal(String propName, Integer val) {
HSLFTextParagraph.setPropVal(characterStyle, propName, val); getTextParagraph().setPropVal(characterStyle, masterStyle, propName, val);
parentParagraph.setDirty(); getTextParagraph().setDirty();
} }
@ -256,7 +261,7 @@ public final class HSLFTextRun implements TextRun {
* @return the percentage of the font size. If the value is positive, it is superscript, otherwise it is subscript * @return the percentage of the font size. If the value is positive, it is superscript, otherwise it is subscript
*/ */
public int getSuperscript() { public int getSuperscript() {
TextProp tp = getPropVal(characterStyle, "superscript", parentParagraph); TextProp tp = getTextParagraph().getPropVal(characterStyle, masterStyle, "superscript");
return tp == null ? 0 : tp.getValue(); return tp == null ? 0 : tp.getValue();
} }
@ -271,7 +276,7 @@ public final class HSLFTextRun implements TextRun {
@Override @Override
public Double getFontSize() { public Double getFontSize() {
TextProp tp = getPropVal(characterStyle, "font.size", parentParagraph); TextProp tp = getTextParagraph().getPropVal(characterStyle, masterStyle, "font.size");
return tp == null ? null : (double)tp.getValue(); return tp == null ? null : (double)tp.getValue();
} }
@ -286,7 +291,7 @@ public final class HSLFTextRun implements TextRun {
* Gets the font index * Gets the font index
*/ */
public int getFontIndex() { public int getFontIndex() {
TextProp tp = getPropVal(characterStyle, "font.index", parentParagraph); TextProp tp = getTextParagraph().getPropVal(characterStyle, masterStyle, "font.index");
return tp == null ? -1 : tp.getValue(); return tp == null ? -1 : tp.getValue();
} }
@ -320,7 +325,7 @@ public final class HSLFTextRun implements TextRun {
if (sheet == null || slideShow == null) { if (sheet == null || slideShow == null) {
return _fontFamily; return _fontFamily;
} }
TextProp tp = getPropVal(characterStyle, "font.index,asian.font.index,ansi.font.index,symbol.font.index", parentParagraph); TextProp tp = getTextParagraph().getPropVal(characterStyle, masterStyle, "font.index,asian.font.index,ansi.font.index,symbol.font.index");
if (tp == null) { return null; } if (tp == null) { return null; }
return slideShow.getFontCollection().getFontWithId(tp.getValue()); return slideShow.getFontCollection().getFontWithId(tp.getValue());
} }
@ -330,8 +335,10 @@ public final class HSLFTextRun implements TextRun {
*/ */
@Override @Override
public SolidPaint getFontColor() { public SolidPaint getFontColor() {
TextProp tp = getPropVal(characterStyle, "font.color", parentParagraph); TextProp tp = getTextParagraph().getPropVal(characterStyle, masterStyle, "font.color");
if (tp == null) return null; if (tp == null) {
return null;
}
Color color = HSLFTextParagraph.getColorFromColorIndexStruct(tp.getValue(), parentParagraph.getSheet()); Color color = HSLFTextParagraph.getColorFromColorIndexStruct(tp.getValue(), parentParagraph.getSheet());
SolidPaint ps = DrawPaint.createSolidPaint(color); SolidPaint ps = DrawPaint.createSolidPaint(color);
return ps; return ps;
@ -374,6 +381,7 @@ public final class HSLFTextRun implements TextRun {
return parentParagraph; return parentParagraph;
} }
@Override
public TextCap getTextCap() { public TextCap getTextCap() {
return TextCap.NONE; return TextCap.NONE;
} }
@ -388,6 +396,7 @@ public final class HSLFTextRun implements TextRun {
return getSuperscript() > 0; return getSuperscript() > 0;
} }
@Override
public byte getPitchAndFamily() { public byte getPitchAndFamily() {
return 0; return 0;
} }
@ -414,4 +423,20 @@ public final class HSLFTextRun implements TextRun {
} }
return link; return link;
} }
@Override
public FieldType getFieldType() {
Placeholder ph = getTextParagraph().getParentShape().getPlaceholder();
if (ph != null) {
switch (ph) {
case SLIDE_NUMBER:
return FieldType.SLIDE_NUMBER;
case DATETIME:
return FieldType.DATE_TIME;
default:
break;
}
}
return null;
}
} }

View File

@ -20,7 +20,6 @@ package org.apache.poi.hslf.usermodel;
import static org.apache.poi.hslf.record.RecordTypes.OEPlaceholderAtom; import static org.apache.poi.hslf.record.RecordTypes.OEPlaceholderAtom;
import static org.apache.poi.hslf.record.RecordTypes.RoundTripHFPlaceholder12; import static org.apache.poi.hslf.record.RecordTypes.RoundTripHFPlaceholder12;
import java.awt.font.FontRenderContext;
import java.awt.geom.Rectangle2D; import java.awt.geom.Rectangle2D;
import java.io.IOException; import java.io.IOException;
import java.util.ArrayList; import java.util.ArrayList;
@ -34,10 +33,14 @@ import org.apache.poi.ddf.EscherSimpleProperty;
import org.apache.poi.ddf.EscherTextboxRecord; import org.apache.poi.ddf.EscherTextboxRecord;
import org.apache.poi.hslf.exceptions.HSLFException; import org.apache.poi.hslf.exceptions.HSLFException;
import org.apache.poi.hslf.model.HSLFMetroShape; import org.apache.poi.hslf.model.HSLFMetroShape;
import org.apache.poi.hslf.model.textproperties.TextPropCollection;
import org.apache.poi.hslf.record.EscherTextboxWrapper; import org.apache.poi.hslf.record.EscherTextboxWrapper;
import org.apache.poi.hslf.record.OEPlaceholderAtom; import org.apache.poi.hslf.record.OEPlaceholderAtom;
import org.apache.poi.hslf.record.PPDrawing; import org.apache.poi.hslf.record.PPDrawing;
import org.apache.poi.hslf.record.RoundTripHFPlaceholder12; import org.apache.poi.hslf.record.RoundTripHFPlaceholder12;
import org.apache.poi.hslf.record.StyleTextPropAtom;
import org.apache.poi.hslf.record.TextBytesAtom;
import org.apache.poi.hslf.record.TextCharsAtom;
import org.apache.poi.hslf.record.TextHeaderAtom; import org.apache.poi.hslf.record.TextHeaderAtom;
import org.apache.poi.sl.draw.DrawFactory; import org.apache.poi.sl.draw.DrawFactory;
import org.apache.poi.sl.draw.DrawTextShape; import org.apache.poi.sl.draw.DrawTextShape;
@ -71,12 +74,12 @@ implements TextShape<HSLFShape,HSLFTextParagraph> {
BOTTOM_BASELINE (7, VerticalAlignment.BOTTOM, false, true), BOTTOM_BASELINE (7, VerticalAlignment.BOTTOM, false, true),
TOP_CENTER_BASELINE (8, VerticalAlignment.TOP, true, true), TOP_CENTER_BASELINE (8, VerticalAlignment.TOP, true, true),
BOTTOM_CENTER_BASELINE(9, VerticalAlignment.BOTTOM, true, true); BOTTOM_CENTER_BASELINE(9, VerticalAlignment.BOTTOM, true, true);
public final int nativeId; public final int nativeId;
public final VerticalAlignment vAlign; public final VerticalAlignment vAlign;
public final boolean centered; public final boolean centered;
public final Boolean baseline; public final Boolean baseline;
HSLFTextAnchor(int nativeId, VerticalAlignment vAlign, boolean centered, Boolean baseline) { HSLFTextAnchor(int nativeId, VerticalAlignment vAlign, boolean centered, Boolean baseline) {
this.nativeId = nativeId; this.nativeId = nativeId;
this.vAlign = vAlign; this.vAlign = vAlign;
@ -86,7 +89,9 @@ implements TextShape<HSLFShape,HSLFTextParagraph> {
static HSLFTextAnchor fromNativeId(int nativeId) { static HSLFTextAnchor fromNativeId(int nativeId) {
for (HSLFTextAnchor ta : values()) { for (HSLFTextAnchor ta : values()) {
if (ta.nativeId == nativeId) return ta; if (ta.nativeId == nativeId) {
return ta;
}
} }
return null; return null;
} }
@ -125,13 +130,13 @@ implements TextShape<HSLFShape,HSLFTextParagraph> {
/** /**
* TextRun object which holds actual text and format data * TextRun object which holds actual text and format data
*/ */
protected List<HSLFTextParagraph> _paragraphs = new ArrayList<HSLFTextParagraph>(); private List<HSLFTextParagraph> _paragraphs = new ArrayList<HSLFTextParagraph>();
/** /**
* Escher container which holds text attributes such as * Escher container which holds text attributes such as
* TextHeaderAtom, TextBytesAtom ot TextCharsAtom, StyleTextPropAtom etc. * TextHeaderAtom, TextBytesAtom or TextCharsAtom, StyleTextPropAtom etc.
*/ */
protected EscherTextboxWrapper _txtbox; private EscherTextboxWrapper _txtbox;
/** /**
* This setting is used for supporting a deprecated alignment * This setting is used for supporting a deprecated alignment
@ -140,11 +145,6 @@ implements TextShape<HSLFShape,HSLFTextParagraph> {
*/ */
// boolean alignToBaseline = false; // boolean alignToBaseline = false;
/**
* Used to calculate text bounds
*/
protected static final FontRenderContext _frc = new FontRenderContext(null, true, true);
/** /**
* Create a TextBox object and initialize it from the supplied Record container. * Create a TextBox object and initialize it from the supplied Record container.
* *
@ -222,10 +222,14 @@ implements TextShape<HSLFShape,HSLFTextParagraph> {
} }
protected EscherTextboxWrapper getEscherTextboxWrapper(){ protected EscherTextboxWrapper getEscherTextboxWrapper(){
if(_txtbox != null) return _txtbox; if(_txtbox != null) {
return _txtbox;
}
EscherTextboxRecord textRecord = getEscherChild(EscherTextboxRecord.RECORD_ID); EscherTextboxRecord textRecord = getEscherChild(EscherTextboxRecord.RECORD_ID);
if (textRecord == null) return null; if (textRecord == null) {
return null;
}
HSLFSheet sheet = getSheet(); HSLFSheet sheet = getSheet();
if (sheet != null) { if (sheet != null) {
@ -248,6 +252,66 @@ implements TextShape<HSLFShape,HSLFTextParagraph> {
return _txtbox; return _txtbox;
} }
private void createEmptyParagraph() {
TextHeaderAtom tha = (TextHeaderAtom)_txtbox.findFirstOfType(TextHeaderAtom._type);
if (tha == null) {
tha = new TextHeaderAtom();
tha.setParentRecord(_txtbox);
_txtbox.appendChildRecord(tha);
}
TextBytesAtom tba = (TextBytesAtom)_txtbox.findFirstOfType(TextBytesAtom._type);
TextCharsAtom tca = (TextCharsAtom)_txtbox.findFirstOfType(TextCharsAtom._type);
if (tba == null && tca == null) {
tba = new TextBytesAtom();
tba.setText(new byte[0]);
_txtbox.appendChildRecord(tba);
}
final String text = ((tba != null) ? tba.getText() : tca.getText());
StyleTextPropAtom sta = (StyleTextPropAtom)_txtbox.findFirstOfType(StyleTextPropAtom._type);
TextPropCollection paraStyle = null, charStyle = null;
if (sta == null) {
int parSiz = text.length();
sta = new StyleTextPropAtom(parSiz+1);
if (_paragraphs.isEmpty()) {
paraStyle = sta.addParagraphTextPropCollection(parSiz+1);
charStyle = sta.addCharacterTextPropCollection(parSiz+1);
} else {
for (HSLFTextParagraph htp : _paragraphs) {
int runsLen = 0;
for (HSLFTextRun htr : htp.getTextRuns()) {
runsLen += htr.getLength();
charStyle = sta.addCharacterTextPropCollection(htr.getLength());
htr.setCharacterStyle(charStyle);
}
paraStyle = sta.addParagraphTextPropCollection(runsLen);
htp.setParagraphStyle(paraStyle);
}
assert (paraStyle != null && charStyle != null);
}
_txtbox.appendChildRecord(sta);
} else {
paraStyle = sta.getParagraphStyles().get(0);
charStyle = sta.getCharacterStyles().get(0);
}
if (_paragraphs.isEmpty()) {
HSLFTextParagraph htp = new HSLFTextParagraph(tha, tba, tca, _paragraphs);
htp.setParagraphStyle(paraStyle);
htp.setParentShape(this);
_paragraphs.add(htp);
HSLFTextRun htr = new HSLFTextRun(htp);
htr.setCharacterStyle(charStyle);
htr.setText(text);
htp.addTextRun(htr);
}
}
/** /**
* Adjust the size of the shape so it encompasses the text inside it. * Adjust the size of the shape so it encompasses the text inside it.
* *
@ -276,7 +340,9 @@ implements TextShape<HSLFShape,HSLFTextParagraph> {
*/ */
public int getRunType() { public int getRunType() {
getEscherTextboxWrapper(); getEscherTextboxWrapper();
if (_txtbox == null) return -1; if (_txtbox == null) {
return -1;
}
List<HSLFTextParagraph> paras = HSLFTextParagraph.findTextParagraphs(_txtbox, getSheet()); List<HSLFTextParagraph> paras = HSLFTextParagraph.findTextParagraphs(_txtbox, getSheet());
return (paras.isEmpty()) ? -1 : paras.get(0).getRunType(); return (paras.isEmpty()) ? -1 : paras.get(0).getRunType();
} }
@ -289,7 +355,9 @@ implements TextShape<HSLFShape,HSLFTextParagraph> {
*/ */
public void setRunType(int type) { public void setRunType(int type) {
getEscherTextboxWrapper(); getEscherTextboxWrapper();
if (_txtbox == null) return; if (_txtbox == null) {
return;
}
List<HSLFTextParagraph> paras = HSLFTextParagraph.findTextParagraphs(_txtbox, getSheet()); List<HSLFTextParagraph> paras = HSLFTextParagraph.findTextParagraphs(_txtbox, getSheet());
if (!paras.isEmpty()) { if (!paras.isEmpty()) {
paras.get(0).setRunType(type); paras.get(0).setRunType(type);
@ -562,19 +630,23 @@ implements TextShape<HSLFShape,HSLFTextParagraph> {
@Override @Override
public List<HSLFTextParagraph> getTextParagraphs(){ public List<HSLFTextParagraph> getTextParagraphs(){
if (!_paragraphs.isEmpty()) return _paragraphs; if (!_paragraphs.isEmpty()) {
return _paragraphs;
}
_txtbox = getEscherTextboxWrapper(); _txtbox = getEscherTextboxWrapper();
if (_txtbox == null) { if (_txtbox == null) {
_paragraphs.addAll(HSLFTextParagraph.createEmptyParagraph()); _txtbox = new EscherTextboxWrapper();
_txtbox = _paragraphs.get(0).getTextboxWrapper(); createEmptyParagraph();
} else { } else {
_paragraphs = HSLFTextParagraph.findTextParagraphs(_txtbox, getSheet()); List<HSLFTextParagraph> pList = HSLFTextParagraph.findTextParagraphs(_txtbox, getSheet());
if (_paragraphs == null) { if (pList == null) {
// there are actually TextBoxRecords without extra data - see #54722 // there are actually TextBoxRecords without extra data - see #54722
_paragraphs = HSLFTextParagraph.createEmptyParagraph(_txtbox); createEmptyParagraph();
} else {
_paragraphs = pList;
} }
if (_paragraphs.isEmpty()) { if (_paragraphs.isEmpty()) {
LOG.log(POILogger.WARN, "TextRecord didn't contained any text lines"); LOG.log(POILogger.WARN, "TextRecord didn't contained any text lines");
} }
@ -587,6 +659,7 @@ implements TextShape<HSLFShape,HSLFTextParagraph> {
return _paragraphs; return _paragraphs;
} }
@Override @Override
public void setSheet(HSLFSheet sheet) { public void setSheet(HSLFSheet sheet) {
super.setSheet(sheet); super.setSheet(sheet);
@ -611,26 +684,30 @@ implements TextShape<HSLFShape,HSLFTextParagraph> {
/** /**
* Return {@link RoundTripHFPlaceholder12}, the atom that describes a header/footer placeholder. * Return {@link RoundTripHFPlaceholder12}, the atom that describes a header/footer placeholder.
* Compare the {@link RoundTripHFPlaceholder12#getPlaceholderId()} with * Compare the {@link RoundTripHFPlaceholder12#getPlaceholderId()} with
* {@link OEPlaceholderAtom#MasterHeader} or {@link OEPlaceholderAtom#MasterFooter}, to find out * {@link Placeholder#HEADER} or {@link Placeholder#FOOTER}, to find out
* what kind of placeholder this is. * what kind of placeholder this is.
* *
* @return {@link RoundTripHFPlaceholder12} or {@code null} if not found * @return {@link RoundTripHFPlaceholder12} or {@code null} if not found
* *
* @since POI 3.14-Beta2 * @since POI 3.14-Beta2
*/ */
public RoundTripHFPlaceholder12 getHFPlaceholderAtom() { public RoundTripHFPlaceholder12 getHFPlaceholderAtom() {
// special case for files saved in Office 2007 // special case for files saved in Office 2007
return getClientDataRecord(RoundTripHFPlaceholder12.typeID); return getClientDataRecord(RoundTripHFPlaceholder12.typeID);
} }
@Override @Override
public boolean isPlaceholder() { public boolean isPlaceholder() {
OEPlaceholderAtom oep = getPlaceholderAtom(); OEPlaceholderAtom oep = getPlaceholderAtom();
if (oep != null) return true; if (oep != null) {
return true;
}
//special case for files saved in Office 2007 //special case for files saved in Office 2007
RoundTripHFPlaceholder12 hldr = getHFPlaceholderAtom(); RoundTripHFPlaceholder12 hldr = getHFPlaceholderAtom();
if (hldr != null) return true; if (hldr != null) {
return true;
}
return false; return false;
} }
@ -710,7 +787,7 @@ implements TextShape<HSLFShape,HSLFTextParagraph> {
} }
setEscherProperty(opt, EscherProperties.TEXT__TEXTFLOW, msotxfl); setEscherProperty(opt, EscherProperties.TEXT__TEXTFLOW, msotxfl);
} }
@Override @Override
public Double getTextRotation() { public Double getTextRotation() {
// see 2.4.6 MSOCDIR // see 2.4.6 MSOCDIR
@ -718,7 +795,7 @@ implements TextShape<HSLFShape,HSLFTextParagraph> {
EscherSimpleProperty prop = getEscherProperty(opt, EscherProperties.TEXT__FONTROTATION); EscherSimpleProperty prop = getEscherProperty(opt, EscherProperties.TEXT__FONTROTATION);
return (prop == null) ? null : (90. * prop.getPropertyValue()); return (prop == null) ? null : (90. * prop.getPropertyValue());
} }
@Override @Override
public void setTextRotation(Double rotation) { public void setTextRotation(Double rotation) {
AbstractEscherOptRecord opt = getEscherOptRecord(); AbstractEscherOptRecord opt = getEscherOptRecord();
@ -729,7 +806,7 @@ implements TextShape<HSLFShape,HSLFTextParagraph> {
setEscherProperty(EscherProperties.TEXT__FONTROTATION, rot); setEscherProperty(EscherProperties.TEXT__FONTROTATION, rot);
} }
} }
/** /**
* Returns the raw text content of the shape. This hasn't had any * Returns the raw text content of the shape. This hasn't had any
* changes applied to it, and so is probably unlikely to print * changes applied to it, and so is probably unlikely to print
@ -751,7 +828,7 @@ implements TextShape<HSLFShape,HSLFTextParagraph> {
List<HSLFTextParagraph> paras = getTextParagraphs(); List<HSLFTextParagraph> paras = getTextParagraphs();
HSLFTextRun htr = HSLFTextParagraph.appendText(paras, text, newParagraph); HSLFTextRun htr = HSLFTextParagraph.appendText(paras, text, newParagraph);
setTextId(getRawText().hashCode()); setTextId(getRawText().hashCode());
return htr; return htr;
} }
@Override @Override

View File

@ -25,8 +25,6 @@ import org.apache.poi.hslf.record.SlideAtom;
/** /**
* Title masters define the design template for slides with a Title Slide layout. * Title masters define the design template for slides with a Title Slide layout.
*
* @author Yegor Kozlov
*/ */
public final class HSLFTitleMaster extends HSLFMasterSheet { public final class HSLFTitleMaster extends HSLFMasterSheet {
private final List<List<HSLFTextParagraph>> _paragraphs = new ArrayList<List<HSLFTextParagraph>>(); private final List<List<HSLFTextParagraph>> _paragraphs = new ArrayList<List<HSLFTextParagraph>>();
@ -39,13 +37,16 @@ public final class HSLFTitleMaster extends HSLFMasterSheet {
super(record, sheetNo); super(record, sheetNo);
for (List<HSLFTextParagraph> l : HSLFTextParagraph.findTextParagraphs(getPPDrawing(), this)) { for (List<HSLFTextParagraph> l : HSLFTextParagraph.findTextParagraphs(getPPDrawing(), this)) {
if (!_paragraphs.contains(l)) _paragraphs.add(l); if (!_paragraphs.contains(l)) {
_paragraphs.add(l);
}
} }
} }
/** /**
* Returns an array of all the TextRuns found * Returns an array of all the TextRuns found
*/ */
@Override
public List<List<HSLFTextParagraph>> getTextParagraphs() { public List<List<HSLFTextParagraph>> getTextParagraphs() {
return _paragraphs; return _paragraphs;
} }
@ -53,20 +54,23 @@ public final class HSLFTitleMaster extends HSLFMasterSheet {
/** /**
* Delegate the call to the underlying slide master. * Delegate the call to the underlying slide master.
*/ */
@Override
public TextProp getStyleAttribute(int txtype, int level, String name, boolean isCharacter) { public TextProp getStyleAttribute(int txtype, int level, String name, boolean isCharacter) {
HSLFMasterSheet master = getMasterSheet(); HSLFMasterSheet master = getMasterSheet();
return master == null ? null : master.getStyleAttribute(txtype, level, name, isCharacter); return (master == null) ? null : master.getStyleAttribute(txtype, level, name, isCharacter);
} }
/** /**
* Returns the slide master for this title master. * Returns the slide master for this title master.
*/ */
@Override
public HSLFMasterSheet getMasterSheet(){ public HSLFMasterSheet getMasterSheet(){
List<HSLFSlideMaster> master = getSlideShow().getSlideMasters();
SlideAtom sa = ((org.apache.poi.hslf.record.Slide)getSheetContainer()).getSlideAtom(); SlideAtom sa = ((org.apache.poi.hslf.record.Slide)getSheetContainer()).getSlideAtom();
int masterId = sa.getMasterID(); int masterId = sa.getMasterID();
for (HSLFSlideMaster sm : master) { for (HSLFSlideMaster sm : getSlideShow().getSlideMasters()) {
if (masterId == sm._getSheetNumber()) return sm; if (masterId == sm._getSheetNumber()) {
return sm;
}
} }
return null; return null;
} }

View File

@ -17,36 +17,43 @@
package org.apache.poi.hslf.record; package org.apache.poi.hslf.record;
import java.io.ByteArrayInputStream; import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import java.io.ByteArrayOutputStream; import java.io.ByteArrayOutputStream;
import java.io.IOException;
import org.apache.poi.hslf.record.SlideAtom.SSlideLayoutAtom; import org.apache.poi.hslf.HSLFTestDataSamples;
import org.apache.poi.hslf.record.SlideAtomLayout.SlideLayoutType;
import org.apache.poi.hslf.usermodel.HSLFSlide;
import org.apache.poi.hslf.usermodel.HSLFSlideShow; import org.apache.poi.hslf.usermodel.HSLFSlideShow;
import org.junit.Test;
import junit.framework.TestCase;
/** /**
* Tests that SlideAtom works properly * Tests that SlideAtom works properly
*
* @author Nick Burch (nick at torchbox dot com)
*/ */
public final class TestSlideAtom extends TestCase { public final class TestSlideAtom {
// From a real file // From a real file
private final byte[] data_a = new byte[] { 1, 0, 0xEF-256, 3, 0x18, 0, 0, 0, private static final byte[] data_a = new byte[] { 1, 0, 0xEF-256, 3, 0x18, 0, 0, 0,
0, 0, 0, 0, 0x0F, 0x10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x80-256, 0, 0, 0, 0, 0x0F, 0x10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x80-256,
0, 1, 0, 0, 7, 0, 0x0C, 0x30 }; 0, 1, 0, 0, 7, 0, 0x0C, 0x30 };
public void testRecordType() { @Test
public void testRecordType() {
SlideAtom sa = new SlideAtom(data_a, 0, data_a.length); SlideAtom sa = new SlideAtom(data_a, 0, data_a.length);
assertEquals(1007l, sa.getRecordType()); assertEquals(1007l, sa.getRecordType());
} }
@Test
public void testFlags() { public void testFlags() {
SlideAtom sa = new SlideAtom(data_a, 0, data_a.length); SlideAtom sa = new SlideAtom(data_a, 0, data_a.length);
// First 12 bytes are a SSlideLayoutAtom, checked elsewhere // First 12 bytes are a SSlideLayoutAtom, checked elsewhere
// Check the IDs // Check the IDs
assertEquals(0x80000000, sa.getMasterID()); assertEquals(SlideAtom.USES_MASTER_SLIDE_ID, sa.getMasterID());
assertEquals(256, sa.getNotesID()); assertEquals(256, sa.getNotesID());
// Check the flags // Check the flags
@ -54,39 +61,37 @@ public final class TestSlideAtom extends TestCase {
assertEquals(true, sa.getFollowMasterScheme()); assertEquals(true, sa.getFollowMasterScheme());
assertEquals(true, sa.getFollowMasterBackground()); assertEquals(true, sa.getFollowMasterBackground());
} }
public void testSSlideLayoutAtom() {
@Test
public void testSSlideLayoutAtom() {
SlideAtom sa = new SlideAtom(data_a, 0, data_a.length); SlideAtom sa = new SlideAtom(data_a, 0, data_a.length);
SSlideLayoutAtom ssla = sa.getSSlideLayoutAtom(); SlideAtomLayout ssla = sa.getSSlideLayoutAtom();
assertEquals(0, ssla.getGeometryType()); assertEquals(SlideLayoutType.TITLE_SLIDE, ssla.getGeometryType());
// Should also check the placehold IDs at some point // Should also check the placeholder IDs at some point
} }
public void testWrite() throws Exception { @Test
public void testWrite() throws IOException {
SlideAtom sa = new SlideAtom(data_a, 0, data_a.length); SlideAtom sa = new SlideAtom(data_a, 0, data_a.length);
ByteArrayOutputStream baos = new ByteArrayOutputStream(); ByteArrayOutputStream baos = new ByteArrayOutputStream();
sa.writeOut(baos); sa.writeOut(baos);
byte[] b = baos.toByteArray(); assertArrayEquals(data_a, baos.toByteArray());
assertEquals(data_a.length, b.length);
for(int i=0; i<data_a.length; i++) {
assertEquals(data_a[i],b[i]);
}
} }
public void testSSSlideInfoAtom() throws Exception { @Test
HSLFSlideShow ss = new HSLFSlideShow(); public void testSSSlideInfoAtom() throws IOException {
org.apache.poi.hslf.usermodel.HSLFSlide slide1 = ss.createSlide(), slide2 = ss.createSlide(); HSLFSlideShow ss1 = new HSLFSlideShow();
HSLFSlide slide1 = ss1.createSlide(), slide2 = ss1.createSlide();
slide2.setHidden(true); slide2.setHidden(true);
ByteArrayOutputStream bos = new ByteArrayOutputStream(4096); HSLFSlideShow ss2 = HSLFTestDataSamples.writeOutAndReadBack(ss1);
ss.write(bos); slide1 = ss2.getSlides().get(0);
ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray()); slide2 = ss2.getSlides().get(1);
ss = new HSLFSlideShow(bis);
slide1 = ss.getSlides().get(0);
slide2 = ss.getSlides().get(1);
assertFalse(slide1.getHidden()); assertFalse(slide1.getHidden());
assertTrue(slide2.getHidden()); assertTrue(slide2.getHidden());
ss2.close();
ss1.close();
} }
} }

View File

@ -38,6 +38,7 @@ import java.io.OutputStream;
import java.io.PrintStream; import java.io.PrintStream;
import java.text.AttributedCharacterIterator; import java.text.AttributedCharacterIterator;
import java.text.AttributedCharacterIterator.Attribute; import java.text.AttributedCharacterIterator.Attribute;
import java.text.CharacterIterator;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Date; import java.util.Date;
import java.util.HashMap; import java.util.HashMap;
@ -466,12 +467,16 @@ public final class TestBugs {
// get slides // get slides
for (HSLFSlide slide : ppt.getSlides()) { for (HSLFSlide slide : ppt.getSlides()) {
for (HSLFShape shape : slide.getShapes()) { for (HSLFShape shape : slide.getShapes()) {
if (!(shape instanceof HSLFTextBox)) continue; if (!(shape instanceof HSLFTextBox)) {
continue;
}
HSLFTextBox tb = (HSLFTextBox) shape; HSLFTextBox tb = (HSLFTextBox) shape;
// work with TextBox // work with TextBox
String str = tb.getText(); String str = tb.getText();
if (!str.contains("$$DATE$$")) continue; if (!str.contains("$$DATE$$")) {
continue;
}
str = str.replace("$$DATE$$", new Date().toString()); str = str.replace("$$DATE$$", new Date().toString());
tb.setText(str); tb.setText(str);
@ -512,7 +517,9 @@ public final class TestBugs {
int tha = 0; int tha = 0;
for (Record r : s1.getSlideRecords()) { for (Record r : s1.getSlideRecords()) {
if (r instanceof TextHeaderAtom) tha++; if (r instanceof TextHeaderAtom) {
tha++;
}
} }
assertEquals(2, tha); assertEquals(2, tha);
@ -525,7 +532,9 @@ public final class TestBugs {
// Will have skipped the empty one // Will have skipped the empty one
int str = 0; int str = 0;
for (List<HSLFTextParagraph> tr : _slides.get(0).getTextParagraphs()) { for (List<HSLFTextParagraph> tr : _slides.get(0).getTextParagraphs()) {
if (! tr.get(0).isDrawingBased()) str++; if (! tr.get(0).isDrawingBased()) {
str++;
}
} }
assertEquals(2, str); assertEquals(2, str);
@ -758,7 +767,7 @@ public final class TestBugs {
public void bug47904() throws IOException { public void bug47904() throws IOException {
HSLFSlideShow ppt1 = new HSLFSlideShow(); HSLFSlideShow ppt1 = new HSLFSlideShow();
HSLFSlideMaster sm = ppt1.getSlideMasters().get(0); HSLFSlideMaster sm = ppt1.getSlideMasters().get(0);
HSLFAutoShape as = (HSLFAutoShape)sm.getShapes().get(0); HSLFAutoShape as = (HSLFAutoShape)sm.getPlaceholder(Placeholder.TITLE);
HSLFTextParagraph tp = as.getTextParagraphs().get(0); HSLFTextParagraph tp = as.getTextParagraphs().get(0);
HSLFTextRun tr = tp.getTextRuns().get(0); HSLFTextRun tr = tp.getTextRuns().get(0);
tr.setFontFamily("Tahoma"); tr.setFontFamily("Tahoma");
@ -766,8 +775,9 @@ public final class TestBugs {
tr.setFontSize(44.); tr.setFontSize(44.);
tr.setFontColor(Color.red); tr.setFontColor(Color.red);
tp.setTextAlign(TextAlign.RIGHT); tp.setTextAlign(TextAlign.RIGHT);
ppt1.createSlide().addTitle().setText("foobaa"); HSLFTextBox tb = ppt1.createSlide().addTitle();
tb.setText("foobaa");
HSLFSlideShow ppt2 = HSLFTestDataSamples.writeOutAndReadBack(ppt1); HSLFSlideShow ppt2 = HSLFTestDataSamples.writeOutAndReadBack(ppt1);
ppt1.close(); ppt1.close();
@ -877,7 +887,7 @@ public final class TestBugs {
StringBuffer sb = new StringBuffer(); StringBuffer sb = new StringBuffer();
for (char c = iterator.first(); for (char c = iterator.first();
c != AttributedCharacterIterator.DONE; c != CharacterIterator.DONE;
c = iterator.next()) { c = iterator.next()) {
sb.append(c); sb.append(c);
attributes = iterator.getAttributes(); attributes = iterator.getAttributes();

View File

@ -18,29 +18,23 @@
package org.apache.poi.hslf.usermodel; package org.apache.poi.hslf.usermodel;
import static org.junit.Assert.assertEquals;
import java.io.IOException;
import java.util.List; import java.util.List;
import junit.framework.TestCase; import org.apache.poi.hslf.HSLFTestDataSamples;
import org.junit.Test;
import org.apache.poi.POIDataSamples;
/** /**
* Tests that SlideShow returns the right number of Sheets and MetaSheets * Tests that SlideShow returns the right number of Sheets and MetaSheets
*
* @author Nick Burch (nick at torchbox dot com)
*/ */
public final class TestCounts extends TestCase { public final class TestCounts {
// SlideShow primed on the test data @Test
private final HSLFSlideShow ss; public void testSheetsCount() throws IOException {
HSLFSlideShow ppt = HSLFTestDataSamples.getSlideShow("basic_test_ppt_file.ppt");
public TestCounts() throws Exception {
POIDataSamples slTests = POIDataSamples.getSlideShowInstance(); List<HSLFSlide> slides = ppt.getSlides();
HSLFSlideShowImpl hss = new HSLFSlideShowImpl(slTests.openResourceAsStream("basic_test_ppt_file.ppt"));
ss = new HSLFSlideShow(hss);
}
public void testSheetsCount() {
List<HSLFSlide> slides = ss.getSlides();
// Two sheets - master sheet is separate // Two sheets - master sheet is separate
assertEquals(2, slides.size()); assertEquals(2, slides.size());
@ -55,10 +49,15 @@ public final class TestCounts extends TestCase {
// These are slides 1+2 -> 256+257 // These are slides 1+2 -> 256+257
assertEquals(256, slides.get(0)._getSheetNumber()); assertEquals(256, slides.get(0)._getSheetNumber());
assertEquals(257, slides.get(1)._getSheetNumber()); assertEquals(257, slides.get(1)._getSheetNumber());
ppt.close();
} }
public void testNotesCount() { @Test
List<HSLFNotes> notes = ss.getNotes(); public void testNotesCount() throws IOException {
HSLFSlideShow ppt = HSLFTestDataSamples.getSlideShow("basic_test_ppt_file.ppt");
List<HSLFNotes> notes = ppt.getNotes();
// Two sheets -> two notes // Two sheets -> two notes
// Note: there are also notes on the slide master // Note: there are also notes on the slide master
//assertEquals(3, notes.length); // When we do slide masters //assertEquals(3, notes.length); // When we do slide masters
@ -74,5 +73,7 @@ public final class TestCounts extends TestCase {
// They happen to go between the two slides in Ref terms // They happen to go between the two slides in Ref terms
assertEquals(5, notes.get(0)._getSheetRefId()); assertEquals(5, notes.get(0)._getSheetRefId());
assertEquals(7, notes.get(1)._getSheetRefId()); assertEquals(7, notes.get(1)._getSheetRefId());
ppt.close();
} }
} }